aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/atm/he.c4
-rw-r--r--drivers/atm/idt77105.c6
-rw-r--r--drivers/atm/iphase.c2
-rw-r--r--drivers/bcma/Kconfig12
-rw-r--r--drivers/bcma/driver_gpio.c20
-rw-r--r--drivers/block/drbd/drbd_receiver.c4
-rw-r--r--drivers/bluetooth/Kconfig15
-rw-r--r--drivers/bluetooth/Makefile1
-rw-r--r--drivers/bluetooth/ath3k.c6
-rw-r--r--drivers/bluetooth/bt3c_cs.c3
-rw-r--r--drivers/bluetooth/btbcm.c138
-rw-r--r--drivers/bluetooth/btbcm.h61
-rw-r--r--drivers/bluetooth/btintel.c6
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c2
-rw-r--r--drivers/bluetooth/btrtl.c390
-rw-r--r--drivers/bluetooth/btrtl.h52
-rw-r--r--drivers/bluetooth/btusb.c572
-rw-r--r--drivers/bluetooth/btwilink.c2
-rw-r--r--drivers/bluetooth/hci_ath.c1
-rw-r--r--drivers/bluetooth/hci_bcm.c107
-rw-r--r--drivers/bluetooth/hci_bcsp.c20
-rw-r--r--drivers/bluetooth/hci_h4.c1
-rw-r--r--drivers/bluetooth/hci_ldisc.c123
-rw-r--r--drivers/bluetooth/hci_uart.h11
-rw-r--r--drivers/bluetooth/hci_vhci.c2
-rw-r--r--drivers/clk/qcom/gcc-ipq806x.c594
-rw-r--r--drivers/edac/Kconfig22
-rw-r--r--drivers/edac/Makefile1
-rw-r--r--drivers/edac/altera_edac.c381
-rw-r--r--drivers/edac/altera_edac.h201
-rw-r--r--drivers/edac/edac_mc.c9
-rw-r--r--drivers/edac/edac_stub.c1
-rw-r--r--drivers/edac/mce_amd_inj.c177
-rw-r--r--drivers/edac/mpc85xx_edac.c10
-rw-r--r--drivers/edac/mpc85xx_edac.h1
-rw-r--r--drivers/edac/xgene_edac.c1215
-rw-r--r--drivers/gpio/gpio-bcm-kona.c2
-rw-r--r--drivers/gpio/gpio-em.c2
-rw-r--r--drivers/gpio/gpio-grgpio.c2
-rw-r--r--drivers/gpio/gpio-mpc8xxx.c2
-rw-r--r--drivers/gpio/gpio-sa1100.c2
-rw-r--r--drivers/gpio/gpio-sodaville.c2
-rw-r--r--drivers/infiniband/hw/cxgb4/provider.c8
-rw-r--r--drivers/infiniband/hw/mlx4/alias_GUID.c7
-rw-r--r--drivers/infiniband/hw/mlx4/mad.c49
-rw-r--r--drivers/infiniband/hw/mlx4/main.c118
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h8
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c7
-rw-r--r--drivers/infiniband/hw/mlx5/Kconfig4
-rw-r--r--drivers/infiniband/hw/mlx5/cq.c11
-rw-r--r--drivers/infiniband/hw/mlx5/mad.c299
-rw-r--r--drivers/infiniband/hw/mlx5/main.c646
-rw-r--r--drivers/infiniband/hw/mlx5/mlx5_ib.h23
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c3
-rw-r--r--drivers/infiniband/hw/mlx5/odp.c47
-rw-r--r--drivers/infiniband/hw/mlx5/qp.c89
-rw-r--r--drivers/infiniband/hw/mlx5/srq.c11
-rw-r--r--drivers/input/Kconfig13
-rw-r--r--drivers/input/Makefile1
-rw-r--r--drivers/input/evdev.c5
-rw-r--r--drivers/input/ff-core.c4
-rw-r--r--drivers/input/input-leds.c212
-rw-r--r--drivers/input/input.c2
-rw-r--r--drivers/input/keyboard/Kconfig1
-rw-r--r--drivers/input/keyboard/adp5589-keys.c6
-rw-r--r--drivers/input/keyboard/clps711x-keypad.c7
-rw-r--r--drivers/input/keyboard/max7359_keypad.c31
-rw-r--r--drivers/input/keyboard/samsung-keypad.c2
-rw-r--r--drivers/input/keyboard/spear-keyboard.c2
-rw-r--r--drivers/input/misc/Kconfig23
-rw-r--r--drivers/input/misc/Makefile2
-rw-r--r--drivers/input/misc/adxl34x-i2c.c21
-rw-r--r--drivers/input/misc/da9063_onkey.c226
-rw-r--r--drivers/input/misc/drv260x.c13
-rw-r--r--drivers/input/misc/drv2665.c322
-rw-r--r--drivers/input/misc/gpio-beeper.c7
-rw-r--r--drivers/input/misc/retu-pwrbutton.c3
-rw-r--r--drivers/input/misc/soc_button_array.c1
-rw-r--r--drivers/input/misc/twl4030-pwrbutton.c3
-rw-r--r--drivers/input/misc/twl6040-vibra.c3
-rw-r--r--drivers/input/misc/wm831x-on.c3
-rw-r--r--drivers/input/mouse/alps.c244
-rw-r--r--drivers/input/mouse/alps.h1
-rw-r--r--drivers/input/mouse/cyapa_gen3.c3
-rw-r--r--drivers/input/mouse/cyapa_gen5.c23
-rw-r--r--drivers/input/mouse/elan_i2c.h8
-rw-r--r--drivers/input/mouse/elan_i2c_core.c63
-rw-r--r--drivers/input/mouse/elan_i2c_i2c.c4
-rw-r--r--drivers/input/mouse/elan_i2c_smbus.c6
-rw-r--r--drivers/input/mouse/focaltech.c13
-rw-r--r--drivers/input/mouse/psmouse-base.c2
-rw-r--r--drivers/input/mouse/sentelic.h4
-rw-r--r--drivers/input/mouse/synaptics_i2c.c6
-rw-r--r--drivers/input/touchscreen/Kconfig1
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c8
-rw-r--r--drivers/input/touchscreen/cyttsp4_core.c5
-rw-r--r--drivers/input/touchscreen/goodix.c58
-rw-r--r--drivers/input/touchscreen/pixcir_i2c_ts.c2
-rw-r--r--drivers/input/touchscreen/s3c2410_ts.c2
-rw-r--r--drivers/input/touchscreen/stmpe-ts.c37
-rw-r--r--drivers/input/touchscreen/zforce_ts.c1
-rw-r--r--drivers/isdn/capi/capidrv.c4
-rw-r--r--drivers/isdn/hisax/Kconfig4
-rw-r--r--drivers/isdn/hisax/st5481_usb.c4
-rw-r--r--drivers/isdn/mISDN/socket.c12
-rw-r--r--drivers/leds/Kconfig3
-rw-r--r--drivers/mfd/janz-cmodio.c4
-rw-r--r--drivers/net/Kconfig14
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/arcnet/Kconfig4
-rw-r--r--drivers/net/bonding/bond_3ad.c26
-rw-r--r--drivers/net/bonding/bond_main.c55
-rw-r--r--drivers/net/bonding/bond_netlink.c66
-rw-r--r--drivers/net/bonding/bond_options.c91
-rw-r--r--drivers/net/bonding/bond_procfs.c93
-rw-r--r--drivers/net/bonding/bond_sysfs.c52
-rw-r--r--drivers/net/bonding/bond_sysfs_slave.c32
-rw-r--r--drivers/net/can/dev.c5
-rw-r--r--drivers/net/can/flexcan.c53
-rw-r--r--drivers/net/can/janz-ican3.c125
-rw-r--r--drivers/net/can/slcan.c1
-rw-r--r--drivers/net/can/spi/mcp251x.c9
-rw-r--r--drivers/net/can/vcan.c3
-rw-r--r--drivers/net/dsa/Kconfig12
-rw-r--r--drivers/net/dsa/bcm_sf2.c14
-rw-r--r--drivers/net/dsa/mv88e6123_61_65.c186
-rw-r--r--drivers/net/dsa/mv88e6131.c185
-rw-r--r--drivers/net/dsa/mv88e6171.c234
-rw-r--r--drivers/net/dsa/mv88e6352.c188
-rw-r--r--drivers/net/dsa/mv88e6xxx.c980
-rw-r--r--drivers/net/dsa/mv88e6xxx.h112
-rw-r--r--drivers/net/ethernet/3com/Kconfig18
-rw-r--r--drivers/net/ethernet/8390/Kconfig26
-rw-r--r--drivers/net/ethernet/Kconfig2
-rw-r--r--drivers/net/ethernet/Makefile2
-rw-r--r--drivers/net/ethernet/adaptec/Kconfig4
-rw-r--r--drivers/net/ethernet/adi/Kconfig2
-rw-r--r--drivers/net/ethernet/agere/Kconfig4
-rw-r--r--drivers/net/ethernet/allwinner/Kconfig3
-rw-r--r--drivers/net/ethernet/alteon/Kconfig4
-rw-r--r--drivers/net/ethernet/amd/Kconfig20
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-common.h155
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-dcb.c17
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-desc.c35
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-dev.c99
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-drv.c341
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c79
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-main.c384
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-mdio.c1332
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe.h236
-rw-r--r--drivers/net/ethernet/apm/xgene/Makefile2
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_hw.c43
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_hw.h8
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_main.c257
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_main.h30
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_ring2.c200
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_ring2.h49
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c73
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c12
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h20
-rw-r--r--drivers/net/ethernet/apple/Kconfig7
-rw-r--r--drivers/net/ethernet/arc/Kconfig4
-rw-r--r--drivers/net/ethernet/atheros/Kconfig4
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig3
-rw-r--r--drivers/net/ethernet/broadcom/b44.h8
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.c170
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.h4
-rw-r--r--drivers/net/ethernet/broadcom/bgmac.h3
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x.h16
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c59
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h31
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c67
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmmii.c7
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c2
-rw-r--r--drivers/net/ethernet/brocade/Kconfig4
-rw-r--r--drivers/net/ethernet/brocade/bna/Makefile2
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_cee.c1
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_cs.h14
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs.h11
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs_cna.h16
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs_mfg_comm.h10
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.c71
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.h23
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c101
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_msgq.c10
-rw-r--r--drivers/net/ethernet/brocade/bna/bfi.h84
-rw-r--r--drivers/net/ethernet/brocade/bna/bfi_cna.h30
-rw-r--r--drivers/net/ethernet/brocade/bna/bfi_enet.h176
-rw-r--r--drivers/net/ethernet/brocade/bna/bna.h199
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_enet.c101
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_hw_defs.h70
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_tx_rx.c673
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_types.h19
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c119
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.h4
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad_debugfs.c67
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad_ethtool.c15
-rw-r--r--drivers/net/ethernet/brocade/bna/cna.h62
-rw-r--r--drivers/net/ethernet/brocade/bna/cna_fwimg.c2
-rw-r--r--drivers/net/ethernet/cadence/Kconfig2
-rw-r--r--drivers/net/ethernet/cadence/macb.c61
-rw-r--r--drivers/net/ethernet/cadence/macb.h9
-rw-r--r--drivers/net/ethernet/cavium/Kconfig57
-rw-r--r--drivers/net/ethernet/cavium/Makefile5
-rw-r--r--drivers/net/ethernet/cavium/liquidio/Makefile16
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn66xx_device.c796
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn66xx_device.h107
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn66xx_regs.h535
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn68xx_device.c198
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn68xx_device.h33
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn68xx_regs.h51
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_ethtool.c1216
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_main.c3668
-rw-r--r--drivers/net/ethernet/cavium/liquidio/liquidio_common.h673
-rw-r--r--drivers/net/ethernet/cavium/liquidio/liquidio_image.h57
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_config.h424
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_console.c723
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_device.c1309
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_device.h649
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_droq.c989
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_droq.h426
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_iq.h319
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_main.h237
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.c199
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.h75
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_network.h224
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_nic.c189
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_nic.h227
-rw-r--r--drivers/net/ethernet/cavium/liquidio/request_manager.c766
-rw-r--r--drivers/net/ethernet/cavium/liquidio/response_manager.c178
-rw-r--r--drivers/net/ethernet/cavium/liquidio/response_manager.h140
-rw-r--r--drivers/net/ethernet/cavium/thunder/Makefile11
-rw-r--r--drivers/net/ethernet/cavium/thunder/nic.h423
-rw-r--r--drivers/net/ethernet/cavium/thunder/nic_main.c932
-rw-r--r--drivers/net/ethernet/cavium/thunder/nic_reg.h213
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c600
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_main.c1341
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_queues.c1545
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_queues.h381
-rw-r--r--drivers/net/ethernet/cavium/thunder/q_struct.h701
-rw-r--r--drivers/net/ethernet/cavium/thunder/thunder_bgx.c966
-rw-r--r--drivers/net/ethernet/cavium/thunder/thunder_bgx.h220
-rw-r--r--drivers/net/ethernet/chelsio/Kconfig4
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c12
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4.h220
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c363
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c294
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c491
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h3
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/sge.c384
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c2215
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.h38
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_msg.h86
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_regs.h184
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_values.h24
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h72
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h5
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c13
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/sge.c123
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h18
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c36
-rw-r--r--drivers/net/ethernet/cirrus/Kconfig12
-rw-r--r--drivers/net/ethernet/cisco/Kconfig4
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_clsf.c31
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_ethtool.c10
-rw-r--r--drivers/net/ethernet/dec/Kconfig4
-rw-r--r--drivers/net/ethernet/dec/tulip/Kconfig10
-rw-r--r--drivers/net/ethernet/dec/tulip/de4x5.c10
-rw-r--r--drivers/net/ethernet/dec/tulip/uli526x.c2
-rw-r--r--drivers/net/ethernet/dlink/Kconfig4
-rw-r--r--drivers/net/ethernet/dlink/dl2k.c4
-rw-r--r--drivers/net/ethernet/emulex/Kconfig4
-rw-r--r--drivers/net/ethernet/emulex/benet/Kconfig9
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h55
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.c56
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.h50
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c11
-rw-r--r--drivers/net/ethernet/emulex/benet/be_hw.h14
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c502
-rw-r--r--drivers/net/ethernet/emulex/benet/be_roce.c2
-rw-r--r--drivers/net/ethernet/emulex/benet/be_roce.h2
-rw-r--r--drivers/net/ethernet/ezchip/Kconfig26
-rw-r--r--drivers/net/ethernet/ezchip/Makefile1
-rw-r--r--drivers/net/ethernet/ezchip/nps_enet.c658
-rw-r--r--drivers/net/ethernet/ezchip/nps_enet.h336
-rw-r--r--drivers/net/ethernet/faraday/Kconfig4
-rw-r--r--drivers/net/ethernet/freescale/Kconfig4
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c82
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c1
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c33
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c53
-rw-r--r--drivers/net/ethernet/fujitsu/Kconfig4
-rw-r--r--drivers/net/ethernet/hisilicon/Kconfig4
-rw-r--r--drivers/net/ethernet/hisilicon/hip04_eth.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hix5hd2_gmac.c1
-rw-r--r--drivers/net/ethernet/hp/Kconfig8
-rw-r--r--drivers/net/ethernet/i825xx/Kconfig4
-rw-r--r--drivers/net/ethernet/ibm/Kconfig4
-rw-r--r--drivers/net/ethernet/ibm/emac/core.c10
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c41
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.h5
-rw-r--r--drivers/net/ethernet/intel/Kconfig4
-rw-r--r--drivers/net/ethernet/intel/e100.c6
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c19
-rw-r--r--drivers/net/ethernet/intel/e1000e/80003es2lan.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/80003es2lan.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/82571.c4
-rw-r--r--drivers/net/ethernet/intel/e1000e/82571.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/defines.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/e1000.h8
-rw-r--r--drivers/net/ethernet/intel/e1000e/ethtool.c29
-rw-r--r--drivers/net/ethernet/intel/e1000e/hw.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c26
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.h11
-rw-r--r--drivers/net/ethernet/intel/e1000e/mac.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/mac.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/manage.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/manage.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c205
-rw-r--r--drivers/net/ethernet/intel/e1000e/nvm.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/nvm.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/param.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/phy.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/phy.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/ptp.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/regs.h4
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c5
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_iov.c38
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_main.c66
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_mbx.c5
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_netdev.c11
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_pci.c27
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_pf.c18
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_pf.h8
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_ptp.c13
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_type.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e.h5
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ethtool.c30
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_fcoe.c11
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c43
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c146
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_type.h1
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c7
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_txrx.c160
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_txrx.h2
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_type.h1
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c38
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c3
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c7
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_common.c63
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_common.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c51
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c161
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c91
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_type.h272
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c46
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c896
-rw-r--r--drivers/net/ethernet/marvell/Kconfig4
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c9
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c8
-rw-r--r--drivers/net/ethernet/mellanox/Kconfig4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cmd.c110
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cq.c13
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_cq.c56
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c30
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_port.c29
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_resources.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c13
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/eq.c400
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c266
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h17
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_stats.h10
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/profile.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/qp.c9
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c208
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/Kconfig14
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/Makefile5
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/alloc.c96
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cmd.c36
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cq.c18
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en.h521
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c679
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c860
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_main.c1915
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rx.c252
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tx.c350
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c105
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eq.c23
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/flow_table.c422
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fw.c146
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c343
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mcg.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h21
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/port.c226
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/qp.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/srq.c444
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/transobj.c360
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/transobj.h64
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/uar.c44
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/vport.c345
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/wq.c183
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/wq.h171
-rw-r--r--drivers/net/ethernet/micrel/Kconfig4
-rw-r--r--drivers/net/ethernet/micrel/ksz884x.c4
-rw-r--r--drivers/net/ethernet/microchip/Kconfig4
-rw-r--r--drivers/net/ethernet/moxa/Kconfig4
-rw-r--r--drivers/net/ethernet/moxa/moxart_ether.c1
-rw-r--r--drivers/net/ethernet/myricom/Kconfig4
-rw-r--r--drivers/net/ethernet/natsemi/Kconfig7
-rw-r--r--drivers/net/ethernet/neterion/Kconfig4
-rw-r--r--drivers/net/ethernet/neterion/s2io.c6
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-traffic.c7
-rw-r--r--drivers/net/ethernet/nuvoton/Kconfig4
-rw-r--r--drivers/net/ethernet/nvidia/Kconfig8
-rw-r--r--drivers/net/ethernet/oki-semi/Kconfig4
-rw-r--r--drivers/net/ethernet/packetengines/Kconfig8
-rw-r--r--drivers/net/ethernet/pasemi/Kconfig4
-rw-r--r--drivers/net/ethernet/qlogic/Kconfig4
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h3
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c77
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_main.c4
-rw-r--r--drivers/net/ethernet/qualcomm/Kconfig4
-rw-r--r--drivers/net/ethernet/qualcomm/qca_spi.c46
-rw-r--r--drivers/net/ethernet/rdc/Kconfig4
-rw-r--r--drivers/net/ethernet/realtek/Kconfig14
-rw-r--r--drivers/net/ethernet/renesas/Kconfig29
-rw-r--r--drivers/net/ethernet/renesas/Makefile4
-rw-r--r--drivers/net/ethernet/renesas/ravb.h832
-rw-r--r--drivers/net/ethernet/renesas/ravb_main.c1824
-rw-r--r--drivers/net/ethernet/renesas/ravb_ptp.c357
-rw-r--r--drivers/net/ethernet/rocker/rocker.c1615
-rw-r--r--drivers/net/ethernet/rocker/rocker.h28
-rw-r--r--drivers/net/ethernet/seeq/Kconfig4
-rw-r--r--drivers/net/ethernet/sfc/Kconfig9
-rw-r--r--drivers/net/ethernet/sfc/Makefile2
-rw-r--r--drivers/net/ethernet/sfc/ef10.c1147
-rw-r--r--drivers/net/ethernet/sfc/ef10_sriov.c783
-rw-r--r--drivers/net/ethernet/sfc/ef10_sriov.h69
-rw-r--r--drivers/net/ethernet/sfc/efx.c317
-rw-r--r--drivers/net/ethernet/sfc/efx.h15
-rw-r--r--drivers/net/ethernet/sfc/enum.h2
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c7
-rw-r--r--drivers/net/ethernet/sfc/falcon.c33
-rw-r--r--drivers/net/ethernet/sfc/farch.c64
-rw-r--r--drivers/net/ethernet/sfc/mcdi.c228
-rw-r--r--drivers/net/ethernet/sfc/mcdi.h16
-rw-r--r--drivers/net/ethernet/sfc/mcdi_pcol.h434
-rw-r--r--drivers/net/ethernet/sfc/mcdi_port.c13
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h34
-rw-r--r--drivers/net/ethernet/sfc/nic.h251
-rw-r--r--drivers/net/ethernet/sfc/ptp.c40
-rw-r--r--drivers/net/ethernet/sfc/siena.c27
-rw-r--r--drivers/net/ethernet/sfc/siena_sriov.c156
-rw-r--r--drivers/net/ethernet/sfc/siena_sriov.h79
-rw-r--r--drivers/net/ethernet/sfc/sriov.c83
-rw-r--r--drivers/net/ethernet/sfc/sriov.h31
-rw-r--r--drivers/net/ethernet/sgi/Kconfig8
-rw-r--r--drivers/net/ethernet/silan/Kconfig4
-rw-r--r--drivers/net/ethernet/sis/Kconfig4
-rw-r--r--drivers/net/ethernet/smsc/Kconfig18
-rw-r--r--drivers/net/ethernet/stmicro/Kconfig4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig90
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile14
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/descs.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c41
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c365
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c99
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c24
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c350
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c21
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c29
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c25
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/enh_desc.c3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/norm_desc.c3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h14
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c108
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c19
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c129
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h9
-rw-r--r--drivers/net/ethernet/sun/Kconfig4
-rw-r--r--drivers/net/ethernet/tehuti/Kconfig4
-rw-r--r--drivers/net/ethernet/ti/Kconfig8
-rw-r--r--drivers/net/ethernet/ti/cpsw.c9
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.c45
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.h2
-rw-r--r--drivers/net/ethernet/ti/netcp_core.c3
-rw-r--r--drivers/net/ethernet/tile/tilepro.c3
-rw-r--r--drivers/net/ethernet/toshiba/Kconfig4
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_net.c24
-rw-r--r--drivers/net/ethernet/toshiba/spider_net.c3
-rw-r--r--drivers/net/ethernet/tundra/Kconfig4
-rw-r--r--drivers/net/ethernet/via/Kconfig8
-rw-r--r--drivers/net/ethernet/via/via-rhine.c250
-rw-r--r--drivers/net/ethernet/wiznet/Kconfig4
-rw-r--r--drivers/net/ethernet/xilinx/Kconfig4
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac_main.c16
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet.h108
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c288
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c30
-rw-r--r--drivers/net/ethernet/xircom/Kconfig4
-rw-r--r--drivers/net/ethernet/xscale/Kconfig4
-rw-r--r--drivers/net/fddi/skfp/srf.c2
-rw-r--r--drivers/net/geneve.c523
-rw-r--r--drivers/net/hamradio/bpqether.c1
-rw-r--r--drivers/net/hyperv/hyperv_net.h10
-rw-r--r--drivers/net/hyperv/netvsc.c54
-rw-r--r--drivers/net/hyperv/netvsc_drv.c97
-rw-r--r--drivers/net/hyperv/rndis_filter.c16
-rw-r--r--drivers/net/ieee802154/Kconfig10
-rw-r--r--drivers/net/ieee802154/Makefile1
-rw-r--r--drivers/net/ieee802154/at86rf230.c488
-rw-r--r--drivers/net/ieee802154/at86rf230.h220
-rw-r--r--drivers/net/ieee802154/atusb.c762
-rw-r--r--drivers/net/ieee802154/atusb.h84
-rw-r--r--drivers/net/ieee802154/cc2520.c153
-rw-r--r--drivers/net/ieee802154/fakelb.c212
-rw-r--r--drivers/net/ieee802154/mrf24j40.c12
-rw-r--r--drivers/net/ipvlan/ipvlan.h5
-rw-r--r--drivers/net/ipvlan/ipvlan_core.c138
-rw-r--r--drivers/net/ipvlan/ipvlan_main.c25
-rw-r--r--drivers/net/irda/irda-usb.c4
-rw-r--r--drivers/net/macvtap.c44
-rw-r--r--drivers/net/phy/Kconfig13
-rw-r--r--drivers/net/phy/Makefile2
-rw-r--r--drivers/net/phy/amd-xgbe-phy.c1901
-rw-r--r--drivers/net/phy/bcm7xxx.c7
-rw-r--r--drivers/net/phy/davicom.c13
-rw-r--r--drivers/net/phy/dp83867.c239
-rw-r--r--drivers/net/phy/icplus.c5
-rw-r--r--drivers/net/phy/marvell.c10
-rw-r--r--drivers/net/phy/mdio-bcm-unimac.c8
-rw-r--r--drivers/net/phy/mdio-bitbang.c7
-rw-r--r--drivers/net/phy/mdio-gpio.c1
-rw-r--r--drivers/net/phy/micrel.c53
-rw-r--r--drivers/net/phy/phy.c34
-rw-r--r--drivers/net/phy/realtek.c68
-rw-r--r--drivers/net/ppp/pppoe.c4
-rw-r--r--drivers/net/ppp/pppox.c2
-rw-r--r--drivers/net/ppp/pptp.c6
-rw-r--r--drivers/net/team/team.c10
-rw-r--r--drivers/net/tun.c26
-rw-r--r--drivers/net/vmxnet3/vmxnet3_defs.h38
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c164
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h4
-rw-r--r--drivers/net/vxlan.c10
-rw-r--r--drivers/net/wan/cosa.c2
-rw-r--r--drivers/net/wan/dscc4.c9
-rw-r--r--drivers/net/wan/lapbether.c1
-rw-r--r--drivers/net/wireless/Kconfig1
-rw-r--r--drivers/net/wireless/Makefile2
-rw-r--r--drivers/net/wireless/adm8211.c35
-rw-r--r--drivers/net/wireless/at76c50x-usb.c4
-rw-r--r--drivers/net/wireless/at76c50x-usb.h2
-rw-r--r--drivers/net/wireless/ath/ar5523/ar5523.c9
-rw-r--r--drivers/net/wireless/ath/ath.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/Makefile4
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c182
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h65
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c127
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.c50
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.c98
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h132
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c208
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c34
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.c21
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h59
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c2840
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.h29
-rw-r--r--drivers/net/wireless/ath/ath10k/p2p.c156
-rw-r--r--drivers/net/wireless/ath/ath10k/p2p.h28
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c362
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.h95
-rw-r--r--drivers/net/wireless/ath/ath10k/rx_desc.h22
-rw-r--r--drivers/net/wireless/ath/ath10k/spectral.c5
-rw-r--r--drivers/net/wireless/ath/ath10k/thermal.c134
-rw-r--r--drivers/net/wireless/ath/ath10k/thermal.h10
-rw-r--r--drivers/net/wireless/ath/ath10k/trace.h22
-rw-r--r--drivers/net/wireless/ath/ath10k/txrx.c9
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-ops.h194
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c582
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.h168
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c312
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h229
-rw-r--r--drivers/net/wireless/ath/ath10k/wow.c321
-rw-r--r--drivers/net/wireless/ath/ath10k/wow.h40
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h1
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c12
-rw-r--r--drivers/net/wireless/ath/ath5k/led.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c16
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c4
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c155
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_phy.c144
-rw-r--r--drivers/net/wireless/ath/ath9k/common-spectral.c740
-rw-r--r--drivers/net/wireless/ath/ath9k/common-spectral.h35
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h8
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_beacon.c19
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c25
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c20
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c24
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c5
-rw-r--r--drivers/net/wireless/ath/carl9170/fw.c5
-rw-r--r--drivers/net/wireless/ath/carl9170/led.c2
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c27
-rw-r--r--drivers/net/wireless/ath/carl9170/usb.c5
-rw-r--r--drivers/net/wireless/ath/dfs_pattern_detector.c72
-rw-r--r--drivers/net/wireless/ath/dfs_pattern_detector.h4
-rw-r--r--drivers/net/wireless/ath/dfs_pri_detector.c4
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c12
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.c4
-rw-r--r--drivers/net/wireless/ath/wil6210/Makefile1
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c174
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c115
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c33
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c8
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c105
-rw-r--r--drivers/net/wireless/ath/wil6210/pmc.c375
-rw-r--r--drivers/net/wireless/ath/wil6210/pmc.h27
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c50
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.h24
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h33
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform.c14
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform.h3
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c75
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h50
-rw-r--r--drivers/net/wireless/b43/main.c16
-rw-r--r--drivers/net/wireless/b43legacy/main.c13
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c37
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c521
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/chip.c1
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/commonring.c37
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/commonring.h3
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/core.c4
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/debug.c50
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/feature.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/feature.h8
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/firmware.c251
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/firmware.h6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/flowring.c5
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/flowring.h4
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h79
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c32
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/of.c11
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.c203
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/pcie.c200
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio.c17
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c9
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c12
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/main.c2
-rw-r--r--drivers/net/wireless/brcm80211/include/brcm_hw_ids.h3
-rw-r--r--drivers/net/wireless/cw1200/main.c16
-rw-r--r--drivers/net/wireless/cw1200/sta.c10
-rw-r--r--drivers/net/wireless/iwlegacy/3945-mac.c10
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c16
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig12
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile1
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c33
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-7000.c25
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-8000.c71
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-config.h45
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h15
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fh.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-file.h107
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.c113
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h22
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex.c103
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c22
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c21
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c14
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h91
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h63
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw.c23
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c443
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h162
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c16
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c37
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.c44
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rx.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c1418
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c14
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.c33
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tt.c40
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c35
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/utils.c2
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/drv.c17
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/internal.h51
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/rx.c415
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c135
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c2
-rw-r--r--drivers/net/wireless/libertas/cfg.c13
-rw-r--r--drivers/net/wireless/libertas/cfg.h3
-rw-r--r--drivers/net/wireless/libertas/cmd.h3
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c13
-rw-r--r--drivers/net/wireless/libertas_tf/main.c9
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c77
-rw-r--r--drivers/net/wireless/mediatek/Kconfig10
-rw-r--r--drivers/net/wireless/mediatek/Makefile1
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/Kconfig6
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/Makefile9
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/core.c78
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/debugfs.c172
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/dma.c505
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/dma.h127
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/eeprom.c418
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/eeprom.h151
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/init.c628
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/initvals.h164
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/initvals_phy.h291
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mac.c573
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mac.h178
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/main.c413
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mcu.c534
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mcu.h94
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mt7601u.h390
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/phy.c1251
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/regs.h636
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/trace.c21
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/trace.h400
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/tx.c319
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/usb.c367
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/usb.h77
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/util.c42
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/util.h77
-rw-r--r--drivers/net/wireless/mwifiex/11h.c72
-rw-r--r--drivers/net/wireless/mwifiex/11n.c128
-rw-r--r--drivers/net/wireless/mwifiex/11n_aggr.c7
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.c136
-rw-r--r--drivers/net/wireless/mwifiex/Kconfig2
-rw-r--r--drivers/net/wireless/mwifiex/README6
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c592
-rw-r--r--drivers/net/wireless/mwifiex/cfp.c50
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c368
-rw-r--r--drivers/net/wireless/mwifiex/debugfs.c165
-rw-r--r--drivers/net/wireless/mwifiex/decl.h7
-rw-r--r--drivers/net/wireless/mwifiex/ethtool.c97
-rw-r--r--drivers/net/wireless/mwifiex/fw.h71
-rw-r--r--drivers/net/wireless/mwifiex/ie.c102
-rw-r--r--drivers/net/wireless/mwifiex/init.c54
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h7
-rw-r--r--drivers/net/wireless/mwifiex/join.c254
-rw-r--r--drivers/net/wireless/mwifiex/main.c224
-rw-r--r--drivers/net/wireless/mwifiex/main.h96
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c589
-rw-r--r--drivers/net/wireless/mwifiex/scan.c377
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c458
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c159
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c223
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c194
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c147
-rw-r--r--drivers/net/wireless/mwifiex/sta_rx.c13
-rw-r--r--drivers/net/wireless/mwifiex/sta_tx.c18
-rw-r--r--drivers/net/wireless/mwifiex/tdls.c86
-rw-r--r--drivers/net/wireless/mwifiex/txrx.c51
-rw-r--r--drivers/net/wireless/mwifiex/uap_cmd.c75
-rw-r--r--drivers/net/wireless/mwifiex/uap_event.c112
-rw-r--r--drivers/net/wireless/mwifiex/uap_txrx.c54
-rw-r--r--drivers/net/wireless/mwifiex/usb.c141
-rw-r--r--drivers/net/wireless/mwifiex/util.c84
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c107
-rw-r--r--drivers/net/wireless/mwl8k.c11
-rw-r--r--drivers/net/wireless/p54/fwio.c3
-rw-r--r--drivers/net/wireless/p54/led.c2
-rw-r--r--drivers/net/wireless/p54/main.c18
-rw-r--r--drivers/net/wireless/ray_cs.c2
-rw-r--r--drivers/net/wireless/rndis_wlan.c8
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_mac80211.c7
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c12
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c12
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c13
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h10
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c92
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.h5
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800soc.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c22
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c13
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c13
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/dev.c9
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/dev.c6
-rw-r--r--drivers/net/wireless/rtlwifi/Kconfig2
-rw-r--r--drivers/net/wireless/rtlwifi/base.c22
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c7
-rw-r--r--drivers/net/wireless/rtlwifi/core.h3
-rw-r--r--drivers/net/wireless/rtlwifi/regd.c42
-rw-r--r--drivers/net/wireless/rtlwifi/regd.h1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/dm.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/hw.c20
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c3
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/hw.c54
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/mac.c17
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/mac.h5
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/phy.c28
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/rf.c22
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/trx.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/dm.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/fw.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/hw.c21
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/dm.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/hw.c13
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/dm.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/fw.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/hw.c21
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8821ae/dm.c14
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8821ae/hw.c24
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h1
-rw-r--r--drivers/net/wireless/ti/wl1251/acx.c3
-rw-r--r--drivers/net/wireless/ti/wl1251/main.c12
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c71
-rw-r--r--drivers/net/wireless/ti/wl18xx/reg.h1
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c54
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c12
-rw-r--r--drivers/net/xen-netback/netback.c21
-rw-r--r--drivers/net/xen-netback/xenbus.c4
-rw-r--r--drivers/net/xen-netfront.c7
-rw-r--r--drivers/nfc/Kconfig2
-rw-r--r--drivers/nfc/Makefile4
-rw-r--r--drivers/nfc/microread/i2c.c3
-rw-r--r--drivers/nfc/nfcmrvl/Kconfig11
-rw-r--r--drivers/nfc/nfcmrvl/Makefile3
-rw-r--r--drivers/nfc/nfcmrvl/main.c134
-rw-r--r--drivers/nfc/nfcmrvl/nfcmrvl.h60
-rw-r--r--drivers/nfc/nfcmrvl/uart.c225
-rw-r--r--drivers/nfc/nfcmrvl/usb.c27
-rw-r--r--drivers/nfc/nxp-nci/Makefile2
-rw-r--r--drivers/nfc/nxp-nci/i2c.c52
-rw-r--r--drivers/nfc/pn544/i2c.c43
-rw-r--r--drivers/nfc/st-nci/Kconfig23
-rw-r--r--drivers/nfc/st-nci/Makefile9
-rw-r--r--drivers/nfc/st-nci/core.c179
-rw-r--r--drivers/nfc/st-nci/i2c.c (renamed from drivers/nfc/st21nfcb/i2c.c)147
-rw-r--r--drivers/nfc/st-nci/ndlc.c (renamed from drivers/nfc/st21nfcb/ndlc.c)23
-rw-r--r--drivers/nfc/st-nci/ndlc.h (renamed from drivers/nfc/st21nfcb/ndlc.h)5
-rw-r--r--drivers/nfc/st-nci/st-nci.h (renamed from drivers/nfc/st21nfcb/st21nfcb.h)30
-rw-r--r--drivers/nfc/st-nci/st-nci_se.c (renamed from drivers/nfc/st21nfcb/st21nfcb_se.c)383
-rw-r--r--drivers/nfc/st-nci/st-nci_se.h61
-rw-r--r--drivers/nfc/st21nfcb/Kconfig22
-rw-r--r--drivers/nfc/st21nfcb/Makefile9
-rw-r--r--drivers/nfc/st21nfcb/st21nfcb.c143
-rw-r--r--drivers/nfc/st21nfcb/st21nfcb_se.h61
-rw-r--r--drivers/nfc/trf7970a.c23
-rw-r--r--drivers/of/of_mdio.c3
-rw-r--r--drivers/pinctrl/Kconfig19
-rw-r--r--drivers/pinctrl/Makefile2
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm281xx.c4
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm2835.c4
-rw-r--r--drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c8
-rw-r--r--drivers/pinctrl/bcm/pinctrl-cygnus-mux.c4
-rw-r--r--drivers/pinctrl/berlin/berlin-bg2.c18
-rw-r--r--drivers/pinctrl/berlin/berlin-bg2cd.c8
-rw-r--r--drivers/pinctrl/berlin/berlin-bg2q.c16
-rw-r--r--drivers/pinctrl/berlin/berlin.c4
-rw-r--r--drivers/pinctrl/core.c21
-rw-r--r--drivers/pinctrl/freescale/Kconfig7
-rw-r--r--drivers/pinctrl/freescale/Makefile1
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx.c59
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx1-core.c4
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx7d.c384
-rw-r--r--drivers/pinctrl/freescale/pinctrl-mxs.c4
-rw-r--r--drivers/pinctrl/intel/pinctrl-cherryview.c4
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.c4
-rw-r--r--drivers/pinctrl/intel/pinctrl-sunrisepoint.c263
-rw-r--r--drivers/pinctrl/mediatek/Kconfig13
-rw-r--r--drivers/pinctrl/mediatek/Makefile2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt6397.c77
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8127.c358
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8135.c13
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8173.c377
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.c161
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.h75
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-mt6397.h424
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-mt8127.h1318
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson.c4
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-370.c22
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-375.c50
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-38x.c120
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-39x.c131
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-xp.c98
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.c4
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-ab8505.c2
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-abx500.c5
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-nomadik.c66
-rw-r--r--drivers/pinctrl/pinctrl-adi2.c5
-rw-r--r--drivers/pinctrl/pinctrl-amd.c5
-rw-r--r--drivers/pinctrl/pinctrl-as3722.c4
-rw-r--r--drivers/pinctrl/pinctrl-at91.c20
-rw-r--r--drivers/pinctrl/pinctrl-lantiq.c4
-rw-r--r--drivers/pinctrl/pinctrl-lpc18xx.c1220
-rw-r--r--drivers/pinctrl/pinctrl-palmas.c4
-rw-r--r--drivers/pinctrl/pinctrl-pistachio.c1504
-rw-r--r--drivers/pinctrl/pinctrl-rockchip.c131
-rw-r--r--drivers/pinctrl/pinctrl-single.c6
-rw-r--r--drivers/pinctrl/pinctrl-st.c4
-rw-r--r--drivers/pinctrl/pinctrl-tb10x.c4
-rw-r--r--drivers/pinctrl/pinctrl-tegra-xusb.c27
-rw-r--r--drivers/pinctrl/pinctrl-tegra.c4
-rw-r--r--drivers/pinctrl/pinctrl-tz1090-pdc.c4
-rw-r--r--drivers/pinctrl/pinctrl-tz1090.c4
-rw-r--r--drivers/pinctrl/pinctrl-u300.c4
-rw-r--r--drivers/pinctrl/pinctrl-zynq.c91
-rw-r--r--drivers/pinctrl/pinmux.c59
-rw-r--r--drivers/pinctrl/qcom/Kconfig8
-rw-r--r--drivers/pinctrl/qcom/Makefile1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.c4
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm8660.c984
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-gpio.c4
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-mpp.c4
-rw-r--r--drivers/pinctrl/samsung/pinctrl-exynos5440.c4
-rw-r--r--drivers/pinctrl/samsung/pinctrl-samsung.c6
-rw-r--r--drivers/pinctrl/sh-pfc/Kconfig10
-rw-r--r--drivers/pinctrl/sh-pfc/Makefile2
-rw-r--r--drivers/pinctrl/sh-pfc/core.c15
-rw-r--r--drivers/pinctrl/sh-pfc/core.h2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a73a4.c4
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7740.c2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7790.c101
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7791.c186
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7794.c4207
-rw-r--r--drivers/pinctrl/sh-pfc/pinctrl.c4
-rw-r--r--drivers/pinctrl/sirf/Makefile1
-rw-r--r--drivers/pinctrl/sirf/pinctrl-atlas7.c4637
-rw-r--r--drivers/pinctrl/sirf/pinctrl-sirf.c4
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear.c4
-rw-r--r--drivers/pinctrl/sunxi/Kconfig4
-rw-r--r--drivers/pinctrl/sunxi/Makefile1
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c1
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c513
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.c4
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wmt.c4
-rw-r--r--drivers/s390/net/lcs.c2
-rw-r--r--drivers/s390/net/qeth_core.h2
-rw-r--r--drivers/s390/net/qeth_core_main.c3
-rw-r--r--drivers/s390/net/qeth_core_mpc.c3
-rw-r--r--drivers/s390/net/qeth_core_mpc.h3
-rw-r--r--drivers/s390/net/qeth_l2_main.c124
-rw-r--r--drivers/s390/net/qeth_l2_sys.c74
-rw-r--r--drivers/s390/net/qeth_l3_main.c9
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.c2
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c1
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h1
-rw-r--r--drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c2
-rw-r--r--drivers/staging/vt6655/device_main.c19
-rw-r--r--drivers/staging/vt6656/main_usb.c19
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c2
-rw-r--r--drivers/target/iscsi/iscsi_target.c1
-rw-r--r--drivers/target/target_core_file.c1
-rw-r--r--drivers/target/target_core_pr.c1
-rw-r--r--drivers/target/target_core_transport.c1
-rw-r--r--drivers/target/target_core_user.c1
-rw-r--r--drivers/tty/sysrq.c19
-rw-r--r--drivers/tty/vt/keyboard.c156
-rw-r--r--drivers/vhost/scsi.c1
-rw-r--r--drivers/video/backlight/Kconfig8
-rw-r--r--drivers/video/backlight/da9052_bl.c2
-rw-r--r--drivers/video/backlight/gpio_backlight.c2
-rw-r--r--drivers/video/backlight/lp855x_bl.c18
-rw-r--r--drivers/video/backlight/pwm_bl.c6
979 files changed, 100002 insertions, 20397 deletions
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index 93dca2e73bf5..a8da3a50e374 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -116,8 +116,8 @@ static bool disable64;
static short nvpibits = -1;
static short nvcibits = -1;
static short rx_skb_reserve = 16;
-static bool irq_coalesce = 1;
-static bool sdh = 0;
+static bool irq_coalesce = true;
+static bool sdh;
/* Read from EEPROM = 0000 0011b */
static unsigned int readtab[] = {
diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c
index 909c95bd7be2..feb023d7eebd 100644
--- a/drivers/atm/idt77105.c
+++ b/drivers/atm/idt77105.c
@@ -306,14 +306,12 @@ static int idt77105_start(struct atm_dev *dev)
if (start_timer) {
start_timer = 0;
- init_timer(&stats_timer);
+ setup_timer(&stats_timer, idt77105_stats_timer_func, 0UL);
stats_timer.expires = jiffies+IDT77105_STATS_TIMER_PERIOD;
- stats_timer.function = idt77105_stats_timer_func;
add_timer(&stats_timer);
- init_timer(&restart_timer);
+ setup_timer(&restart_timer, idt77105_restart_timer_func, 0UL);
restart_timer.expires = jiffies+IDT77105_RESTART_TIMER_PERIOD;
- restart_timer.function = idt77105_restart_timer_func;
add_timer(&restart_timer);
}
spin_unlock_irqrestore(&idt77105_priv_lock, flags);
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 924f8e26789d..65e65903faa0 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -2618,7 +2618,7 @@ static void ia_close(struct atm_vcc *vcc)
if (vcc->qos.txtp.traffic_class != ATM_NONE) {
iadev->close_pending++;
prepare_to_wait(&iadev->timeout_wait, &wait, TASK_UNINTERRUPTIBLE);
- schedule_timeout(50);
+ schedule_timeout(msecs_to_jiffies(500));
finish_wait(&iadev->timeout_wait, &wait);
spin_lock_irqsave(&iadev->tx_lock, flags);
while((skb = skb_dequeue(&iadev->tx_backlog))) {
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index fc6ffcfa8061..be5fffb6da24 100644
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -29,12 +29,6 @@ config BCMA_HOST_PCI
select BCMA_DRIVER_PCI
default y
-config BCMA_DRIVER_PCI_HOSTMODE
- bool "Driver for PCI core working in hostmode"
- depends on BCMA && MIPS && BCMA_HOST_PCI
- help
- PCI core hostmode operation (external PCI bus).
-
config BCMA_HOST_SOC
bool "Support for BCMA in a SoC"
depends on BCMA
@@ -61,6 +55,12 @@ config BCMA_DRIVER_PCI
This driver is also prerequisite for a hostmode PCIe core
support.
+config BCMA_DRIVER_PCI_HOSTMODE
+ bool "Driver for PCI core working in hostmode"
+ depends on BCMA && MIPS && BCMA_DRIVER_PCI
+ help
+ PCI core hostmode operation (external PCI bus).
+
config BCMA_DRIVER_MIPS
bool "BCMA Broadcom MIPS core driver"
depends on BCMA && MIPS
diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c
index 74ccb02e0f10..5f6018e7cd4c 100644
--- a/drivers/bcma/driver_gpio.c
+++ b/drivers/bcma/driver_gpio.c
@@ -226,6 +226,7 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
chip->of_node = cc->core->dev.of_node;
#endif
switch (bus->chipinfo.id) {
+ case BCMA_CHIP_ID_BCM4707:
case BCMA_CHIP_ID_BCM5357:
case BCMA_CHIP_ID_BCM53572:
chip->ngpio = 32;
@@ -235,16 +236,17 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
}
/*
- * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO
- * pin numbers. We don't have Device Tree there and we can't really use
- * relative (per chip) numbers.
- * So let's use predictable base for BCM47XX and "random" for all other.
+ * Register SoC GPIO devices with absolute GPIO pin base.
+ * On MIPS, we don't have Device Tree and we can't use relative (per chip)
+ * GPIO numbers.
+ * On some ARM devices, user space may want to access some system GPIO
+ * pins directly, which is easier to do with a predictable GPIO base.
*/
-#if IS_BUILTIN(CONFIG_BCM47XX)
- chip->base = bus->num * BCMA_GPIO_MAX_PINS;
-#else
- chip->base = -1;
-#endif
+ if (IS_BUILTIN(CONFIG_BCM47XX) ||
+ cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
+ chip->base = bus->num * BCMA_GPIO_MAX_PINS;
+ else
+ chip->base = -1;
err = bcma_gpio_irq_domain_init(cc);
if (err)
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index cee20354ac37..c097909c589c 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -598,7 +598,7 @@ static struct socket *drbd_try_connect(struct drbd_connection *connection)
memcpy(&peer_in6, &connection->peer_addr, peer_addr_len);
what = "sock_create_kern";
- err = sock_create_kern(((struct sockaddr *)&src_in6)->sa_family,
+ err = sock_create_kern(&init_net, ((struct sockaddr *)&src_in6)->sa_family,
SOCK_STREAM, IPPROTO_TCP, &sock);
if (err < 0) {
sock = NULL;
@@ -693,7 +693,7 @@ static int prepare_listen_socket(struct drbd_connection *connection, struct acce
memcpy(&my_addr, &connection->my_addr, my_addr_len);
what = "sock_create_kern";
- err = sock_create_kern(((struct sockaddr *)&my_addr)->sa_family,
+ err = sock_create_kern(&init_net, ((struct sockaddr *)&my_addr)->sa_family,
SOCK_STREAM, IPPROTO_TCP, &s_listen);
if (err) {
s_listen = NULL;
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index ed5c2738bea2..2e777071e1dc 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -9,6 +9,10 @@ config BT_BCM
tristate
select FW_LOADER
+config BT_RTL
+ tristate
+ select FW_LOADER
+
config BT_HCIBTUSB
tristate "HCI USB driver"
depends on USB
@@ -32,6 +36,17 @@ config BT_HCIBTUSB_BCM
Say Y here to compile support for Broadcom protocol.
+config BT_HCIBTUSB_RTL
+ bool "Realtek protocol support"
+ depends on BT_HCIBTUSB
+ select BT_RTL
+ default y
+ help
+ The Realtek protocol support enables firmware and configuration
+ download support for Realtek Bluetooth controllers.
+
+ Say Y here to compile support for Realtek protocol.
+
config BT_HCIBTSDIO
tristate "HCI SDIO driver"
depends on MMC
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index dd0d9c40b999..f40e194e7080 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_BT_MRVL) += btmrvl.o
obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o
obj-$(CONFIG_BT_WILINK) += btwilink.o
obj-$(CONFIG_BT_BCM) += btbcm.o
+obj-$(CONFIG_BT_RTL) += btrtl.o
btmrvl-y := btmrvl_main.o
btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 8c81af6dbe06..e527a3e13939 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -80,6 +80,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x0489, 0xe057) },
{ USB_DEVICE(0x0489, 0xe056) },
{ USB_DEVICE(0x0489, 0xe05f) },
+ { USB_DEVICE(0x0489, 0xe076) },
{ USB_DEVICE(0x0489, 0xe078) },
{ USB_DEVICE(0x04c5, 0x1330) },
{ USB_DEVICE(0x04CA, 0x3004) },
@@ -88,6 +89,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x04CA, 0x3007) },
{ USB_DEVICE(0x04CA, 0x3008) },
{ USB_DEVICE(0x04CA, 0x300b) },
+ { USB_DEVICE(0x04CA, 0x300d) },
{ USB_DEVICE(0x04CA, 0x300f) },
{ USB_DEVICE(0x04CA, 0x3010) },
{ USB_DEVICE(0x0930, 0x0219) },
@@ -113,6 +115,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x13d3, 0x3408) },
{ USB_DEVICE(0x13d3, 0x3423) },
{ USB_DEVICE(0x13d3, 0x3432) },
+ { USB_DEVICE(0x13d3, 0x3474) },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE02C) },
@@ -137,6 +140,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe076), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
@@ -145,6 +149,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x04ca, 0x3007), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04ca, 0x300d), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
@@ -170,6 +175,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 },
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 6de97b3871b0..7aab65427d38 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -202,9 +202,8 @@ static void bt3c_write_wakeup(struct bt3c_info *info)
/* Send frame */
len = bt3c_write(iobase, 256, skb->data, skb->len);
- if (len != skb->len) {
+ if (len != skb->len)
BT_ERR("Very strange");
- }
kfree_skb(skb);
diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c
index 4bba86677adc..1e1a4323a71f 100644
--- a/drivers/bluetooth/btbcm.c
+++ b/drivers/bluetooth/btbcm.c
@@ -33,6 +33,7 @@
#define VERSION "0.1"
#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}})
+#define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}})
int btbcm_check_bdaddr(struct hci_dev *hdev)
{
@@ -55,17 +56,19 @@ int btbcm_check_bdaddr(struct hci_dev *hdev)
}
bda = (struct hci_rp_read_bd_addr *)skb->data;
- if (bda->status) {
- BT_ERR("%s: BCM: Device address result failed (%02x)",
- hdev->name, bda->status);
- kfree_skb(skb);
- return -bt_to_errno(bda->status);
- }
- /* The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller
+ /* Check if the address indicates a controller with either an
+ * invalid or default address. In both cases the device needs
+ * to be marked as not having a valid address.
+ *
+ * The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller
* with no configured address.
+ *
+ * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller
+ * with waiting for configuration state.
*/
- if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0)) {
+ if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) ||
+ !bacmp(&bda->bdaddr, BDADDR_BCM4324B3)) {
BT_INFO("%s: BCM: Using default device address (%pMR)",
hdev->name, &bda->bdaddr);
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
@@ -95,21 +98,14 @@ int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
}
EXPORT_SYMBOL_GPL(btbcm_set_bdaddr);
-int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
+int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw)
{
const struct hci_command_hdr *cmd;
- const struct firmware *fw;
const u8 *fw_ptr;
size_t fw_size;
struct sk_buff *skb;
u16 opcode;
- int err;
-
- err = request_firmware(&fw, firmware, &hdev->dev);
- if (err < 0) {
- BT_INFO("%s: BCM: Patch %s not found", hdev->name, firmware);
- return err;
- }
+ int err = 0;
/* Start Download */
skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT);
@@ -135,8 +131,7 @@ int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
fw_size -= sizeof(*cmd);
if (fw_size < cmd->plen) {
- BT_ERR("%s: BCM: Patch %s is corrupted", hdev->name,
- firmware);
+ BT_ERR("%s: BCM: Patch is corrupted", hdev->name);
err = -EINVAL;
goto done;
}
@@ -162,7 +157,6 @@ int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
msleep(250);
done:
- release_firmware(fw);
return err;
}
EXPORT_SYMBOL(btbcm_patchram);
@@ -248,9 +242,101 @@ static const struct {
const char *name;
} bcm_uart_subver_table[] = {
{ 0x410e, "BCM43341B0" }, /* 002.001.014 */
+ { 0x4406, "BCM4324B3" }, /* 002.004.006 */
+ { 0x610c, "BCM4354" }, /* 003.001.012 */
{ }
};
+int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len)
+{
+ u16 subver, rev;
+ const char *hw_name = NULL;
+ struct sk_buff *skb;
+ struct hci_rp_read_local_version *ver;
+ int i, err;
+
+ /* Reset */
+ err = btbcm_reset(hdev);
+ if (err)
+ return err;
+
+ /* Read Local Version Info */
+ skb = btbcm_read_local_version(hdev);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ ver = (struct hci_rp_read_local_version *)skb->data;
+ rev = le16_to_cpu(ver->hci_rev);
+ subver = le16_to_cpu(ver->lmp_subver);
+ kfree_skb(skb);
+
+ /* Read Verbose Config Version Info */
+ skb = btbcm_read_verbose_config(hdev);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]);
+ kfree_skb(skb);
+
+ switch ((rev & 0xf000) >> 12) {
+ case 0:
+ case 1:
+ case 3:
+ for (i = 0; bcm_uart_subver_table[i].name; i++) {
+ if (subver == bcm_uart_subver_table[i].subver) {
+ hw_name = bcm_uart_subver_table[i].name;
+ break;
+ }
+ }
+
+ snprintf(fw_name, len, "brcm/%s.hcd", hw_name ? : "BCM");
+ break;
+ default:
+ return 0;
+ }
+
+ BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
+ hw_name ? : "BCM", (subver & 0x7000) >> 13,
+ (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(btbcm_initialize);
+
+int btbcm_finalize(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+ struct hci_rp_read_local_version *ver;
+ u16 subver, rev;
+ int err;
+
+ /* Reset */
+ err = btbcm_reset(hdev);
+ if (err)
+ return err;
+
+ /* Read Local Version Info */
+ skb = btbcm_read_local_version(hdev);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ ver = (struct hci_rp_read_local_version *)skb->data;
+ rev = le16_to_cpu(ver->hci_rev);
+ subver = le16_to_cpu(ver->lmp_subver);
+ kfree_skb(skb);
+
+ BT_INFO("%s: BCM (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
+ (subver & 0x7000) >> 13, (subver & 0x1f00) >> 8,
+ (subver & 0x00ff), rev & 0x0fff);
+
+ btbcm_check_bdaddr(hdev);
+
+ set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(btbcm_finalize);
+
static const struct {
u16 subver;
const char *name;
@@ -271,6 +357,7 @@ static const struct {
int btbcm_setup_patchram(struct hci_dev *hdev)
{
char fw_name[64];
+ const struct firmware *fw;
u16 subver, rev, pid, vid;
const char *hw_name = NULL;
struct sk_buff *skb;
@@ -302,6 +389,7 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
switch ((rev & 0xf000) >> 12) {
case 0:
+ case 3:
for (i = 0; bcm_uart_subver_table[i].name; i++) {
if (subver == bcm_uart_subver_table[i].subver) {
hw_name = bcm_uart_subver_table[i].name;
@@ -341,9 +429,15 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
hw_name ? : "BCM", (subver & 0x7000) >> 13,
(subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
- err = btbcm_patchram(hdev, fw_name);
- if (err == -ENOENT)
+ err = request_firmware(&fw, fw_name, &hdev->dev);
+ if (err < 0) {
+ BT_INFO("%s: BCM: Patch %s not found", hdev->name, fw_name);
return 0;
+ }
+
+ btbcm_patchram(hdev, fw);
+
+ release_firmware(fw);
/* Reset */
err = btbcm_reset(hdev);
diff --git a/drivers/bluetooth/btbcm.h b/drivers/bluetooth/btbcm.h
index eb6ab5f9483d..d9e6b41658e5 100644
--- a/drivers/bluetooth/btbcm.h
+++ b/drivers/bluetooth/btbcm.h
@@ -21,15 +21,61 @@
*
*/
+#define BCM_UART_CLOCK_48MHZ 0x01
+#define BCM_UART_CLOCK_24MHZ 0x02
+
+struct bcm_update_uart_baud_rate {
+ __le16 zero;
+ __le32 baud_rate;
+} __packed;
+
+struct bcm_write_uart_clock_setting {
+ __u8 type;
+} __packed;
+
+struct bcm_set_sleep_mode {
+ __u8 sleep_mode;
+ __u8 idle_host;
+ __u8 idle_dev;
+ __u8 bt_wake_active;
+ __u8 host_wake_active;
+ __u8 allow_host_sleep;
+ __u8 combine_modes;
+ __u8 tristate_control;
+ __u8 usb_auto_sleep;
+ __u8 usb_resume_timeout;
+ __u8 pulsed_host_wake;
+ __u8 break_to_host;
+} __packed;
+
+struct bcm_set_pcm_int_params {
+ __u8 routing;
+ __u8 rate;
+ __u8 frame_sync;
+ __u8 sync_mode;
+ __u8 clock_mode;
+} __packed;
+
+struct bcm_set_pcm_format_params {
+ __u8 lsb_first;
+ __u8 fill_value;
+ __u8 fill_method;
+ __u8 fill_num;
+ __u8 right_justify;
+} __packed;
+
#if IS_ENABLED(CONFIG_BT_BCM)
int btbcm_check_bdaddr(struct hci_dev *hdev);
int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
-int btbcm_patchram(struct hci_dev *hdev, const char *firmware);
+int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw);
int btbcm_setup_patchram(struct hci_dev *hdev);
int btbcm_setup_apple(struct hci_dev *hdev);
+int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len);
+int btbcm_finalize(struct hci_dev *hdev);
+
#else
static inline int btbcm_check_bdaddr(struct hci_dev *hdev)
@@ -42,7 +88,7 @@ static inline int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
return -EOPNOTSUPP;
}
-static inline int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
+static inline int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw)
{
return -EOPNOTSUPP;
}
@@ -57,4 +103,15 @@ static inline int btbcm_setup_apple(struct hci_dev *hdev)
return 0;
}
+static inline int btbcm_initialize(struct hci_dev *hdev, char *fw_name,
+ size_t len)
+{
+ return 0;
+}
+
+static inline int btbcm_finalize(struct hci_dev *hdev)
+{
+ return 0;
+}
+
#endif
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 2d43d4279b00..828f2f8d1568 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -53,12 +53,6 @@ int btintel_check_bdaddr(struct hci_dev *hdev)
}
bda = (struct hci_rp_read_bd_addr *)skb->data;
- if (bda->status) {
- BT_ERR("%s: Intel device address result failed (%02x)",
- hdev->name, bda->status);
- kfree_skb(skb);
- return -bt_to_errno(bda->status);
- }
/* For some Intel based controllers, the default Bluetooth device
* address 00:03:19:9E:8B:00 can be found. These controllers are
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 01d6da577eeb..b9a811900f6a 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -1217,7 +1217,7 @@ static void btmrvl_sdio_dump_firmware(struct btmrvl_private *priv)
unsigned int reg, reg_start, reg_end;
enum rdwr_status stat;
u8 *dbg_ptr, *end_ptr, *fw_dump_data, *fw_dump_ptr;
- u8 dump_num, idx, i, read_reg, doneflag = 0;
+ u8 dump_num = 0, idx, i, read_reg, doneflag = 0;
u32 memory_size, fw_dump_len = 0;
/* dump sdio register first */
diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
new file mode 100644
index 000000000000..84288938f7f2
--- /dev/null
+++ b/drivers/bluetooth/btrtl.c
@@ -0,0 +1,390 @@
+/*
+ * Bluetooth support for Realtek devices
+ *
+ * Copyright (C) 2015 Endless Mobile, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <asm/unaligned.h>
+#include <linux/usb.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "btrtl.h"
+
+#define VERSION "0.1"
+
+#define RTL_EPATCH_SIGNATURE "Realtech"
+#define RTL_ROM_LMP_3499 0x3499
+#define RTL_ROM_LMP_8723A 0x1200
+#define RTL_ROM_LMP_8723B 0x8723
+#define RTL_ROM_LMP_8821A 0x8821
+#define RTL_ROM_LMP_8761A 0x8761
+
+static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version)
+{
+ struct rtl_rom_version_evt *rom_version;
+ struct sk_buff *skb;
+
+ /* Read RTL ROM version command */
+ skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: Read ROM version failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return PTR_ERR(skb);
+ }
+
+ if (skb->len != sizeof(*rom_version)) {
+ BT_ERR("%s: RTL version event length mismatch", hdev->name);
+ kfree_skb(skb);
+ return -EIO;
+ }
+
+ rom_version = (struct rtl_rom_version_evt *)skb->data;
+ BT_INFO("%s: rom_version status=%x version=%x",
+ hdev->name, rom_version->status, rom_version->version);
+
+ *version = rom_version->version;
+
+ kfree_skb(skb);
+ return 0;
+}
+
+static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
+ const struct firmware *fw,
+ unsigned char **_buf)
+{
+ const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
+ struct rtl_epatch_header *epatch_info;
+ unsigned char *buf;
+ int i, ret, len;
+ size_t min_size;
+ u8 opcode, length, data, rom_version = 0;
+ int project_id = -1;
+ const unsigned char *fwptr, *chip_id_base;
+ const unsigned char *patch_length_base, *patch_offset_base;
+ u32 patch_offset = 0;
+ u16 patch_length, num_patches;
+ const u16 project_id_to_lmp_subver[] = {
+ RTL_ROM_LMP_8723A,
+ RTL_ROM_LMP_8723B,
+ RTL_ROM_LMP_8821A,
+ RTL_ROM_LMP_8761A
+ };
+
+ ret = rtl_read_rom_version(hdev, &rom_version);
+ if (ret)
+ return ret;
+
+ min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
+ if (fw->size < min_size)
+ return -EINVAL;
+
+ fwptr = fw->data + fw->size - sizeof(extension_sig);
+ if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) {
+ BT_ERR("%s: extension section signature mismatch", hdev->name);
+ return -EINVAL;
+ }
+
+ /* Loop from the end of the firmware parsing instructions, until
+ * we find an instruction that identifies the "project ID" for the
+ * hardware supported by this firwmare file.
+ * Once we have that, we double-check that that project_id is suitable
+ * for the hardware we are working with.
+ */
+ while (fwptr >= fw->data + (sizeof(struct rtl_epatch_header) + 3)) {
+ opcode = *--fwptr;
+ length = *--fwptr;
+ data = *--fwptr;
+
+ BT_DBG("check op=%x len=%x data=%x", opcode, length, data);
+
+ if (opcode == 0xff) /* EOF */
+ break;
+
+ if (length == 0) {
+ BT_ERR("%s: found instruction with length 0",
+ hdev->name);
+ return -EINVAL;
+ }
+
+ if (opcode == 0 && length == 1) {
+ project_id = data;
+ break;
+ }
+
+ fwptr -= length;
+ }
+
+ if (project_id < 0) {
+ BT_ERR("%s: failed to find version instruction", hdev->name);
+ return -EINVAL;
+ }
+
+ if (project_id >= ARRAY_SIZE(project_id_to_lmp_subver)) {
+ BT_ERR("%s: unknown project id %d", hdev->name, project_id);
+ return -EINVAL;
+ }
+
+ if (lmp_subver != project_id_to_lmp_subver[project_id]) {
+ BT_ERR("%s: firmware is for %x but this is a %x", hdev->name,
+ project_id_to_lmp_subver[project_id], lmp_subver);
+ return -EINVAL;
+ }
+
+ epatch_info = (struct rtl_epatch_header *)fw->data;
+ if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) {
+ BT_ERR("%s: bad EPATCH signature", hdev->name);
+ return -EINVAL;
+ }
+
+ num_patches = le16_to_cpu(epatch_info->num_patches);
+ BT_DBG("fw_version=%x, num_patches=%d",
+ le32_to_cpu(epatch_info->fw_version), num_patches);
+
+ /* After the rtl_epatch_header there is a funky patch metadata section.
+ * Assuming 2 patches, the layout is:
+ * ChipID1 ChipID2 PatchLength1 PatchLength2 PatchOffset1 PatchOffset2
+ *
+ * Find the right patch for this chip.
+ */
+ min_size += 8 * num_patches;
+ if (fw->size < min_size)
+ return -EINVAL;
+
+ chip_id_base = fw->data + sizeof(struct rtl_epatch_header);
+ patch_length_base = chip_id_base + (sizeof(u16) * num_patches);
+ patch_offset_base = patch_length_base + (sizeof(u16) * num_patches);
+ for (i = 0; i < num_patches; i++) {
+ u16 chip_id = get_unaligned_le16(chip_id_base +
+ (i * sizeof(u16)));
+ if (chip_id == rom_version + 1) {
+ patch_length = get_unaligned_le16(patch_length_base +
+ (i * sizeof(u16)));
+ patch_offset = get_unaligned_le32(patch_offset_base +
+ (i * sizeof(u32)));
+ break;
+ }
+ }
+
+ if (!patch_offset) {
+ BT_ERR("%s: didn't find patch for chip id %d",
+ hdev->name, rom_version);
+ return -EINVAL;
+ }
+
+ BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i);
+ min_size = patch_offset + patch_length;
+ if (fw->size < min_size)
+ return -EINVAL;
+
+ /* Copy the firmware into a new buffer and write the version at
+ * the end.
+ */
+ len = patch_length;
+ buf = kmemdup(fw->data + patch_offset, patch_length, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy(buf + patch_length - 4, &epatch_info->fw_version, 4);
+
+ *_buf = buf;
+ return len;
+}
+
+static int rtl_download_firmware(struct hci_dev *hdev,
+ const unsigned char *data, int fw_len)
+{
+ struct rtl_download_cmd *dl_cmd;
+ int frag_num = fw_len / RTL_FRAG_LEN + 1;
+ int frag_len = RTL_FRAG_LEN;
+ int ret = 0;
+ int i;
+
+ dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL);
+ if (!dl_cmd)
+ return -ENOMEM;
+
+ for (i = 0; i < frag_num; i++) {
+ struct sk_buff *skb;
+
+ BT_DBG("download fw (%d/%d)", i, frag_num);
+
+ dl_cmd->index = i;
+ if (i == (frag_num - 1)) {
+ dl_cmd->index |= 0x80; /* data end */
+ frag_len = fw_len % RTL_FRAG_LEN;
+ }
+ memcpy(dl_cmd->data, data, frag_len);
+
+ /* Send download command */
+ skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: download fw command failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ ret = -PTR_ERR(skb);
+ goto out;
+ }
+
+ if (skb->len != sizeof(struct rtl_download_response)) {
+ BT_ERR("%s: download fw event length mismatch",
+ hdev->name);
+ kfree_skb(skb);
+ ret = -EIO;
+ goto out;
+ }
+
+ kfree_skb(skb);
+ data += RTL_FRAG_LEN;
+ }
+
+out:
+ kfree(dl_cmd);
+ return ret;
+}
+
+static int btrtl_setup_rtl8723a(struct hci_dev *hdev)
+{
+ const struct firmware *fw;
+ int ret;
+
+ BT_INFO("%s: rtl: loading rtl_bt/rtl8723a_fw.bin", hdev->name);
+ ret = request_firmware(&fw, "rtl_bt/rtl8723a_fw.bin", &hdev->dev);
+ if (ret < 0) {
+ BT_ERR("%s: Failed to load rtl_bt/rtl8723a_fw.bin", hdev->name);
+ return ret;
+ }
+
+ if (fw->size < 8) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Check that the firmware doesn't have the epatch signature
+ * (which is only for RTL8723B and newer).
+ */
+ if (!memcmp(fw->data, RTL_EPATCH_SIGNATURE, 8)) {
+ BT_ERR("%s: unexpected EPATCH signature!", hdev->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = rtl_download_firmware(hdev, fw->data, fw->size);
+
+out:
+ release_firmware(fw);
+ return ret;
+}
+
+static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
+ const char *fw_name)
+{
+ unsigned char *fw_data = NULL;
+ const struct firmware *fw;
+ int ret;
+
+ BT_INFO("%s: rtl: loading %s", hdev->name, fw_name);
+ ret = request_firmware(&fw, fw_name, &hdev->dev);
+ if (ret < 0) {
+ BT_ERR("%s: Failed to load %s", hdev->name, fw_name);
+ return ret;
+ }
+
+ ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data);
+ if (ret < 0)
+ goto out;
+
+ ret = rtl_download_firmware(hdev, fw_data, ret);
+ kfree(fw_data);
+ if (ret < 0)
+ goto out;
+
+out:
+ release_firmware(fw);
+ return ret;
+}
+
+static struct sk_buff *btrtl_read_local_version(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+
+ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return skb;
+ }
+
+ if (skb->len != sizeof(struct hci_rp_read_local_version)) {
+ BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
+ hdev->name);
+ kfree_skb(skb);
+ return ERR_PTR(-EIO);
+ }
+
+ return skb;
+}
+
+int btrtl_setup_realtek(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+ struct hci_rp_read_local_version *resp;
+ u16 lmp_subver;
+
+ skb = btrtl_read_local_version(hdev);
+ if (IS_ERR(skb))
+ return -PTR_ERR(skb);
+
+ resp = (struct hci_rp_read_local_version *)skb->data;
+ BT_INFO("%s: rtl: examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
+ "lmp_subver=%04x", hdev->name, resp->hci_ver, resp->hci_rev,
+ resp->lmp_ver, resp->lmp_subver);
+
+ lmp_subver = le16_to_cpu(resp->lmp_subver);
+ kfree_skb(skb);
+
+ /* Match a set of subver values that correspond to stock firmware,
+ * which is not compatible with standard btusb.
+ * If matched, upload an alternative firmware that does conform to
+ * standard btusb. Once that firmware is uploaded, the subver changes
+ * to a different value.
+ */
+ switch (lmp_subver) {
+ case RTL_ROM_LMP_8723A:
+ case RTL_ROM_LMP_3499:
+ return btrtl_setup_rtl8723a(hdev);
+ case RTL_ROM_LMP_8723B:
+ return btrtl_setup_rtl8723b(hdev, lmp_subver,
+ "rtl_bt/rtl8723b_fw.bin");
+ case RTL_ROM_LMP_8821A:
+ return btrtl_setup_rtl8723b(hdev, lmp_subver,
+ "rtl_bt/rtl8821a_fw.bin");
+ case RTL_ROM_LMP_8761A:
+ return btrtl_setup_rtl8723b(hdev, lmp_subver,
+ "rtl_bt/rtl8761a_fw.bin");
+ default:
+ BT_INFO("rtl: assuming no firmware upload needed.");
+ return 0;
+ }
+}
+EXPORT_SYMBOL_GPL(btrtl_setup_realtek);
+
+MODULE_AUTHOR("Daniel Drake <drake@endlessm.com>");
+MODULE_DESCRIPTION("Bluetooth support for Realtek devices ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/bluetooth/btrtl.h b/drivers/bluetooth/btrtl.h
new file mode 100644
index 000000000000..38ffe4890cd1
--- /dev/null
+++ b/drivers/bluetooth/btrtl.h
@@ -0,0 +1,52 @@
+/*
+ * Bluetooth support for Realtek devices
+ *
+ * Copyright (C) 2015 Endless Mobile, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the 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.
+ *
+ */
+
+#define RTL_FRAG_LEN 252
+
+struct rtl_download_cmd {
+ __u8 index;
+ __u8 data[RTL_FRAG_LEN];
+} __packed;
+
+struct rtl_download_response {
+ __u8 status;
+ __u8 index;
+} __packed;
+
+struct rtl_rom_version_evt {
+ __u8 status;
+ __u8 version;
+} __packed;
+
+struct rtl_epatch_header {
+ __u8 signature[8];
+ __le32 fw_version;
+ __le16 num_patches;
+} __packed;
+
+#if IS_ENABLED(CONFIG_BT_RTL)
+
+int btrtl_setup_realtek(struct hci_dev *hdev);
+
+#else
+
+static inline int btrtl_setup_realtek(struct hci_dev *hdev)
+{
+ return -EOPNOTSUPP;
+}
+
+#endif
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 3c10d4dfe9a7..b4cf8d9c9dac 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -31,13 +31,14 @@
#include "btintel.h"
#include "btbcm.h"
+#include "btrtl.h"
#define VERSION "0.8"
static bool disable_scofix;
static bool force_scofix;
-static bool reset = 1;
+static bool reset = true;
static struct usb_driver btusb_driver;
@@ -178,6 +179,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe076), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
@@ -186,6 +188,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x04ca, 0x3007), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04ca, 0x300d), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
@@ -211,6 +214,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@@ -265,7 +269,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0e5e, 0x6622), .driver_info = BTUSB_BROKEN_ISOC },
/* Roper Class 1 Bluetooth Dongle (Silicon Wave based) */
- { USB_DEVICE(0x1300, 0x0001), .driver_info = BTUSB_SWAVE },
+ { USB_DEVICE(0x1310, 0x0001), .driver_info = BTUSB_SWAVE },
/* Digianswer devices */
{ USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER },
@@ -330,6 +334,7 @@ static const struct usb_device_id blacklist_table[] = {
#define BTUSB_FIRMWARE_LOADED 7
#define BTUSB_FIRMWARE_FAILED 8
#define BTUSB_BOOTING 9
+#define BTUSB_RESET_RESUME 10
struct btusb_data {
struct hci_dev *hdev;
@@ -1298,28 +1303,6 @@ static void btusb_waker(struct work_struct *work)
usb_autopm_put_interface(data->intf);
}
-static struct sk_buff *btusb_read_local_version(struct hci_dev *hdev)
-{
- struct sk_buff *skb;
-
- skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
- HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
- hdev->name, PTR_ERR(skb));
- return skb;
- }
-
- if (skb->len != sizeof(struct hci_rp_read_local_version)) {
- BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
- hdev->name);
- kfree_skb(skb);
- return ERR_PTR(-EIO);
- }
-
- return skb;
-}
-
static int btusb_setup_bcm92035(struct hci_dev *hdev)
{
struct sk_buff *skb;
@@ -1340,408 +1323,40 @@ static int btusb_setup_csr(struct hci_dev *hdev)
{
struct hci_rp_read_local_version *rp;
struct sk_buff *skb;
- int ret;
BT_DBG("%s", hdev->name);
- skb = btusb_read_local_version(hdev);
- if (IS_ERR(skb))
- return -PTR_ERR(skb);
-
- rp = (struct hci_rp_read_local_version *)skb->data;
-
- if (!rp->status) {
- if (le16_to_cpu(rp->manufacturer) != 10) {
- /* Clear the reset quirk since this is not an actual
- * early Bluetooth 1.1 device from CSR.
- */
- clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
-
- /* These fake CSR controllers have all a broken
- * stored link key handling and so just disable it.
- */
- set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY,
- &hdev->quirks);
- }
- }
-
- ret = -bt_to_errno(rp->status);
-
- kfree_skb(skb);
-
- return ret;
-}
-
-#define RTL_FRAG_LEN 252
-
-struct rtl_download_cmd {
- __u8 index;
- __u8 data[RTL_FRAG_LEN];
-} __packed;
-
-struct rtl_download_response {
- __u8 status;
- __u8 index;
-} __packed;
-
-struct rtl_rom_version_evt {
- __u8 status;
- __u8 version;
-} __packed;
-
-struct rtl_epatch_header {
- __u8 signature[8];
- __le32 fw_version;
- __le16 num_patches;
-} __packed;
-
-#define RTL_EPATCH_SIGNATURE "Realtech"
-#define RTL_ROM_LMP_3499 0x3499
-#define RTL_ROM_LMP_8723A 0x1200
-#define RTL_ROM_LMP_8723B 0x8723
-#define RTL_ROM_LMP_8821A 0x8821
-#define RTL_ROM_LMP_8761A 0x8761
-
-static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version)
-{
- struct rtl_rom_version_evt *rom_version;
- struct sk_buff *skb;
- int ret;
-
- /* Read RTL ROM version command */
- skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT);
+ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
+ HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
- BT_ERR("%s: Read ROM version failed (%ld)",
- hdev->name, PTR_ERR(skb));
- return PTR_ERR(skb);
+ int err = PTR_ERR(skb);
+ BT_ERR("%s: CSR: Local version failed (%d)", hdev->name, err);
+ return err;
}
- if (skb->len != sizeof(*rom_version)) {
- BT_ERR("%s: RTL version event length mismatch", hdev->name);
+ if (skb->len != sizeof(struct hci_rp_read_local_version)) {
+ BT_ERR("%s: CSR: Local version length mismatch", hdev->name);
kfree_skb(skb);
return -EIO;
}
- rom_version = (struct rtl_rom_version_evt *)skb->data;
- BT_INFO("%s: rom_version status=%x version=%x",
- hdev->name, rom_version->status, rom_version->version);
-
- ret = rom_version->status;
- if (ret == 0)
- *version = rom_version->version;
-
- kfree_skb(skb);
- return ret;
-}
-
-static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
- const struct firmware *fw,
- unsigned char **_buf)
-{
- const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
- struct rtl_epatch_header *epatch_info;
- unsigned char *buf;
- int i, ret, len;
- size_t min_size;
- u8 opcode, length, data, rom_version = 0;
- int project_id = -1;
- const unsigned char *fwptr, *chip_id_base;
- const unsigned char *patch_length_base, *patch_offset_base;
- u32 patch_offset = 0;
- u16 patch_length, num_patches;
- const u16 project_id_to_lmp_subver[] = {
- RTL_ROM_LMP_8723A,
- RTL_ROM_LMP_8723B,
- RTL_ROM_LMP_8821A,
- RTL_ROM_LMP_8761A
- };
-
- ret = rtl_read_rom_version(hdev, &rom_version);
- if (ret)
- return -bt_to_errno(ret);
-
- min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
- if (fw->size < min_size)
- return -EINVAL;
-
- fwptr = fw->data + fw->size - sizeof(extension_sig);
- if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) {
- BT_ERR("%s: extension section signature mismatch", hdev->name);
- return -EINVAL;
- }
-
- /* Loop from the end of the firmware parsing instructions, until
- * we find an instruction that identifies the "project ID" for the
- * hardware supported by this firwmare file.
- * Once we have that, we double-check that that project_id is suitable
- * for the hardware we are working with.
- */
- while (fwptr >= fw->data + (sizeof(struct rtl_epatch_header) + 3)) {
- opcode = *--fwptr;
- length = *--fwptr;
- data = *--fwptr;
-
- BT_DBG("check op=%x len=%x data=%x", opcode, length, data);
-
- if (opcode == 0xff) /* EOF */
- break;
-
- if (length == 0) {
- BT_ERR("%s: found instruction with length 0",
- hdev->name);
- return -EINVAL;
- }
-
- if (opcode == 0 && length == 1) {
- project_id = data;
- break;
- }
-
- fwptr -= length;
- }
-
- if (project_id < 0) {
- BT_ERR("%s: failed to find version instruction", hdev->name);
- return -EINVAL;
- }
-
- if (project_id >= ARRAY_SIZE(project_id_to_lmp_subver)) {
- BT_ERR("%s: unknown project id %d", hdev->name, project_id);
- return -EINVAL;
- }
-
- if (lmp_subver != project_id_to_lmp_subver[project_id]) {
- BT_ERR("%s: firmware is for %x but this is a %x", hdev->name,
- project_id_to_lmp_subver[project_id], lmp_subver);
- return -EINVAL;
- }
-
- epatch_info = (struct rtl_epatch_header *)fw->data;
- if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) {
- BT_ERR("%s: bad EPATCH signature", hdev->name);
- return -EINVAL;
- }
-
- num_patches = le16_to_cpu(epatch_info->num_patches);
- BT_DBG("fw_version=%x, num_patches=%d",
- le32_to_cpu(epatch_info->fw_version), num_patches);
-
- /* After the rtl_epatch_header there is a funky patch metadata section.
- * Assuming 2 patches, the layout is:
- * ChipID1 ChipID2 PatchLength1 PatchLength2 PatchOffset1 PatchOffset2
- *
- * Find the right patch for this chip.
- */
- min_size += 8 * num_patches;
- if (fw->size < min_size)
- return -EINVAL;
-
- chip_id_base = fw->data + sizeof(struct rtl_epatch_header);
- patch_length_base = chip_id_base + (sizeof(u16) * num_patches);
- patch_offset_base = patch_length_base + (sizeof(u16) * num_patches);
- for (i = 0; i < num_patches; i++) {
- u16 chip_id = get_unaligned_le16(chip_id_base +
- (i * sizeof(u16)));
- if (chip_id == rom_version + 1) {
- patch_length = get_unaligned_le16(patch_length_base +
- (i * sizeof(u16)));
- patch_offset = get_unaligned_le32(patch_offset_base +
- (i * sizeof(u32)));
- break;
- }
- }
-
- if (!patch_offset) {
- BT_ERR("%s: didn't find patch for chip id %d",
- hdev->name, rom_version);
- return -EINVAL;
- }
-
- BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i);
- min_size = patch_offset + patch_length;
- if (fw->size < min_size)
- return -EINVAL;
-
- /* Copy the firmware into a new buffer and write the version at
- * the end.
- */
- len = patch_length;
- buf = kmemdup(fw->data + patch_offset, patch_length, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- memcpy(buf + patch_length - 4, &epatch_info->fw_version, 4);
-
- *_buf = buf;
- return len;
-}
-
-static int rtl_download_firmware(struct hci_dev *hdev,
- const unsigned char *data, int fw_len)
-{
- struct rtl_download_cmd *dl_cmd;
- int frag_num = fw_len / RTL_FRAG_LEN + 1;
- int frag_len = RTL_FRAG_LEN;
- int ret = 0;
- int i;
-
- dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL);
- if (!dl_cmd)
- return -ENOMEM;
-
- for (i = 0; i < frag_num; i++) {
- struct rtl_download_response *dl_resp;
- struct sk_buff *skb;
-
- BT_DBG("download fw (%d/%d)", i, frag_num);
-
- dl_cmd->index = i;
- if (i == (frag_num - 1)) {
- dl_cmd->index |= 0x80; /* data end */
- frag_len = fw_len % RTL_FRAG_LEN;
- }
- memcpy(dl_cmd->data, data, frag_len);
-
- /* Send download command */
- skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd,
- HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- BT_ERR("%s: download fw command failed (%ld)",
- hdev->name, PTR_ERR(skb));
- ret = -PTR_ERR(skb);
- goto out;
- }
-
- if (skb->len != sizeof(*dl_resp)) {
- BT_ERR("%s: download fw event length mismatch",
- hdev->name);
- kfree_skb(skb);
- ret = -EIO;
- goto out;
- }
-
- dl_resp = (struct rtl_download_response *)skb->data;
- if (dl_resp->status != 0) {
- kfree_skb(skb);
- ret = bt_to_errno(dl_resp->status);
- goto out;
- }
-
- kfree_skb(skb);
- data += RTL_FRAG_LEN;
- }
-
-out:
- kfree(dl_cmd);
- return ret;
-}
-
-static int btusb_setup_rtl8723a(struct hci_dev *hdev)
-{
- struct btusb_data *data = dev_get_drvdata(&hdev->dev);
- struct usb_device *udev = interface_to_usbdev(data->intf);
- const struct firmware *fw;
- int ret;
-
- BT_INFO("%s: rtl: loading rtl_bt/rtl8723a_fw.bin", hdev->name);
- ret = request_firmware(&fw, "rtl_bt/rtl8723a_fw.bin", &udev->dev);
- if (ret < 0) {
- BT_ERR("%s: Failed to load rtl_bt/rtl8723a_fw.bin", hdev->name);
- return ret;
- }
-
- if (fw->size < 8) {
- ret = -EINVAL;
- goto out;
- }
-
- /* Check that the firmware doesn't have the epatch signature
- * (which is only for RTL8723B and newer).
- */
- if (!memcmp(fw->data, RTL_EPATCH_SIGNATURE, 8)) {
- BT_ERR("%s: unexpected EPATCH signature!", hdev->name);
- ret = -EINVAL;
- goto out;
- }
-
- ret = rtl_download_firmware(hdev, fw->data, fw->size);
-
-out:
- release_firmware(fw);
- return ret;
-}
+ rp = (struct hci_rp_read_local_version *)skb->data;
-static int btusb_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
- const char *fw_name)
-{
- struct btusb_data *data = dev_get_drvdata(&hdev->dev);
- struct usb_device *udev = interface_to_usbdev(data->intf);
- unsigned char *fw_data = NULL;
- const struct firmware *fw;
- int ret;
+ if (le16_to_cpu(rp->manufacturer) != 10) {
+ /* Clear the reset quirk since this is not an actual
+ * early Bluetooth 1.1 device from CSR.
+ */
+ clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
- BT_INFO("%s: rtl: loading %s", hdev->name, fw_name);
- ret = request_firmware(&fw, fw_name, &udev->dev);
- if (ret < 0) {
- BT_ERR("%s: Failed to load %s", hdev->name, fw_name);
- return ret;
+ /* These fake CSR controllers have all a broken
+ * stored link key handling and so just disable it.
+ */
+ set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
}
- ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data);
- if (ret < 0)
- goto out;
-
- ret = rtl_download_firmware(hdev, fw_data, ret);
- kfree(fw_data);
- if (ret < 0)
- goto out;
-
-out:
- release_firmware(fw);
- return ret;
-}
-
-static int btusb_setup_realtek(struct hci_dev *hdev)
-{
- struct sk_buff *skb;
- struct hci_rp_read_local_version *resp;
- u16 lmp_subver;
-
- skb = btusb_read_local_version(hdev);
- if (IS_ERR(skb))
- return -PTR_ERR(skb);
-
- resp = (struct hci_rp_read_local_version *)skb->data;
- BT_INFO("%s: rtl: examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
- "lmp_subver=%04x", hdev->name, resp->hci_ver, resp->hci_rev,
- resp->lmp_ver, resp->lmp_subver);
-
- lmp_subver = le16_to_cpu(resp->lmp_subver);
kfree_skb(skb);
- /* Match a set of subver values that correspond to stock firmware,
- * which is not compatible with standard btusb.
- * If matched, upload an alternative firmware that does conform to
- * standard btusb. Once that firmware is uploaded, the subver changes
- * to a different value.
- */
- switch (lmp_subver) {
- case RTL_ROM_LMP_8723A:
- case RTL_ROM_LMP_3499:
- return btusb_setup_rtl8723a(hdev);
- case RTL_ROM_LMP_8723B:
- return btusb_setup_rtl8723b(hdev, lmp_subver,
- "rtl_bt/rtl8723b_fw.bin");
- case RTL_ROM_LMP_8821A:
- return btusb_setup_rtl8723b(hdev, lmp_subver,
- "rtl_bt/rtl8821a_fw.bin");
- case RTL_ROM_LMP_8761A:
- return btusb_setup_rtl8723b(hdev, lmp_subver,
- "rtl_bt/rtl8761a_fw.bin");
- default:
- BT_INFO("rtl: assuming no firmware upload needed.");
- return 0;
- }
+ return 0;
}
static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev,
@@ -1951,12 +1566,6 @@ static int btusb_setup_intel(struct hci_dev *hdev)
}
ver = (struct intel_version *)skb->data;
- if (ver->status) {
- BT_ERR("%s Intel fw version event failed (%02x)", hdev->name,
- ver->status);
- kfree_skb(skb);
- return -bt_to_errno(ver->status);
- }
BT_INFO("%s: read Intel version: %02x%02x%02x%02x%02x%02x%02x%02x%02x",
hdev->name, ver->hw_platform, ver->hw_variant,
@@ -1990,6 +1599,8 @@ static int btusb_setup_intel(struct hci_dev *hdev)
}
fw_ptr = fw->data;
+ kfree_skb(skb);
+
/* This Intel specific command enables the manufacturer mode of the
* controller.
*
@@ -2004,15 +1615,6 @@ static int btusb_setup_intel(struct hci_dev *hdev)
return PTR_ERR(skb);
}
- if (skb->data[0]) {
- u8 evt_status = skb->data[0];
-
- BT_ERR("%s enable Intel manufacturer mode event failed (%02x)",
- hdev->name, evt_status);
- kfree_skb(skb);
- release_firmware(fw);
- return -bt_to_errno(evt_status);
- }
kfree_skb(skb);
disable_patch = 1;
@@ -2331,6 +1933,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
struct intel_boot_params *params;
const struct firmware *fw;
const u8 *fw_ptr;
+ u32 frag_len;
char fwname[64];
ktime_t calltime, delta, rettime;
unsigned long long duration;
@@ -2358,13 +1961,6 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
}
ver = (struct intel_version *)skb->data;
- if (ver->status) {
- BT_ERR("%s: Intel version command failure (%02x)",
- hdev->name, ver->status);
- err = -bt_to_errno(ver->status);
- kfree_skb(skb);
- return err;
- }
/* The hardware platform number has a fixed value of 0x37 and
* for now only accept this single value.
@@ -2439,13 +2035,6 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
}
params = (struct intel_boot_params *)skb->data;
- if (params->status) {
- BT_ERR("%s: Intel boot parameters command failure (%02x)",
- hdev->name, params->status);
- err = -bt_to_errno(params->status);
- kfree_skb(skb);
- return err;
- }
BT_INFO("%s: Device revision is %u", hdev->name,
le16_to_cpu(params->dev_revid));
@@ -2495,6 +2084,12 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
BT_INFO("%s: Found device firmware: %s", hdev->name, fwname);
+ /* Save the DDC file name for later use to apply once the firmware
+ * downloading is done.
+ */
+ snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.ddc",
+ le16_to_cpu(params->dev_revid));
+
kfree_skb(skb);
if (fw->size < 644) {
@@ -2537,24 +2132,33 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
}
fw_ptr = fw->data + 644;
+ frag_len = 0;
while (fw_ptr - fw->data < fw->size) {
- struct hci_command_hdr *cmd = (void *)fw_ptr;
- u8 cmd_len;
+ struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
- cmd_len = sizeof(*cmd) + cmd->plen;
+ frag_len += sizeof(*cmd) + cmd->plen;
- /* Send each command from the firmware data buffer as
- * a single Data fragment.
+ /* The paramter length of the secure send command requires
+ * a 4 byte alignment. It happens so that the firmware file
+ * contains proper Intel_NOP commands to align the fragments
+ * as needed.
+ *
+ * Send set of commands with 4 byte alignment from the
+ * firmware data buffer as a single Data fragement.
*/
- err = btusb_intel_secure_send(hdev, 0x01, cmd_len, fw_ptr);
- if (err < 0) {
- BT_ERR("%s: Failed to send firmware data (%d)",
- hdev->name, err);
- goto done;
- }
+ if (!(frag_len % 4)) {
+ err = btusb_intel_secure_send(hdev, 0x01, frag_len,
+ fw_ptr);
+ if (err < 0) {
+ BT_ERR("%s: Failed to send firmware data (%d)",
+ hdev->name, err);
+ goto done;
+ }
- fw_ptr += cmd_len;
+ fw_ptr += frag_len;
+ frag_len = 0;
+ }
}
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
@@ -2647,6 +2251,43 @@ done:
clear_bit(BTUSB_BOOTLOADER, &data->flags);
+ /* Once the device is running in operational mode, it needs to apply
+ * the device configuration (DDC) parameters.
+ *
+ * The device can work without DDC parameters, so even if it fails
+ * to load the file, no need to fail the setup.
+ */
+ err = request_firmware_direct(&fw, fwname, &hdev->dev);
+ if (err < 0)
+ return 0;
+
+ BT_INFO("%s: Found Intel DDC parameters: %s", hdev->name, fwname);
+
+ fw_ptr = fw->data;
+
+ /* DDC file contains one or more DDC structure which has
+ * Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2).
+ */
+ while (fw->size > fw_ptr - fw->data) {
+ u8 cmd_plen = fw_ptr[0] + sizeof(u8);
+
+ skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: Failed to send Intel_Write_DDC (%ld)",
+ hdev->name, PTR_ERR(skb));
+ release_firmware(fw);
+ return PTR_ERR(skb);
+ }
+
+ fw_ptr += cmd_plen;
+ kfree_skb(skb);
+ }
+
+ release_firmware(fw);
+
+ BT_INFO("%s: Applying Intel DDC parameters completed", hdev->name);
+
return 0;
}
@@ -2678,13 +2319,6 @@ static void btusb_hw_error_intel(struct hci_dev *hdev, u8 code)
return;
}
- if (skb->data[0] != 0x00) {
- BT_ERR("%s: Exception info command failure (%02x)",
- hdev->name, skb->data[0]);
- kfree_skb(skb);
- return;
- }
-
BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1));
kfree_skb(skb);
@@ -2792,6 +2426,7 @@ struct qca_device_info {
static const struct qca_device_info qca_devices_table[] = {
{ 0x00000100, 20, 4, 10 }, /* Rome 1.0 */
{ 0x00000101, 20, 4, 10 }, /* Rome 1.1 */
+ { 0x00000200, 28, 4, 18 }, /* Rome 2.0 */
{ 0x00000201, 28, 4, 18 }, /* Rome 2.1 */
{ 0x00000300, 28, 4, 18 }, /* Rome 3.0 */
{ 0x00000302, 28, 4, 18 }, /* Rome 3.2 */
@@ -3175,8 +2810,17 @@ static int btusb_probe(struct usb_interface *intf,
hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
}
- if (id->driver_info & BTUSB_REALTEK)
- hdev->setup = btusb_setup_realtek;
+#ifdef CONFIG_BT_HCIBTUSB_RTL
+ if (id->driver_info & BTUSB_REALTEK) {
+ hdev->setup = btrtl_setup_realtek;
+
+ /* Realtek devices lose their updated firmware over suspend,
+ * but the USB hub doesn't notice any status change.
+ * Explicitly request a device reset on resume.
+ */
+ set_bit(BTUSB_RESET_RESUME, &data->flags);
+ }
+#endif
if (id->driver_info & BTUSB_AMP) {
/* AMP controllers do not support SCO packets */
@@ -3308,6 +2952,14 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
btusb_stop_traffic(data);
usb_kill_anchored_urbs(&data->tx_anchor);
+ /* Optionally request a device reset on resume, but only when
+ * wakeups are disabled. If wakeups are enabled we assume the
+ * device will stay powered up throughout suspend.
+ */
+ if (test_bit(BTUSB_RESET_RESUME, &data->flags) &&
+ !device_may_wakeup(&data->udev->dev))
+ data->udev->reset_resume = 1;
+
return 0;
}
diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c
index 55c135b7757a..7a722df97343 100644
--- a/drivers/bluetooth/btwilink.c
+++ b/drivers/bluetooth/btwilink.c
@@ -22,7 +22,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#define DEBUG
+
#include <linux/platform_device.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index ec8fa0e0f036..6da5e4ca13ea 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -192,6 +192,7 @@ static int ath_recv(struct hci_uart *hu, const void *data, int count)
if (IS_ERR(ath->rx_skb)) {
int err = PTR_ERR(ath->rx_skb);
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
+ ath->rx_skb = NULL;
return err;
}
diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index 1ec0b4a5ffa6..23523e140a9a 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -24,6 +24,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/skbuff.h>
+#include <linux/firmware.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -36,6 +37,55 @@ struct bcm_data {
struct sk_buff_head txq;
};
+static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed)
+{
+ struct hci_dev *hdev = hu->hdev;
+ struct sk_buff *skb;
+ struct bcm_update_uart_baud_rate param;
+
+ if (speed > 3000000) {
+ struct bcm_write_uart_clock_setting clock;
+
+ clock.type = BCM_UART_CLOCK_48MHZ;
+
+ BT_DBG("%s: Set Controller clock (%d)", hdev->name, clock.type);
+
+ /* This Broadcom specific command changes the UART's controller
+ * clock for baud rate > 3000000.
+ */
+ skb = __hci_cmd_sync(hdev, 0xfc45, 1, &clock, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ int err = PTR_ERR(skb);
+ BT_ERR("%s: BCM: failed to write clock command (%d)",
+ hdev->name, err);
+ return err;
+ }
+
+ kfree_skb(skb);
+ }
+
+ BT_DBG("%s: Set Controller UART speed to %d bit/s", hdev->name, speed);
+
+ param.zero = cpu_to_le16(0);
+ param.baud_rate = cpu_to_le32(speed);
+
+ /* This Broadcom specific command changes the UART's controller baud
+ * rate.
+ */
+ skb = __hci_cmd_sync(hdev, 0xfc18, sizeof(param), &param,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ int err = PTR_ERR(skb);
+ BT_ERR("%s: BCM: failed to write update baudrate command (%d)",
+ hdev->name, err);
+ return err;
+ }
+
+ kfree_skb(skb);
+
+ return 0;
+}
+
static int bcm_open(struct hci_uart *hu)
{
struct bcm_data *bcm;
@@ -79,11 +129,62 @@ static int bcm_flush(struct hci_uart *hu)
static int bcm_setup(struct hci_uart *hu)
{
+ char fw_name[64];
+ const struct firmware *fw;
+ unsigned int speed;
+ int err;
+
BT_DBG("hu %p", hu);
hu->hdev->set_bdaddr = btbcm_set_bdaddr;
- return btbcm_setup_patchram(hu->hdev);
+ err = btbcm_initialize(hu->hdev, fw_name, sizeof(fw_name));
+ if (err)
+ return err;
+
+ err = request_firmware(&fw, fw_name, &hu->hdev->dev);
+ if (err < 0) {
+ BT_INFO("%s: BCM: Patch %s not found", hu->hdev->name, fw_name);
+ return 0;
+ }
+
+ err = btbcm_patchram(hu->hdev, fw);
+ if (err) {
+ BT_INFO("%s: BCM: Patch failed (%d)", hu->hdev->name, err);
+ goto finalize;
+ }
+
+ /* Init speed if any */
+ if (hu->init_speed)
+ speed = hu->init_speed;
+ else if (hu->proto->init_speed)
+ speed = hu->proto->init_speed;
+ else
+ speed = 0;
+
+ if (speed)
+ hci_uart_set_baudrate(hu, speed);
+
+ /* Operational speed if any */
+ if (hu->oper_speed)
+ speed = hu->oper_speed;
+ else if (hu->proto->oper_speed)
+ speed = hu->proto->oper_speed;
+ else
+ speed = 0;
+
+ if (speed) {
+ err = bcm_set_baudrate(hu, speed);
+ if (!err)
+ hci_uart_set_baudrate(hu, speed);
+ }
+
+finalize:
+ release_firmware(fw);
+
+ err = btbcm_finalize(hu->hdev);
+
+ return err;
}
static const struct h4_recv_pkt bcm_recv_pkts[] = {
@@ -104,6 +205,7 @@ static int bcm_recv(struct hci_uart *hu, const void *data, int count)
if (IS_ERR(bcm->rx_skb)) {
int err = PTR_ERR(bcm->rx_skb);
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
+ bcm->rx_skb = NULL;
return err;
}
@@ -133,10 +235,13 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
static const struct hci_uart_proto bcm_proto = {
.id = HCI_UART_BCM,
.name = "BCM",
+ .init_speed = 115200,
+ .oper_speed = 4000000,
.open = bcm_open,
.close = bcm_close,
.flush = bcm_flush,
.setup = bcm_setup,
+ .set_baudrate = bcm_set_baudrate,
.recv = bcm_recv,
.enqueue = bcm_enqueue,
.dequeue = bcm_dequeue,
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index dc8e3d4356a0..d0b615a932d1 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -47,8 +47,8 @@
#include "hci_uart.h"
-static bool txcrc = 1;
-static bool hciextn = 1;
+static bool txcrc = true;
+static bool hciextn = true;
#define BCSP_TXWINSIZE 4
@@ -436,7 +436,7 @@ static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char
break;
default:
memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1);
- if ((bcsp->rx_skb-> data[0] & 0x40) != 0 &&
+ if ((bcsp->rx_skb->data[0] & 0x40) != 0 &&
bcsp->rx_state != BCSP_W4_CRC)
bcsp_crc_update(&bcsp->message_crc, byte);
bcsp->rx_count--;
@@ -447,24 +447,24 @@ static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char
switch (byte) {
case 0xdc:
memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1);
- if ((bcsp->rx_skb-> data[0] & 0x40) != 0 &&
+ if ((bcsp->rx_skb->data[0] & 0x40) != 0 &&
bcsp->rx_state != BCSP_W4_CRC)
- bcsp_crc_update(&bcsp-> message_crc, 0xc0);
+ bcsp_crc_update(&bcsp->message_crc, 0xc0);
bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
bcsp->rx_count--;
break;
case 0xdd:
memcpy(skb_put(bcsp->rx_skb, 1), &db, 1);
- if ((bcsp->rx_skb-> data[0] & 0x40) != 0 &&
+ if ((bcsp->rx_skb->data[0] & 0x40) != 0 &&
bcsp->rx_state != BCSP_W4_CRC)
- bcsp_crc_update(&bcsp-> message_crc, 0xdb);
+ bcsp_crc_update(&bcsp->message_crc, 0xdb);
bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
bcsp->rx_count--;
break;
default:
- BT_ERR ("Invalid byte %02x after esc byte", byte);
+ BT_ERR("Invalid byte %02x after esc byte", byte);
kfree_skb(bcsp->rx_skb);
bcsp->rx_skb = NULL;
bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
@@ -527,7 +527,7 @@ static void bcsp_complete_rx_pkt(struct hci_uart *hu)
hci_recv_frame(hu->hdev, bcsp->rx_skb);
} else {
- BT_ERR ("Packet for unknown channel (%u %s)",
+ BT_ERR("Packet for unknown channel (%u %s)",
bcsp->rx_skb->data[1] & 0x0f,
bcsp->rx_skb->data[0] & 0x80 ?
"reliable" : "unreliable");
@@ -587,7 +587,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
}
if (bcsp->rx_skb->data[0] & 0x80 /* reliable pkt */
&& (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) {
- BT_ERR ("Out-of-order packet arrived, got %u expected %u",
+ BT_ERR("Out-of-order packet arrived, got %u expected %u",
bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack);
kfree_skb(bcsp->rx_skb);
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index f7190f01e135..57faddc53645 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -133,6 +133,7 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count)
if (IS_ERR(h4->rx_skb)) {
int err = PTR_ERR(h4->rx_skb);
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
+ h4->rx_skb = NULL;
return err;
}
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 5c9a73f02664..177dd69fdd95 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -40,6 +40,7 @@
#include <linux/signal.h>
#include <linux/ioctl.h>
#include <linux/skbuff.h>
+#include <linux/firmware.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -265,11 +266,133 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
return 0;
}
+/* Flow control or un-flow control the device */
+void hci_uart_set_flow_control(struct hci_uart *hu, bool enable)
+{
+ struct tty_struct *tty = hu->tty;
+ struct ktermios ktermios;
+ int status;
+ unsigned int set = 0;
+ unsigned int clear = 0;
+
+ if (enable) {
+ /* Disable hardware flow control */
+ ktermios = tty->termios;
+ ktermios.c_cflag &= ~CRTSCTS;
+ status = tty_set_termios(tty, &ktermios);
+ BT_DBG("Disabling hardware flow control: %s",
+ status ? "failed" : "success");
+
+ /* Clear RTS to prevent the device from sending */
+ /* Most UARTs need OUT2 to enable interrupts */
+ status = tty->driver->ops->tiocmget(tty);
+ BT_DBG("Current tiocm 0x%x", status);
+
+ set &= ~(TIOCM_OUT2 | TIOCM_RTS);
+ clear = ~set;
+ set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
+ TIOCM_OUT2 | TIOCM_LOOP;
+ clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
+ TIOCM_OUT2 | TIOCM_LOOP;
+ status = tty->driver->ops->tiocmset(tty, set, clear);
+ BT_DBG("Clearing RTS: %s", status ? "failed" : "success");
+ } else {
+ /* Set RTS to allow the device to send again */
+ status = tty->driver->ops->tiocmget(tty);
+ BT_DBG("Current tiocm 0x%x", status);
+
+ set |= (TIOCM_OUT2 | TIOCM_RTS);
+ clear = ~set;
+ set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
+ TIOCM_OUT2 | TIOCM_LOOP;
+ clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
+ TIOCM_OUT2 | TIOCM_LOOP;
+ status = tty->driver->ops->tiocmset(tty, set, clear);
+ BT_DBG("Setting RTS: %s", status ? "failed" : "success");
+
+ /* Re-enable hardware flow control */
+ ktermios = tty->termios;
+ ktermios.c_cflag |= CRTSCTS;
+ status = tty_set_termios(tty, &ktermios);
+ BT_DBG("Enabling hardware flow control: %s",
+ status ? "failed" : "success");
+ }
+}
+
+void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed,
+ unsigned int oper_speed)
+{
+ hu->init_speed = init_speed;
+ hu->oper_speed = oper_speed;
+}
+
+void hci_uart_init_tty(struct hci_uart *hu)
+{
+ struct tty_struct *tty = hu->tty;
+ struct ktermios ktermios;
+
+ /* Bring the UART into a known 8 bits no parity hw fc state */
+ ktermios = tty->termios;
+ ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP |
+ INLCR | IGNCR | ICRNL | IXON);
+ ktermios.c_oflag &= ~OPOST;
+ ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+ ktermios.c_cflag &= ~(CSIZE | PARENB);
+ ktermios.c_cflag |= CS8;
+ ktermios.c_cflag |= CRTSCTS;
+
+ /* tty_set_termios() return not checked as it is always 0 */
+ tty_set_termios(tty, &ktermios);
+}
+
+void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed)
+{
+ struct tty_struct *tty = hu->tty;
+ struct ktermios ktermios;
+
+ ktermios = tty->termios;
+ ktermios.c_cflag &= ~CBAUD;
+ tty_termios_encode_baud_rate(&ktermios, speed, speed);
+
+ /* tty_set_termios() return not checked as it is always 0 */
+ tty_set_termios(tty, &ktermios);
+
+ BT_DBG("%s: New tty speeds: %d/%d", hu->hdev->name,
+ tty->termios.c_ispeed, tty->termios.c_ospeed);
+}
+
static int hci_uart_setup(struct hci_dev *hdev)
{
struct hci_uart *hu = hci_get_drvdata(hdev);
struct hci_rp_read_local_version *ver;
struct sk_buff *skb;
+ unsigned int speed;
+ int err;
+
+ /* Init speed if any */
+ if (hu->init_speed)
+ speed = hu->init_speed;
+ else if (hu->proto->init_speed)
+ speed = hu->proto->init_speed;
+ else
+ speed = 0;
+
+ if (speed)
+ hci_uart_set_baudrate(hu, speed);
+
+ /* Operational speed if any */
+ if (hu->oper_speed)
+ speed = hu->oper_speed;
+ else if (hu->proto->oper_speed)
+ speed = hu->proto->oper_speed;
+ else
+ speed = 0;
+
+ if (hu->proto->set_baudrate && speed) {
+ err = hu->proto->set_baudrate(hu, speed);
+ if (!err)
+ hci_uart_set_baudrate(hu, speed);
+ }
if (hu->proto->setup)
return hu->proto->setup(hu);
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 72120a5ba13c..ce9c670956f5 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -58,10 +58,13 @@ struct hci_uart;
struct hci_uart_proto {
unsigned int id;
const char *name;
+ unsigned int init_speed;
+ unsigned int oper_speed;
int (*open)(struct hci_uart *hu);
int (*close)(struct hci_uart *hu);
int (*flush)(struct hci_uart *hu);
int (*setup)(struct hci_uart *hu);
+ int (*set_baudrate)(struct hci_uart *hu, unsigned int speed);
int (*recv)(struct hci_uart *hu, const void *data, int len);
int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
struct sk_buff *(*dequeue)(struct hci_uart *hu);
@@ -82,6 +85,9 @@ struct hci_uart {
struct sk_buff *tx_skb;
unsigned long tx_state;
spinlock_t rx_lock;
+
+ unsigned int init_speed;
+ unsigned int oper_speed;
};
/* HCI_UART proto flag bits */
@@ -96,6 +102,11 @@ int hci_uart_register_proto(const struct hci_uart_proto *p);
int hci_uart_unregister_proto(const struct hci_uart_proto *p);
int hci_uart_tx_wakeup(struct hci_uart *hu);
int hci_uart_init_ready(struct hci_uart *hu);
+void hci_uart_init_tty(struct hci_uart *hu);
+void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed);
+void hci_uart_set_flow_control(struct hci_uart *hu, bool enable);
+void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed,
+ unsigned int oper_speed);
#ifdef CONFIG_BT_HCIUART_H4
int h4_init(void);
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index 6653473f2757..78653db2ef2b 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -366,7 +366,7 @@ static const struct file_operations vhci_fops = {
.llseek = no_llseek,
};
-static struct miscdevice vhci_miscdev= {
+static struct miscdevice vhci_miscdev = {
.name = "vhci",
.fops = &vhci_fops,
.minor = VHCI_MINOR,
diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c
index a50936a17376..563969942a1d 100644
--- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/drivers/clk/qcom/gcc-ipq806x.c
@@ -140,12 +140,47 @@ static struct clk_regmap pll14_vote = {
},
};
+#define NSS_PLL_RATE(f, _l, _m, _n, i) \
+ { \
+ .freq = f, \
+ .l = _l, \
+ .m = _m, \
+ .n = _n, \
+ .ibits = i, \
+ }
+
+static struct pll_freq_tbl pll18_freq_tbl[] = {
+ NSS_PLL_RATE(550000000, 44, 0, 1, 0x01495625),
+ NSS_PLL_RATE(733000000, 58, 16, 25, 0x014b5625),
+};
+
+static struct clk_pll pll18 = {
+ .l_reg = 0x31a4,
+ .m_reg = 0x31a8,
+ .n_reg = 0x31ac,
+ .config_reg = 0x31b4,
+ .mode_reg = 0x31a0,
+ .status_reg = 0x31b8,
+ .status_bit = 16,
+ .post_div_shift = 16,
+ .post_div_width = 1,
+ .freq_tbl = pll18_freq_tbl,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pll18",
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
enum {
P_PXO,
P_PLL8,
P_PLL3,
P_PLL0,
P_CXO,
+ P_PLL14,
+ P_PLL18,
};
static const struct parent_map gcc_pxo_pll8_map[] = {
@@ -197,6 +232,22 @@ static const char *gcc_pxo_pll8_pll0_map[] = {
"pll0_vote",
};
+static const struct parent_map gcc_pxo_pll8_pll14_pll18_pll0_map[] = {
+ { P_PXO, 0 },
+ { P_PLL8, 4 },
+ { P_PLL0, 2 },
+ { P_PLL14, 5 },
+ { P_PLL18, 1 }
+};
+
+static const char *gcc_pxo_pll8_pll14_pll18_pll0[] = {
+ "pxo",
+ "pll8_vote",
+ "pll0_vote",
+ "pll14",
+ "pll18",
+};
+
static struct freq_tbl clk_tbl_gsbi_uart[] = {
{ 1843200, P_PLL8, 2, 6, 625 },
{ 3686400, P_PLL8, 2, 12, 625 },
@@ -2202,6 +2253,472 @@ static struct clk_branch ebi2_aon_clk = {
},
};
+static const struct freq_tbl clk_tbl_gmac[] = {
+ { 133000000, P_PLL0, 1, 50, 301 },
+ { 266000000, P_PLL0, 1, 127, 382 },
+ { }
+};
+
+static struct clk_dyn_rcg gmac_core1_src = {
+ .ns_reg[0] = 0x3cac,
+ .ns_reg[1] = 0x3cb0,
+ .md_reg[0] = 0x3ca4,
+ .md_reg[1] = 0x3ca8,
+ .bank_reg = 0x3ca0,
+ .mn[0] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .mn[1] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_gmac,
+ .clkr = {
+ .enable_reg = 0x3ca0,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core1_src",
+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
+ .num_parents = 5,
+ .ops = &clk_dyn_rcg_ops,
+ },
+ },
+};
+
+static struct clk_branch gmac_core1_clk = {
+ .halt_reg = 0x3c20,
+ .halt_bit = 4,
+ .hwcg_reg = 0x3cb4,
+ .hwcg_bit = 6,
+ .clkr = {
+ .enable_reg = 0x3cb4,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core1_clk",
+ .parent_names = (const char *[]){
+ "gmac_core1_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_dyn_rcg gmac_core2_src = {
+ .ns_reg[0] = 0x3ccc,
+ .ns_reg[1] = 0x3cd0,
+ .md_reg[0] = 0x3cc4,
+ .md_reg[1] = 0x3cc8,
+ .bank_reg = 0x3ca0,
+ .mn[0] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .mn[1] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_gmac,
+ .clkr = {
+ .enable_reg = 0x3cc0,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core2_src",
+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
+ .num_parents = 5,
+ .ops = &clk_dyn_rcg_ops,
+ },
+ },
+};
+
+static struct clk_branch gmac_core2_clk = {
+ .halt_reg = 0x3c20,
+ .halt_bit = 5,
+ .hwcg_reg = 0x3cd4,
+ .hwcg_bit = 6,
+ .clkr = {
+ .enable_reg = 0x3cd4,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core2_clk",
+ .parent_names = (const char *[]){
+ "gmac_core2_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_dyn_rcg gmac_core3_src = {
+ .ns_reg[0] = 0x3cec,
+ .ns_reg[1] = 0x3cf0,
+ .md_reg[0] = 0x3ce4,
+ .md_reg[1] = 0x3ce8,
+ .bank_reg = 0x3ce0,
+ .mn[0] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .mn[1] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_gmac,
+ .clkr = {
+ .enable_reg = 0x3ce0,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core3_src",
+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
+ .num_parents = 5,
+ .ops = &clk_dyn_rcg_ops,
+ },
+ },
+};
+
+static struct clk_branch gmac_core3_clk = {
+ .halt_reg = 0x3c20,
+ .halt_bit = 6,
+ .hwcg_reg = 0x3cf4,
+ .hwcg_bit = 6,
+ .clkr = {
+ .enable_reg = 0x3cf4,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core3_clk",
+ .parent_names = (const char *[]){
+ "gmac_core3_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_dyn_rcg gmac_core4_src = {
+ .ns_reg[0] = 0x3d0c,
+ .ns_reg[1] = 0x3d10,
+ .md_reg[0] = 0x3d04,
+ .md_reg[1] = 0x3d08,
+ .bank_reg = 0x3d00,
+ .mn[0] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .mn[1] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_gmac,
+ .clkr = {
+ .enable_reg = 0x3d00,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core4_src",
+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
+ .num_parents = 5,
+ .ops = &clk_dyn_rcg_ops,
+ },
+ },
+};
+
+static struct clk_branch gmac_core4_clk = {
+ .halt_reg = 0x3c20,
+ .halt_bit = 7,
+ .hwcg_reg = 0x3d14,
+ .hwcg_bit = 6,
+ .clkr = {
+ .enable_reg = 0x3d14,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core4_clk",
+ .parent_names = (const char *[]){
+ "gmac_core4_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static const struct freq_tbl clk_tbl_nss_tcm[] = {
+ { 266000000, P_PLL0, 3, 0, 0 },
+ { 400000000, P_PLL0, 2, 0, 0 },
+ { }
+};
+
+static struct clk_dyn_rcg nss_tcm_src = {
+ .ns_reg[0] = 0x3dc4,
+ .ns_reg[1] = 0x3dc8,
+ .bank_reg = 0x3dc0,
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 4,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 4,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_nss_tcm,
+ .clkr = {
+ .enable_reg = 0x3dc0,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "nss_tcm_src",
+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
+ .num_parents = 5,
+ .ops = &clk_dyn_rcg_ops,
+ },
+ },
+};
+
+static struct clk_branch nss_tcm_clk = {
+ .halt_reg = 0x3c20,
+ .halt_bit = 14,
+ .clkr = {
+ .enable_reg = 0x3dd0,
+ .enable_mask = BIT(6) | BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "nss_tcm_clk",
+ .parent_names = (const char *[]){
+ "nss_tcm_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static const struct freq_tbl clk_tbl_nss[] = {
+ { 110000000, P_PLL18, 1, 1, 5 },
+ { 275000000, P_PLL18, 2, 0, 0 },
+ { 550000000, P_PLL18, 1, 0, 0 },
+ { 733000000, P_PLL18, 1, 0, 0 },
+ { }
+};
+
+static struct clk_dyn_rcg ubi32_core1_src_clk = {
+ .ns_reg[0] = 0x3d2c,
+ .ns_reg[1] = 0x3d30,
+ .md_reg[0] = 0x3d24,
+ .md_reg[1] = 0x3d28,
+ .bank_reg = 0x3d20,
+ .mn[0] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .mn[1] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_nss,
+ .clkr = {
+ .enable_reg = 0x3d20,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "ubi32_core1_src_clk",
+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
+ .num_parents = 5,
+ .ops = &clk_dyn_rcg_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ },
+ },
+};
+
+static struct clk_dyn_rcg ubi32_core2_src_clk = {
+ .ns_reg[0] = 0x3d4c,
+ .ns_reg[1] = 0x3d50,
+ .md_reg[0] = 0x3d44,
+ .md_reg[1] = 0x3d48,
+ .bank_reg = 0x3d40,
+ .mn[0] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .mn[1] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_nss,
+ .clkr = {
+ .enable_reg = 0x3d40,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "ubi32_core2_src_clk",
+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
+ .num_parents = 5,
+ .ops = &clk_dyn_rcg_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ },
+ },
+};
+
static struct clk_regmap *gcc_ipq806x_clks[] = {
[PLL0] = &pll0.clkr,
[PLL0_VOTE] = &pll0_vote,
@@ -2211,6 +2728,7 @@ static struct clk_regmap *gcc_ipq806x_clks[] = {
[PLL8_VOTE] = &pll8_vote,
[PLL14] = &pll14.clkr,
[PLL14_VOTE] = &pll14_vote,
+ [PLL18] = &pll18.clkr,
[GSBI1_UART_SRC] = &gsbi1_uart_src.clkr,
[GSBI1_UART_CLK] = &gsbi1_uart_clk.clkr,
[GSBI2_UART_SRC] = &gsbi2_uart_src.clkr,
@@ -2307,6 +2825,18 @@ static struct clk_regmap *gcc_ipq806x_clks[] = {
[USB_FS1_SYSTEM_CLK] = &usb_fs1_sys_clk.clkr,
[EBI2_CLK] = &ebi2_clk.clkr,
[EBI2_AON_CLK] = &ebi2_aon_clk.clkr,
+ [GMAC_CORE1_CLK_SRC] = &gmac_core1_src.clkr,
+ [GMAC_CORE1_CLK] = &gmac_core1_clk.clkr,
+ [GMAC_CORE2_CLK_SRC] = &gmac_core2_src.clkr,
+ [GMAC_CORE2_CLK] = &gmac_core2_clk.clkr,
+ [GMAC_CORE3_CLK_SRC] = &gmac_core3_src.clkr,
+ [GMAC_CORE3_CLK] = &gmac_core3_clk.clkr,
+ [GMAC_CORE4_CLK_SRC] = &gmac_core4_src.clkr,
+ [GMAC_CORE4_CLK] = &gmac_core4_clk.clkr,
+ [UBI32_CORE1_CLK_SRC] = &ubi32_core1_src_clk.clkr,
+ [UBI32_CORE2_CLK_SRC] = &ubi32_core2_src_clk.clkr,
+ [NSSTCM_CLK_SRC] = &nss_tcm_src.clkr,
+ [NSSTCM_CLK] = &nss_tcm_clk.clkr,
};
static const struct qcom_reset_map gcc_ipq806x_resets[] = {
@@ -2425,6 +2955,48 @@ static const struct qcom_reset_map gcc_ipq806x_resets[] = {
[USB30_1_PHY_RESET] = { 0x3b58, 0 },
[NSSFB0_RESET] = { 0x3b60, 6 },
[NSSFB1_RESET] = { 0x3b60, 7 },
+ [UBI32_CORE1_CLKRST_CLAMP_RESET] = { 0x3d3c, 3},
+ [UBI32_CORE1_CLAMP_RESET] = { 0x3d3c, 2 },
+ [UBI32_CORE1_AHB_RESET] = { 0x3d3c, 1 },
+ [UBI32_CORE1_AXI_RESET] = { 0x3d3c, 0 },
+ [UBI32_CORE2_CLKRST_CLAMP_RESET] = { 0x3d5c, 3 },
+ [UBI32_CORE2_CLAMP_RESET] = { 0x3d5c, 2 },
+ [UBI32_CORE2_AHB_RESET] = { 0x3d5c, 1 },
+ [UBI32_CORE2_AXI_RESET] = { 0x3d5c, 0 },
+ [GMAC_CORE1_RESET] = { 0x3cbc, 0 },
+ [GMAC_CORE2_RESET] = { 0x3cdc, 0 },
+ [GMAC_CORE3_RESET] = { 0x3cfc, 0 },
+ [GMAC_CORE4_RESET] = { 0x3d1c, 0 },
+ [GMAC_AHB_RESET] = { 0x3e24, 0 },
+ [NSS_CH0_RST_RX_CLK_N_RESET] = { 0x3b60, 0 },
+ [NSS_CH0_RST_TX_CLK_N_RESET] = { 0x3b60, 1 },
+ [NSS_CH0_RST_RX_125M_N_RESET] = { 0x3b60, 2 },
+ [NSS_CH0_HW_RST_RX_125M_N_RESET] = { 0x3b60, 3 },
+ [NSS_CH0_RST_TX_125M_N_RESET] = { 0x3b60, 4 },
+ [NSS_CH1_RST_RX_CLK_N_RESET] = { 0x3b60, 5 },
+ [NSS_CH1_RST_TX_CLK_N_RESET] = { 0x3b60, 6 },
+ [NSS_CH1_RST_RX_125M_N_RESET] = { 0x3b60, 7 },
+ [NSS_CH1_HW_RST_RX_125M_N_RESET] = { 0x3b60, 8 },
+ [NSS_CH1_RST_TX_125M_N_RESET] = { 0x3b60, 9 },
+ [NSS_CH2_RST_RX_CLK_N_RESET] = { 0x3b60, 10 },
+ [NSS_CH2_RST_TX_CLK_N_RESET] = { 0x3b60, 11 },
+ [NSS_CH2_RST_RX_125M_N_RESET] = { 0x3b60, 12 },
+ [NSS_CH2_HW_RST_RX_125M_N_RESET] = { 0x3b60, 13 },
+ [NSS_CH2_RST_TX_125M_N_RESET] = { 0x3b60, 14 },
+ [NSS_CH3_RST_RX_CLK_N_RESET] = { 0x3b60, 15 },
+ [NSS_CH3_RST_TX_CLK_N_RESET] = { 0x3b60, 16 },
+ [NSS_CH3_RST_RX_125M_N_RESET] = { 0x3b60, 17 },
+ [NSS_CH3_HW_RST_RX_125M_N_RESET] = { 0x3b60, 18 },
+ [NSS_CH3_RST_TX_125M_N_RESET] = { 0x3b60, 19 },
+ [NSS_RST_RX_250M_125M_N_RESET] = { 0x3b60, 20 },
+ [NSS_RST_TX_250M_125M_N_RESET] = { 0x3b60, 21 },
+ [NSS_QSGMII_TXPI_RST_N_RESET] = { 0x3b60, 22 },
+ [NSS_QSGMII_CDR_RST_N_RESET] = { 0x3b60, 23 },
+ [NSS_SGMII2_CDR_RST_N_RESET] = { 0x3b60, 24 },
+ [NSS_SGMII3_CDR_RST_N_RESET] = { 0x3b60, 25 },
+ [NSS_CAL_PRBS_RST_N_RESET] = { 0x3b60, 26 },
+ [NSS_LCKDT_RST_N_RESET] = { 0x3b60, 27 },
+ [NSS_SRDS_N_RESET] = { 0x3b60, 28 },
};
static const struct regmap_config gcc_ipq806x_regmap_config = {
@@ -2453,6 +3025,8 @@ static int gcc_ipq806x_probe(struct platform_device *pdev)
{
struct clk *clk;
struct device *dev = &pdev->dev;
+ struct regmap *regmap;
+ int ret;
/* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 25000000);
@@ -2463,7 +3037,25 @@ static int gcc_ipq806x_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return PTR_ERR(clk);
- return qcom_cc_probe(pdev, &gcc_ipq806x_desc);
+ ret = qcom_cc_probe(pdev, &gcc_ipq806x_desc);
+ if (ret)
+ return ret;
+
+ regmap = dev_get_regmap(dev, NULL);
+ if (!regmap)
+ return -ENODEV;
+
+ /* Setup PLL18 static bits */
+ regmap_update_bits(regmap, 0x31a4, 0xffffffc0, 0x40000400);
+ regmap_write(regmap, 0x31b0, 0x3080);
+
+ /* Set GMAC footswitch sleep/wakeup values */
+ regmap_write(regmap, 0x3cb8, 8);
+ regmap_write(regmap, 0x3cd8, 8);
+ regmap_write(regmap, 0x3cf8, 8);
+ regmap_write(regmap, 0x3d18, 8);
+
+ return 0;
}
static int gcc_ipq806x_remove(struct platform_device *pdev)
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index cb59619df23f..8677ead2a8e1 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -2,15 +2,16 @@
# EDAC Kconfig
# Copyright (c) 2008 Doug Thompson www.softwarebitmaker.com
# Licensed and distributed under the GPL
-#
+
+config EDAC_ATOMIC_SCRUB
+ bool
config EDAC_SUPPORT
bool
menuconfig EDAC
bool "EDAC (Error Detection And Correction) reporting"
- depends on HAS_IOMEM
- depends on X86 || PPC || TILE || ARM || EDAC_SUPPORT
+ depends on HAS_IOMEM && EDAC_SUPPORT
help
EDAC is designed to report errors in the core system.
These are low-level errors that are reported in the CPU or
@@ -262,10 +263,10 @@ config EDAC_SBRIDGE
config EDAC_MPC85XX
tristate "Freescale MPC83xx / MPC85xx"
- depends on EDAC_MM_EDAC && FSL_SOC && (PPC_83xx || PPC_85xx)
+ depends on EDAC_MM_EDAC && FSL_SOC
help
Support for error detection and correction on the Freescale
- MPC8349, MPC8560, MPC8540, MPC8548
+ MPC8349, MPC8560, MPC8540, MPC8548, T4240
config EDAC_MV64X60
tristate "Marvell MV64x60"
@@ -377,8 +378,8 @@ config EDAC_OCTEON_PCI
Cavium Octeon family of SOCs.
config EDAC_ALTERA_MC
- tristate "Altera SDRAM Memory Controller EDAC"
- depends on EDAC_MM_EDAC && ARCH_SOCFPGA
+ bool "Altera SDRAM Memory Controller EDAC"
+ depends on EDAC_MM_EDAC=y && ARCH_SOCFPGA
help
Support for error detection and correction on the
Altera SDRAM memory controller. Note that the
@@ -392,4 +393,11 @@ config EDAC_SYNOPSYS
Support for error detection and correction on the Synopsys DDR
memory controller.
+config EDAC_XGENE
+ tristate "APM X-Gene SoC"
+ depends on EDAC_MM_EDAC && (ARM64 || COMPILE_TEST)
+ help
+ Support for error detection and correction on the
+ APM X-Gene family of SOCs.
+
endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index b255f362b1db..28ef2a519f65 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -68,3 +68,4 @@ obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o
obj-$(CONFIG_EDAC_ALTERA_MC) += altera_edac.o
obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o
+obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 3c4929fda9d5..23ef0917483c 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -1,5 +1,5 @@
/*
- * Copyright Altera Corporation (C) 2014. All rights reserved.
+ * Copyright Altera Corporation (C) 2014-2015. All rights reserved.
* Copyright 2011-2012 Calxeda, Inc.
*
* This program is free software; you can redistribute it and/or modify it
@@ -28,113 +28,92 @@
#include <linux/types.h>
#include <linux/uaccess.h>
+#include "altera_edac.h"
#include "edac_core.h"
#include "edac_module.h"
#define EDAC_MOD_STR "altera_edac"
#define EDAC_VERSION "1"
-/* SDRAM Controller CtrlCfg Register */
-#define CTLCFG_OFST 0x00
-
-/* SDRAM Controller CtrlCfg Register Bit Masks */
-#define CTLCFG_ECC_EN 0x400
-#define CTLCFG_ECC_CORR_EN 0x800
-#define CTLCFG_GEN_SB_ERR 0x2000
-#define CTLCFG_GEN_DB_ERR 0x4000
-
-#define CTLCFG_ECC_AUTO_EN (CTLCFG_ECC_EN | \
- CTLCFG_ECC_CORR_EN)
-
-/* SDRAM Controller Address Width Register */
-#define DRAMADDRW_OFST 0x2C
-
-/* SDRAM Controller Address Widths Field Register */
-#define DRAMADDRW_COLBIT_MASK 0x001F
-#define DRAMADDRW_COLBIT_SHIFT 0
-#define DRAMADDRW_ROWBIT_MASK 0x03E0
-#define DRAMADDRW_ROWBIT_SHIFT 5
-#define DRAMADDRW_BANKBIT_MASK 0x1C00
-#define DRAMADDRW_BANKBIT_SHIFT 10
-#define DRAMADDRW_CSBIT_MASK 0xE000
-#define DRAMADDRW_CSBIT_SHIFT 13
-
-/* SDRAM Controller Interface Data Width Register */
-#define DRAMIFWIDTH_OFST 0x30
-
-/* SDRAM Controller Interface Data Width Defines */
-#define DRAMIFWIDTH_16B_ECC 24
-#define DRAMIFWIDTH_32B_ECC 40
-
-/* SDRAM Controller DRAM Status Register */
-#define DRAMSTS_OFST 0x38
-
-/* SDRAM Controller DRAM Status Register Bit Masks */
-#define DRAMSTS_SBEERR 0x04
-#define DRAMSTS_DBEERR 0x08
-#define DRAMSTS_CORR_DROP 0x10
-
-/* SDRAM Controller DRAM IRQ Register */
-#define DRAMINTR_OFST 0x3C
-
-/* SDRAM Controller DRAM IRQ Register Bit Masks */
-#define DRAMINTR_INTREN 0x01
-#define DRAMINTR_SBEMASK 0x02
-#define DRAMINTR_DBEMASK 0x04
-#define DRAMINTR_CORRDROPMASK 0x08
-#define DRAMINTR_INTRCLR 0x10
-
-/* SDRAM Controller Single Bit Error Count Register */
-#define SBECOUNT_OFST 0x40
-
-/* SDRAM Controller Single Bit Error Count Register Bit Masks */
-#define SBECOUNT_MASK 0x0F
-
-/* SDRAM Controller Double Bit Error Count Register */
-#define DBECOUNT_OFST 0x44
-
-/* SDRAM Controller Double Bit Error Count Register Bit Masks */
-#define DBECOUNT_MASK 0x0F
-
-/* SDRAM Controller ECC Error Address Register */
-#define ERRADDR_OFST 0x48
-
-/* SDRAM Controller ECC Error Address Register Bit Masks */
-#define ERRADDR_MASK 0xFFFFFFFF
+static const struct altr_sdram_prv_data c5_data = {
+ .ecc_ctrl_offset = CV_CTLCFG_OFST,
+ .ecc_ctl_en_mask = CV_CTLCFG_ECC_AUTO_EN,
+ .ecc_stat_offset = CV_DRAMSTS_OFST,
+ .ecc_stat_ce_mask = CV_DRAMSTS_SBEERR,
+ .ecc_stat_ue_mask = CV_DRAMSTS_DBEERR,
+ .ecc_saddr_offset = CV_ERRADDR_OFST,
+ .ecc_daddr_offset = CV_ERRADDR_OFST,
+ .ecc_cecnt_offset = CV_SBECOUNT_OFST,
+ .ecc_uecnt_offset = CV_DBECOUNT_OFST,
+ .ecc_irq_en_offset = CV_DRAMINTR_OFST,
+ .ecc_irq_en_mask = CV_DRAMINTR_INTREN,
+ .ecc_irq_clr_offset = CV_DRAMINTR_OFST,
+ .ecc_irq_clr_mask = (CV_DRAMINTR_INTRCLR | CV_DRAMINTR_INTREN),
+ .ecc_cnt_rst_offset = CV_DRAMINTR_OFST,
+ .ecc_cnt_rst_mask = CV_DRAMINTR_INTRCLR,
+#ifdef CONFIG_EDAC_DEBUG
+ .ce_ue_trgr_offset = CV_CTLCFG_OFST,
+ .ce_set_mask = CV_CTLCFG_GEN_SB_ERR,
+ .ue_set_mask = CV_CTLCFG_GEN_DB_ERR,
+#endif
+};
-/* Altera SDRAM Memory Controller data */
-struct altr_sdram_mc_data {
- struct regmap *mc_vbase;
+static const struct altr_sdram_prv_data a10_data = {
+ .ecc_ctrl_offset = A10_ECCCTRL1_OFST,
+ .ecc_ctl_en_mask = A10_ECCCTRL1_ECC_EN,
+ .ecc_stat_offset = A10_INTSTAT_OFST,
+ .ecc_stat_ce_mask = A10_INTSTAT_SBEERR,
+ .ecc_stat_ue_mask = A10_INTSTAT_DBEERR,
+ .ecc_saddr_offset = A10_SERRADDR_OFST,
+ .ecc_daddr_offset = A10_DERRADDR_OFST,
+ .ecc_irq_en_offset = A10_ERRINTEN_OFST,
+ .ecc_irq_en_mask = A10_ECC_IRQ_EN_MASK,
+ .ecc_irq_clr_offset = A10_INTSTAT_OFST,
+ .ecc_irq_clr_mask = (A10_INTSTAT_SBEERR | A10_INTSTAT_DBEERR),
+ .ecc_cnt_rst_offset = A10_ECCCTRL1_OFST,
+ .ecc_cnt_rst_mask = A10_ECC_CNT_RESET_MASK,
+#ifdef CONFIG_EDAC_DEBUG
+ .ce_ue_trgr_offset = A10_DIAGINTTEST_OFST,
+ .ce_set_mask = A10_DIAGINT_TSERRA_MASK,
+ .ue_set_mask = A10_DIAGINT_TDERRA_MASK,
+#endif
};
static irqreturn_t altr_sdram_mc_err_handler(int irq, void *dev_id)
{
struct mem_ctl_info *mci = dev_id;
struct altr_sdram_mc_data *drvdata = mci->pvt_info;
- u32 status, err_count, err_addr;
+ const struct altr_sdram_prv_data *priv = drvdata->data;
+ u32 status, err_count = 1, err_addr;
- /* Error Address is shared by both SBE & DBE */
- regmap_read(drvdata->mc_vbase, ERRADDR_OFST, &err_addr);
+ regmap_read(drvdata->mc_vbase, priv->ecc_stat_offset, &status);
- regmap_read(drvdata->mc_vbase, DRAMSTS_OFST, &status);
-
- if (status & DRAMSTS_DBEERR) {
- regmap_read(drvdata->mc_vbase, DBECOUNT_OFST, &err_count);
+ if (status & priv->ecc_stat_ue_mask) {
+ regmap_read(drvdata->mc_vbase, priv->ecc_daddr_offset,
+ &err_addr);
+ if (priv->ecc_uecnt_offset)
+ regmap_read(drvdata->mc_vbase, priv->ecc_uecnt_offset,
+ &err_count);
panic("\nEDAC: [%d Uncorrectable errors @ 0x%08X]\n",
err_count, err_addr);
}
- if (status & DRAMSTS_SBEERR) {
- regmap_read(drvdata->mc_vbase, SBECOUNT_OFST, &err_count);
+ if (status & priv->ecc_stat_ce_mask) {
+ regmap_read(drvdata->mc_vbase, priv->ecc_saddr_offset,
+ &err_addr);
+ if (priv->ecc_uecnt_offset)
+ regmap_read(drvdata->mc_vbase, priv->ecc_cecnt_offset,
+ &err_count);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, err_count,
err_addr >> PAGE_SHIFT,
err_addr & ~PAGE_MASK, 0,
0, 0, -1, mci->ctl_name, "");
- }
-
- regmap_write(drvdata->mc_vbase, DRAMINTR_OFST,
- (DRAMINTR_INTRCLR | DRAMINTR_INTREN));
+ /* Clear IRQ to resume */
+ regmap_write(drvdata->mc_vbase, priv->ecc_irq_clr_offset,
+ priv->ecc_irq_clr_mask);
- return IRQ_HANDLED;
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
}
#ifdef CONFIG_EDAC_DEBUG
@@ -144,6 +123,7 @@ static ssize_t altr_sdr_mc_err_inject_write(struct file *file,
{
struct mem_ctl_info *mci = file->private_data;
struct altr_sdram_mc_data *drvdata = mci->pvt_info;
+ const struct altr_sdram_prv_data *priv = drvdata->data;
u32 *ptemp;
dma_addr_t dma_handle;
u32 reg, read_reg;
@@ -156,8 +136,9 @@ static ssize_t altr_sdr_mc_err_inject_write(struct file *file,
return -ENOMEM;
}
- regmap_read(drvdata->mc_vbase, CTLCFG_OFST, &read_reg);
- read_reg &= ~(CTLCFG_GEN_SB_ERR | CTLCFG_GEN_DB_ERR);
+ regmap_read(drvdata->mc_vbase, priv->ce_ue_trgr_offset,
+ &read_reg);
+ read_reg &= ~(priv->ce_set_mask | priv->ue_set_mask);
/* Error are injected by writing a word while the SBE or DBE
* bit in the CTLCFG register is set. Reading the word will
@@ -166,20 +147,20 @@ static ssize_t altr_sdr_mc_err_inject_write(struct file *file,
if (count == 3) {
edac_printk(KERN_ALERT, EDAC_MC,
"Inject Double bit error\n");
- regmap_write(drvdata->mc_vbase, CTLCFG_OFST,
- (read_reg | CTLCFG_GEN_DB_ERR));
+ regmap_write(drvdata->mc_vbase, priv->ce_ue_trgr_offset,
+ (read_reg | priv->ue_set_mask));
} else {
edac_printk(KERN_ALERT, EDAC_MC,
"Inject Single bit error\n");
- regmap_write(drvdata->mc_vbase, CTLCFG_OFST,
- (read_reg | CTLCFG_GEN_SB_ERR));
+ regmap_write(drvdata->mc_vbase, priv->ce_ue_trgr_offset,
+ (read_reg | priv->ce_set_mask));
}
ptemp[0] = 0x5A5A5A5A;
ptemp[1] = 0xA5A5A5A5;
/* Clear the error injection bits */
- regmap_write(drvdata->mc_vbase, CTLCFG_OFST, read_reg);
+ regmap_write(drvdata->mc_vbase, priv->ce_ue_trgr_offset, read_reg);
/* Ensure it has been written out */
wmb();
@@ -219,50 +200,106 @@ static void altr_sdr_mc_create_debugfs_nodes(struct mem_ctl_info *mci)
{}
#endif
-/* Get total memory size in bytes */
-static u32 altr_sdram_get_total_mem_size(struct regmap *mc_vbase)
+/* Get total memory size from Open Firmware DTB */
+static unsigned long get_total_mem(void)
{
- u32 size, read_reg, row, bank, col, cs, width;
-
- if (regmap_read(mc_vbase, DRAMADDRW_OFST, &read_reg) < 0)
- return 0;
-
- if (regmap_read(mc_vbase, DRAMIFWIDTH_OFST, &width) < 0)
- return 0;
-
- col = (read_reg & DRAMADDRW_COLBIT_MASK) >>
- DRAMADDRW_COLBIT_SHIFT;
- row = (read_reg & DRAMADDRW_ROWBIT_MASK) >>
- DRAMADDRW_ROWBIT_SHIFT;
- bank = (read_reg & DRAMADDRW_BANKBIT_MASK) >>
- DRAMADDRW_BANKBIT_SHIFT;
- cs = (read_reg & DRAMADDRW_CSBIT_MASK) >>
- DRAMADDRW_CSBIT_SHIFT;
-
- /* Correct for ECC as its not addressible */
- if (width == DRAMIFWIDTH_32B_ECC)
- width = 32;
- if (width == DRAMIFWIDTH_16B_ECC)
- width = 16;
-
- /* calculate the SDRAM size base on this info */
- size = 1 << (row + bank + col);
- size = size * cs * (width / 8);
- return size;
+ struct device_node *np = NULL;
+ const unsigned int *reg, *reg_end;
+ int len, sw, aw;
+ unsigned long start, size, total_mem = 0;
+
+ for_each_node_by_type(np, "memory") {
+ aw = of_n_addr_cells(np);
+ sw = of_n_size_cells(np);
+ reg = (const unsigned int *)of_get_property(np, "reg", &len);
+ reg_end = reg + (len / sizeof(u32));
+
+ total_mem = 0;
+ do {
+ start = of_read_number(reg, aw);
+ reg += aw;
+ size = of_read_number(reg, sw);
+ reg += sw;
+ total_mem += size;
+ } while (reg < reg_end);
+ }
+ edac_dbg(0, "total_mem 0x%lx\n", total_mem);
+ return total_mem;
+}
+
+static const struct of_device_id altr_sdram_ctrl_of_match[] = {
+ { .compatible = "altr,sdram-edac", .data = (void *)&c5_data},
+ { .compatible = "altr,sdram-edac-a10", .data = (void *)&a10_data},
+ {},
+};
+MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match);
+
+static int a10_init(struct regmap *mc_vbase)
+{
+ if (regmap_update_bits(mc_vbase, A10_INTMODE_OFST,
+ A10_INTMODE_SB_INT, A10_INTMODE_SB_INT)) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Error setting SB IRQ mode\n");
+ return -ENODEV;
+ }
+
+ if (regmap_write(mc_vbase, A10_SERRCNTREG_OFST, 1)) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Error setting trigger count\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int a10_unmask_irq(struct platform_device *pdev, u32 mask)
+{
+ void __iomem *sm_base;
+ int ret = 0;
+
+ if (!request_mem_region(A10_SYMAN_INTMASK_CLR, sizeof(u32),
+ dev_name(&pdev->dev))) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Unable to request mem region\n");
+ return -EBUSY;
+ }
+
+ sm_base = ioremap(A10_SYMAN_INTMASK_CLR, sizeof(u32));
+ if (!sm_base) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Unable to ioremap device\n");
+
+ ret = -ENOMEM;
+ goto release;
+ }
+
+ iowrite32(mask, sm_base);
+
+ iounmap(sm_base);
+
+release:
+ release_mem_region(A10_SYMAN_INTMASK_CLR, sizeof(u32));
+
+ return ret;
}
static int altr_sdram_probe(struct platform_device *pdev)
{
+ const struct of_device_id *id;
struct edac_mc_layer layers[2];
struct mem_ctl_info *mci;
struct altr_sdram_mc_data *drvdata;
+ const struct altr_sdram_prv_data *priv;
struct regmap *mc_vbase;
struct dimm_info *dimm;
- u32 read_reg, mem_size;
- int irq;
- int res = 0;
+ u32 read_reg;
+ int irq, irq2, res = 0;
+ unsigned long mem_size, irqflags = 0;
+
+ id = of_match_device(altr_sdram_ctrl_of_match, &pdev->dev);
+ if (!id)
+ return -ENODEV;
- /* Validate the SDRAM controller has ECC enabled */
/* Grab the register range from the sdr controller in device tree */
mc_vbase = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
"altr,sdr-syscon");
@@ -272,25 +309,46 @@ static int altr_sdram_probe(struct platform_device *pdev)
return -ENODEV;
}
- if (regmap_read(mc_vbase, CTLCFG_OFST, &read_reg) ||
- ((read_reg & CTLCFG_ECC_AUTO_EN) != CTLCFG_ECC_AUTO_EN)) {
+ /* Check specific dependencies for the module */
+ priv = of_match_node(altr_sdram_ctrl_of_match,
+ pdev->dev.of_node)->data;
+
+ /* Validate the SDRAM controller has ECC enabled */
+ if (regmap_read(mc_vbase, priv->ecc_ctrl_offset, &read_reg) ||
+ ((read_reg & priv->ecc_ctl_en_mask) != priv->ecc_ctl_en_mask)) {
edac_printk(KERN_ERR, EDAC_MC,
"No ECC/ECC disabled [0x%08X]\n", read_reg);
return -ENODEV;
}
/* Grab memory size from device tree. */
- mem_size = altr_sdram_get_total_mem_size(mc_vbase);
+ mem_size = get_total_mem();
if (!mem_size) {
+ edac_printk(KERN_ERR, EDAC_MC, "Unable to calculate memory size\n");
+ return -ENODEV;
+ }
+
+ /* Ensure the SDRAM Interrupt is disabled */
+ if (regmap_update_bits(mc_vbase, priv->ecc_irq_en_offset,
+ priv->ecc_irq_en_mask, 0)) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Error disabling SDRAM ECC IRQ\n");
+ return -ENODEV;
+ }
+
+ /* Toggle to clear the SDRAM Error count */
+ if (regmap_update_bits(mc_vbase, priv->ecc_cnt_rst_offset,
+ priv->ecc_cnt_rst_mask,
+ priv->ecc_cnt_rst_mask)) {
edac_printk(KERN_ERR, EDAC_MC,
- "Unable to calculate memory size\n");
+ "Error clearing SDRAM ECC count\n");
return -ENODEV;
}
- /* Ensure the SDRAM Interrupt is disabled and cleared */
- if (regmap_write(mc_vbase, DRAMINTR_OFST, DRAMINTR_INTRCLR)) {
+ if (regmap_update_bits(mc_vbase, priv->ecc_cnt_rst_offset,
+ priv->ecc_cnt_rst_mask, 0)) {
edac_printk(KERN_ERR, EDAC_MC,
- "Error clearing SDRAM ECC IRQ\n");
+ "Error clearing SDRAM ECC count\n");
return -ENODEV;
}
@@ -301,6 +359,9 @@ static int altr_sdram_probe(struct platform_device *pdev)
return -ENODEV;
}
+ /* Arria10 has a 2nd IRQ */
+ irq2 = platform_get_irq(pdev, 1);
+
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = 1;
layers[0].is_virt_csrow = true;
@@ -315,9 +376,12 @@ static int altr_sdram_probe(struct platform_device *pdev)
mci->pdev = &pdev->dev;
drvdata = mci->pvt_info;
drvdata->mc_vbase = mc_vbase;
+ drvdata->data = priv;
platform_set_drvdata(pdev, mci);
if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Unable to get managed device resource\n");
res = -ENOMEM;
goto free;
}
@@ -342,8 +406,32 @@ static int altr_sdram_probe(struct platform_device *pdev)
if (res < 0)
goto err;
+ /* Only the Arria10 has separate IRQs */
+ if (irq2 > 0) {
+ /* Arria10 specific initialization */
+ res = a10_init(mc_vbase);
+ if (res < 0)
+ goto err2;
+
+ res = devm_request_irq(&pdev->dev, irq2,
+ altr_sdram_mc_err_handler,
+ IRQF_SHARED, dev_name(&pdev->dev), mci);
+ if (res < 0) {
+ edac_mc_printk(mci, KERN_ERR,
+ "Unable to request irq %d\n", irq2);
+ res = -ENODEV;
+ goto err2;
+ }
+
+ res = a10_unmask_irq(pdev, A10_DDR0_IRQ_MASK);
+ if (res < 0)
+ goto err2;
+
+ irqflags = IRQF_SHARED;
+ }
+
res = devm_request_irq(&pdev->dev, irq, altr_sdram_mc_err_handler,
- 0, dev_name(&pdev->dev), mci);
+ irqflags, dev_name(&pdev->dev), mci);
if (res < 0) {
edac_mc_printk(mci, KERN_ERR,
"Unable to request irq %d\n", irq);
@@ -351,8 +439,9 @@ static int altr_sdram_probe(struct platform_device *pdev)
goto err2;
}
- if (regmap_write(drvdata->mc_vbase, DRAMINTR_OFST,
- (DRAMINTR_INTRCLR | DRAMINTR_INTREN))) {
+ /* Infrastructure ready - enable the IRQ */
+ if (regmap_update_bits(drvdata->mc_vbase, priv->ecc_irq_en_offset,
+ priv->ecc_irq_en_mask, priv->ecc_irq_en_mask)) {
edac_mc_printk(mci, KERN_ERR,
"Error enabling SDRAM ECC IRQ\n");
res = -ENODEV;
@@ -388,17 +477,31 @@ static int altr_sdram_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id altr_sdram_ctrl_of_match[] = {
- { .compatible = "altr,sdram-edac", },
- {},
+/*
+ * If you want to suspend, need to disable EDAC by removing it
+ * from the device tree or defconfig.
+ */
+#ifdef CONFIG_PM
+static int altr_sdram_prepare(struct device *dev)
+{
+ pr_err("Suspend not allowed when EDAC is enabled.\n");
+
+ return -EPERM;
+}
+
+static const struct dev_pm_ops altr_sdram_pm_ops = {
+ .prepare = altr_sdram_prepare,
};
-MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match);
+#endif
static struct platform_driver altr_sdram_edac_driver = {
.probe = altr_sdram_probe,
.remove = altr_sdram_remove,
.driver = {
.name = "altr_sdram_edac",
+#ifdef CONFIG_PM
+ .pm = &altr_sdram_pm_ops,
+#endif
.of_match_table = altr_sdram_ctrl_of_match,
},
};
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h
new file mode 100644
index 000000000000..7b64dc7c4eb7
--- /dev/null
+++ b/drivers/edac/altera_edac.h
@@ -0,0 +1,201 @@
+/*
+ *
+ * Copyright (C) 2015 Altera Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _ALTERA_EDAC_H
+#define _ALTERA_EDAC_H
+
+#include <linux/edac.h>
+#include <linux/types.h>
+
+/* SDRAM Controller CtrlCfg Register */
+#define CV_CTLCFG_OFST 0x00
+
+/* SDRAM Controller CtrlCfg Register Bit Masks */
+#define CV_CTLCFG_ECC_EN 0x400
+#define CV_CTLCFG_ECC_CORR_EN 0x800
+#define CV_CTLCFG_GEN_SB_ERR 0x2000
+#define CV_CTLCFG_GEN_DB_ERR 0x4000
+
+#define CV_CTLCFG_ECC_AUTO_EN (CV_CTLCFG_ECC_EN | \
+ CV_CTLCFG_ECC_CORR_EN)
+
+/* SDRAM Controller Address Width Register */
+#define CV_DRAMADDRW_OFST 0x2C
+
+/* SDRAM Controller Address Widths Field Register */
+#define DRAMADDRW_COLBIT_MASK 0x001F
+#define DRAMADDRW_COLBIT_SHIFT 0
+#define DRAMADDRW_ROWBIT_MASK 0x03E0
+#define DRAMADDRW_ROWBIT_SHIFT 5
+#define CV_DRAMADDRW_BANKBIT_MASK 0x1C00
+#define CV_DRAMADDRW_BANKBIT_SHIFT 10
+#define CV_DRAMADDRW_CSBIT_MASK 0xE000
+#define CV_DRAMADDRW_CSBIT_SHIFT 13
+
+/* SDRAM Controller Interface Data Width Register */
+#define CV_DRAMIFWIDTH_OFST 0x30
+
+/* SDRAM Controller Interface Data Width Defines */
+#define CV_DRAMIFWIDTH_16B_ECC 24
+#define CV_DRAMIFWIDTH_32B_ECC 40
+
+/* SDRAM Controller DRAM Status Register */
+#define CV_DRAMSTS_OFST 0x38
+
+/* SDRAM Controller DRAM Status Register Bit Masks */
+#define CV_DRAMSTS_SBEERR 0x04
+#define CV_DRAMSTS_DBEERR 0x08
+#define CV_DRAMSTS_CORR_DROP 0x10
+
+/* SDRAM Controller DRAM IRQ Register */
+#define CV_DRAMINTR_OFST 0x3C
+
+/* SDRAM Controller DRAM IRQ Register Bit Masks */
+#define CV_DRAMINTR_INTREN 0x01
+#define CV_DRAMINTR_SBEMASK 0x02
+#define CV_DRAMINTR_DBEMASK 0x04
+#define CV_DRAMINTR_CORRDROPMASK 0x08
+#define CV_DRAMINTR_INTRCLR 0x10
+
+/* SDRAM Controller Single Bit Error Count Register */
+#define CV_SBECOUNT_OFST 0x40
+
+/* SDRAM Controller Double Bit Error Count Register */
+#define CV_DBECOUNT_OFST 0x44
+
+/* SDRAM Controller ECC Error Address Register */
+#define CV_ERRADDR_OFST 0x48
+
+/*-----------------------------------------*/
+
+/* SDRAM Controller EccCtrl Register */
+#define A10_ECCCTRL1_OFST 0x00
+
+/* SDRAM Controller EccCtrl Register Bit Masks */
+#define A10_ECCCTRL1_ECC_EN 0x001
+#define A10_ECCCTRL1_CNT_RST 0x010
+#define A10_ECCCTRL1_AWB_CNT_RST 0x100
+#define A10_ECC_CNT_RESET_MASK (A10_ECCCTRL1_CNT_RST | \
+ A10_ECCCTRL1_AWB_CNT_RST)
+
+/* SDRAM Controller Address Width Register */
+#define CV_DRAMADDRW 0xFFC2502C
+#define A10_DRAMADDRW 0xFFCFA0A8
+
+/* SDRAM Controller Address Widths Field Register */
+#define DRAMADDRW_COLBIT_MASK 0x001F
+#define DRAMADDRW_COLBIT_SHIFT 0
+#define DRAMADDRW_ROWBIT_MASK 0x03E0
+#define DRAMADDRW_ROWBIT_SHIFT 5
+#define CV_DRAMADDRW_BANKBIT_MASK 0x1C00
+#define CV_DRAMADDRW_BANKBIT_SHIFT 10
+#define CV_DRAMADDRW_CSBIT_MASK 0xE000
+#define CV_DRAMADDRW_CSBIT_SHIFT 13
+
+#define A10_DRAMADDRW_BANKBIT_MASK 0x3C00
+#define A10_DRAMADDRW_BANKBIT_SHIFT 10
+#define A10_DRAMADDRW_GRPBIT_MASK 0xC000
+#define A10_DRAMADDRW_GRPBIT_SHIFT 14
+#define A10_DRAMADDRW_CSBIT_MASK 0x70000
+#define A10_DRAMADDRW_CSBIT_SHIFT 16
+
+/* SDRAM Controller Interface Data Width Register */
+#define CV_DRAMIFWIDTH 0xFFC25030
+#define A10_DRAMIFWIDTH 0xFFCFB008
+
+/* SDRAM Controller Interface Data Width Defines */
+#define CV_DRAMIFWIDTH_16B_ECC 24
+#define CV_DRAMIFWIDTH_32B_ECC 40
+
+#define A10_DRAMIFWIDTH_16B 0x0
+#define A10_DRAMIFWIDTH_32B 0x1
+#define A10_DRAMIFWIDTH_64B 0x2
+
+/* SDRAM Controller DRAM IRQ Register */
+#define A10_ERRINTEN_OFST 0x10
+
+/* SDRAM Controller DRAM IRQ Register Bit Masks */
+#define A10_ERRINTEN_SERRINTEN 0x01
+#define A10_ERRINTEN_DERRINTEN 0x02
+#define A10_ECC_IRQ_EN_MASK (A10_ERRINTEN_SERRINTEN | \
+ A10_ERRINTEN_DERRINTEN)
+
+/* SDRAM Interrupt Mode Register */
+#define A10_INTMODE_OFST 0x1C
+#define A10_INTMODE_SB_INT 1
+
+/* SDRAM Controller Error Status Register */
+#define A10_INTSTAT_OFST 0x20
+
+/* SDRAM Controller Error Status Register Bit Masks */
+#define A10_INTSTAT_SBEERR 0x01
+#define A10_INTSTAT_DBEERR 0x02
+
+/* SDRAM Controller ECC Error Address Register */
+#define A10_DERRADDR_OFST 0x2C
+#define A10_SERRADDR_OFST 0x30
+
+/* SDRAM Controller ECC Diagnostic Register */
+#define A10_DIAGINTTEST_OFST 0x24
+
+#define A10_DIAGINT_TSERRA_MASK 0x0001
+#define A10_DIAGINT_TDERRA_MASK 0x0100
+
+#define A10_SBERR_IRQ 34
+#define A10_DBERR_IRQ 32
+
+/* SDRAM Single Bit Error Count Compare Set Register */
+#define A10_SERRCNTREG_OFST 0x3C
+
+#define A10_SYMAN_INTMASK_CLR 0xFFD06098
+#define A10_INTMASK_CLR_OFST 0x10
+#define A10_DDR0_IRQ_MASK BIT(17)
+
+struct altr_sdram_prv_data {
+ int ecc_ctrl_offset;
+ int ecc_ctl_en_mask;
+ int ecc_cecnt_offset;
+ int ecc_uecnt_offset;
+ int ecc_stat_offset;
+ int ecc_stat_ce_mask;
+ int ecc_stat_ue_mask;
+ int ecc_saddr_offset;
+ int ecc_daddr_offset;
+ int ecc_irq_en_offset;
+ int ecc_irq_en_mask;
+ int ecc_irq_clr_offset;
+ int ecc_irq_clr_mask;
+ int ecc_cnt_rst_offset;
+ int ecc_cnt_rst_mask;
+#ifdef CONFIG_EDAC_DEBUG
+ struct edac_dev_sysfs_attribute *eccmgr_sysfs_attr;
+ int ecc_enable_mask;
+ int ce_set_mask;
+ int ue_set_mask;
+ int ce_ue_trgr_offset;
+#endif
+};
+
+/* Altera SDRAM Memory Controller data */
+struct altr_sdram_mc_data {
+ struct regmap *mc_vbase;
+ int sb_irq;
+ int db_irq;
+ const struct altr_sdram_prv_data *data;
+};
+
+#endif /* #ifndef _ALTERA_EDAC_H */
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index af3be1914dbb..943ed8cf71b9 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -30,11 +30,16 @@
#include <linux/bitops.h>
#include <asm/uaccess.h>
#include <asm/page.h>
-#include <asm/edac.h>
#include "edac_core.h"
#include "edac_module.h"
#include <ras/ras_event.h>
+#ifdef CONFIG_EDAC_ATOMIC_SCRUB
+#include <asm/edac.h>
+#else
+#define edac_atomic_scrub(va, size) do { } while (0)
+#endif
+
/* lock to memory controller's control array */
static DEFINE_MUTEX(mem_ctls_mutex);
static LIST_HEAD(mc_devices);
@@ -874,7 +879,7 @@ static void edac_mc_scrub_block(unsigned long page, unsigned long offset,
virt_addr = kmap_atomic(pg);
/* Perform architecture specific atomic scrub operation */
- atomic_scrub(virt_addr + offset, size);
+ edac_atomic_scrub(virt_addr + offset, size);
/* Unmap and complete */
kunmap_atomic(virt_addr);
diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c
index 9d9e18aefaaa..ff07aae5b7fb 100644
--- a/drivers/edac/edac_stub.c
+++ b/drivers/edac/edac_stub.c
@@ -16,7 +16,6 @@
#include <linux/edac.h>
#include <linux/atomic.h>
#include <linux/device.h>
-#include <asm/edac.h>
int edac_op_state = EDAC_OPSTATE_INVAL;
EXPORT_SYMBOL_GPL(edac_op_state);
diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c
index f7681b553fd5..4c73e4d03d46 100644
--- a/drivers/edac/mce_amd_inj.c
+++ b/drivers/edac/mce_amd_inj.c
@@ -15,6 +15,8 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/cpu.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
#include <asm/mce.h>
#include "mce_amd.h"
@@ -25,6 +27,25 @@
static struct mce i_mce;
static struct dentry *dfs_inj;
+static u8 n_banks;
+
+#define MAX_FLAG_OPT_SIZE 3
+
+enum injection_type {
+ SW_INJ = 0, /* SW injection, simply decode the error */
+ HW_INJ, /* Trigger a #MC */
+ N_INJ_TYPES,
+};
+
+static const char * const flags_options[] = {
+ [SW_INJ] = "sw",
+ [HW_INJ] = "hw",
+ NULL
+};
+
+/* Set default injection to SW_INJ */
+static enum injection_type inj_type = SW_INJ;
+
#define MCE_INJECT_SET(reg) \
static int inj_##reg##_set(void *data, u64 val) \
{ \
@@ -79,24 +100,66 @@ static int toggle_hw_mce_inject(unsigned int cpu, bool enable)
return err;
}
-static int flags_get(void *data, u64 *val)
+static int __set_inj(const char *buf)
{
- struct mce *m = (struct mce *)data;
+ int i;
- *val = m->inject_flags;
+ for (i = 0; i < N_INJ_TYPES; i++) {
+ if (!strncmp(flags_options[i], buf, strlen(flags_options[i]))) {
+ inj_type = i;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
- return 0;
+static ssize_t flags_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ char buf[MAX_FLAG_OPT_SIZE];
+ int n;
+
+ n = sprintf(buf, "%s\n", flags_options[inj_type]);
+
+ return simple_read_from_buffer(ubuf, cnt, ppos, buf, n);
}
-static int flags_set(void *data, u64 val)
+static ssize_t flags_write(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
{
- struct mce *m = (struct mce *)data;
+ char buf[MAX_FLAG_OPT_SIZE], *__buf;
+ int err;
+ size_t ret;
- m->inject_flags = (u8)val;
- return 0;
+ if (cnt > MAX_FLAG_OPT_SIZE)
+ cnt = MAX_FLAG_OPT_SIZE;
+
+ ret = cnt;
+
+ if (copy_from_user(&buf, ubuf, cnt))
+ return -EFAULT;
+
+ buf[cnt - 1] = 0;
+
+ /* strip whitespace */
+ __buf = strstrip(buf);
+
+ err = __set_inj(__buf);
+ if (err) {
+ pr_err("%s: Invalid flags value: %s\n", __func__, __buf);
+ return err;
+ }
+
+ *ppos += ret;
+
+ return ret;
}
-DEFINE_SIMPLE_ATTRIBUTE(flags_fops, flags_get, flags_set, "%llu\n");
+static const struct file_operations flags_fops = {
+ .read = flags_read,
+ .write = flags_write,
+ .llseek = generic_file_llseek,
+};
/*
* On which CPU to inject?
@@ -128,21 +191,24 @@ static void do_inject(void)
unsigned int cpu = i_mce.extcpu;
u8 b = i_mce.bank;
- if (!(i_mce.inject_flags & MCJ_EXCEPTION)) {
+ if (i_mce.misc)
+ i_mce.status |= MCI_STATUS_MISCV;
+
+ if (inj_type == SW_INJ) {
amd_decode_mce(NULL, 0, &i_mce);
return;
}
- get_online_cpus();
- if (!cpu_online(cpu))
- goto err;
-
/* prep MCE global settings for the injection */
mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV;
if (!(i_mce.status & MCI_STATUS_PCC))
mcg_status |= MCG_STATUS_RIPV;
+ get_online_cpus();
+ if (!cpu_online(cpu))
+ goto err;
+
toggle_hw_mce_inject(cpu, true);
wrmsr_on_cpu(cpu, MSR_IA32_MCG_STATUS,
@@ -174,11 +240,9 @@ static int inj_bank_set(void *data, u64 val)
{
struct mce *m = (struct mce *)data;
- if (val > 5) {
- if (boot_cpu_data.x86 != 0x15 || val > 6) {
- pr_err("Non-existent MCE bank: %llu\n", val);
- return -EINVAL;
- }
+ if (val >= n_banks) {
+ pr_err("Non-existent MCE bank: %llu\n", val);
+ return -EINVAL;
}
m->bank = val;
@@ -187,32 +251,81 @@ static int inj_bank_set(void *data, u64 val)
return 0;
}
-static int inj_bank_get(void *data, u64 *val)
-{
- struct mce *m = (struct mce *)data;
+MCE_INJECT_GET(bank);
- *val = m->bank;
- return 0;
+DEFINE_SIMPLE_ATTRIBUTE(bank_fops, inj_bank_get, inj_bank_set, "%llu\n");
+
+static const char readme_msg[] =
+"Description of the files and their usages:\n"
+"\n"
+"Note1: i refers to the bank number below.\n"
+"Note2: See respective BKDGs for the exact bit definitions of the files below\n"
+"as they mirror the hardware registers.\n"
+"\n"
+"status:\t Set MCi_STATUS: the bits in that MSR control the error type and\n"
+"\t attributes of the error which caused the MCE.\n"
+"\n"
+"misc:\t Set MCi_MISC: provide auxiliary info about the error. It is mostly\n"
+"\t used for error thresholding purposes and its validity is indicated by\n"
+"\t MCi_STATUS[MiscV].\n"
+"\n"
+"addr:\t Error address value to be written to MCi_ADDR. Log address information\n"
+"\t associated with the error.\n"
+"\n"
+"cpu:\t The CPU to inject the error on.\n"
+"\n"
+"bank:\t Specify the bank you want to inject the error into: the number of\n"
+"\t banks in a processor varies and is family/model-specific, therefore, the\n"
+"\t supplied value is sanity-checked. Setting the bank value also triggers the\n"
+"\t injection.\n"
+"\n"
+"flags:\t Injection type to be performed. Writing to this file will trigger a\n"
+"\t real machine check, an APIC interrupt or invoke the error decoder routines\n"
+"\t for AMD processors.\n"
+"\n"
+"\t Allowed error injection types:\n"
+"\t - \"sw\": Software error injection. Decode error to a human-readable \n"
+"\t format only. Safe to use.\n"
+"\t - \"hw\": Hardware error injection. Causes the #MC exception handler to \n"
+"\t handle the error. Be warned: might cause system panic if MCi_STATUS[PCC] \n"
+"\t is set. Therefore, consider setting (debugfs_mountpoint)/mce/fake_panic \n"
+"\t before injecting.\n"
+"\n";
+
+static ssize_t
+inj_readme_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return simple_read_from_buffer(ubuf, cnt, ppos,
+ readme_msg, strlen(readme_msg));
}
-DEFINE_SIMPLE_ATTRIBUTE(bank_fops, inj_bank_get, inj_bank_set, "%llu\n");
+static const struct file_operations readme_fops = {
+ .read = inj_readme_read,
+};
static struct dfs_node {
char *name;
struct dentry *d;
const struct file_operations *fops;
+ umode_t perm;
} dfs_fls[] = {
- { .name = "status", .fops = &status_fops },
- { .name = "misc", .fops = &misc_fops },
- { .name = "addr", .fops = &addr_fops },
- { .name = "bank", .fops = &bank_fops },
- { .name = "flags", .fops = &flags_fops },
- { .name = "cpu", .fops = &extcpu_fops },
+ { .name = "status", .fops = &status_fops, .perm = S_IRUSR | S_IWUSR },
+ { .name = "misc", .fops = &misc_fops, .perm = S_IRUSR | S_IWUSR },
+ { .name = "addr", .fops = &addr_fops, .perm = S_IRUSR | S_IWUSR },
+ { .name = "bank", .fops = &bank_fops, .perm = S_IRUSR | S_IWUSR },
+ { .name = "flags", .fops = &flags_fops, .perm = S_IRUSR | S_IWUSR },
+ { .name = "cpu", .fops = &extcpu_fops, .perm = S_IRUSR | S_IWUSR },
+ { .name = "README", .fops = &readme_fops, .perm = S_IRUSR | S_IRGRP | S_IROTH },
};
static int __init init_mce_inject(void)
{
int i;
+ u64 cap;
+
+ rdmsrl(MSR_IA32_MCG_CAP, cap);
+ n_banks = cap & MCG_BANKCNT_MASK;
dfs_inj = debugfs_create_dir("mce-inject", NULL);
if (!dfs_inj)
@@ -220,7 +333,7 @@ static int __init init_mce_inject(void)
for (i = 0; i < ARRAY_SIZE(dfs_fls); i++) {
dfs_fls[i].d = debugfs_create_file(dfs_fls[i].name,
- S_IRUSR | S_IWUSR,
+ dfs_fls[i].perm,
dfs_inj,
&i_mce,
dfs_fls[i].fops);
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 68bf234bdfe6..23ef8e9f2c9a 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -811,6 +811,8 @@ static void sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc,
}
}
+#define make64(high, low) (((u64)(high) << 32) | (low))
+
static void mpc85xx_mc_check(struct mem_ctl_info *mci)
{
struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
@@ -818,7 +820,7 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
u32 bus_width;
u32 err_detect;
u32 syndrome;
- u32 err_addr;
+ u64 err_addr;
u32 pfn;
int row_index;
u32 cap_high;
@@ -849,7 +851,9 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
else
syndrome &= 0xffff;
- err_addr = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS);
+ err_addr = make64(
+ in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_EXT_ADDRESS),
+ in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS));
pfn = err_addr >> PAGE_SHIFT;
for (row_index = 0; row_index < mci->nr_csrows; row_index++) {
@@ -886,7 +890,7 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
mpc85xx_mc_printk(mci, KERN_ERR,
"Captured Data / ECC:\t%#8.8x_%08x / %#2.2x\n",
cap_high, cap_low, syndrome);
- mpc85xx_mc_printk(mci, KERN_ERR, "Err addr: %#8.8x\n", err_addr);
+ mpc85xx_mc_printk(mci, KERN_ERR, "Err addr: %#8.8llx\n", err_addr);
mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn);
/* we are out of range */
diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h
index 4498baf9ce05..9352e88d53e5 100644
--- a/drivers/edac/mpc85xx_edac.h
+++ b/drivers/edac/mpc85xx_edac.h
@@ -43,6 +43,7 @@
#define MPC85XX_MC_ERR_INT_EN 0x0e48
#define MPC85XX_MC_CAPTURE_ATRIBUTES 0x0e4c
#define MPC85XX_MC_CAPTURE_ADDRESS 0x0e50
+#define MPC85XX_MC_CAPTURE_EXT_ADDRESS 0x0e54
#define MPC85XX_MC_ERR_SBE 0x0e58
#define DSC_MEM_EN 0x80000000
diff --git a/drivers/edac/xgene_edac.c b/drivers/edac/xgene_edac.c
new file mode 100644
index 000000000000..14636e4b6a08
--- /dev/null
+++ b/drivers/edac/xgene_edac.c
@@ -0,0 +1,1215 @@
+/*
+ * APM X-Gene SoC EDAC (error detection and correction)
+ *
+ * Copyright (c) 2015, Applied Micro Circuits Corporation
+ * Author: Feng Kan <fkan@apm.com>
+ * Loc Ho <lho@apm.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/ctype.h>
+#include <linux/edac.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+
+#include "edac_core.h"
+
+#define EDAC_MOD_STR "xgene_edac"
+
+/* Global error configuration status registers (CSR) */
+#define PCPHPERRINTSTS 0x0000
+#define PCPHPERRINTMSK 0x0004
+#define MCU_CTL_ERR_MASK BIT(12)
+#define IOB_PA_ERR_MASK BIT(11)
+#define IOB_BA_ERR_MASK BIT(10)
+#define IOB_XGIC_ERR_MASK BIT(9)
+#define IOB_RB_ERR_MASK BIT(8)
+#define L3C_UNCORR_ERR_MASK BIT(5)
+#define MCU_UNCORR_ERR_MASK BIT(4)
+#define PMD3_MERR_MASK BIT(3)
+#define PMD2_MERR_MASK BIT(2)
+#define PMD1_MERR_MASK BIT(1)
+#define PMD0_MERR_MASK BIT(0)
+#define PCPLPERRINTSTS 0x0008
+#define PCPLPERRINTMSK 0x000C
+#define CSW_SWITCH_TRACE_ERR_MASK BIT(2)
+#define L3C_CORR_ERR_MASK BIT(1)
+#define MCU_CORR_ERR_MASK BIT(0)
+#define MEMERRINTSTS 0x0010
+#define MEMERRINTMSK 0x0014
+
+struct xgene_edac {
+ struct device *dev;
+ struct regmap *csw_map;
+ struct regmap *mcba_map;
+ struct regmap *mcbb_map;
+ struct regmap *efuse_map;
+ void __iomem *pcp_csr;
+ spinlock_t lock;
+ struct dentry *dfs;
+
+ struct list_head mcus;
+ struct list_head pmds;
+
+ struct mutex mc_lock;
+ int mc_active_mask;
+ int mc_registered_mask;
+};
+
+static void xgene_edac_pcp_rd(struct xgene_edac *edac, u32 reg, u32 *val)
+{
+ *val = readl(edac->pcp_csr + reg);
+}
+
+static void xgene_edac_pcp_clrbits(struct xgene_edac *edac, u32 reg,
+ u32 bits_mask)
+{
+ u32 val;
+
+ spin_lock(&edac->lock);
+ val = readl(edac->pcp_csr + reg);
+ val &= ~bits_mask;
+ writel(val, edac->pcp_csr + reg);
+ spin_unlock(&edac->lock);
+}
+
+static void xgene_edac_pcp_setbits(struct xgene_edac *edac, u32 reg,
+ u32 bits_mask)
+{
+ u32 val;
+
+ spin_lock(&edac->lock);
+ val = readl(edac->pcp_csr + reg);
+ val |= bits_mask;
+ writel(val, edac->pcp_csr + reg);
+ spin_unlock(&edac->lock);
+}
+
+/* Memory controller error CSR */
+#define MCU_MAX_RANK 8
+#define MCU_RANK_STRIDE 0x40
+
+#define MCUGECR 0x0110
+#define MCU_GECR_DEMANDUCINTREN_MASK BIT(0)
+#define MCU_GECR_BACKUCINTREN_MASK BIT(1)
+#define MCU_GECR_CINTREN_MASK BIT(2)
+#define MUC_GECR_MCUADDRERREN_MASK BIT(9)
+#define MCUGESR 0x0114
+#define MCU_GESR_ADDRNOMATCH_ERR_MASK BIT(7)
+#define MCU_GESR_ADDRMULTIMATCH_ERR_MASK BIT(6)
+#define MCU_GESR_PHYP_ERR_MASK BIT(3)
+#define MCUESRR0 0x0314
+#define MCU_ESRR_MULTUCERR_MASK BIT(3)
+#define MCU_ESRR_BACKUCERR_MASK BIT(2)
+#define MCU_ESRR_DEMANDUCERR_MASK BIT(1)
+#define MCU_ESRR_CERR_MASK BIT(0)
+#define MCUESRRA0 0x0318
+#define MCUEBLRR0 0x031c
+#define MCU_EBLRR_ERRBANK_RD(src) (((src) & 0x00000007) >> 0)
+#define MCUERCRR0 0x0320
+#define MCU_ERCRR_ERRROW_RD(src) (((src) & 0xFFFF0000) >> 16)
+#define MCU_ERCRR_ERRCOL_RD(src) ((src) & 0x00000FFF)
+#define MCUSBECNT0 0x0324
+#define MCU_SBECNT_COUNT(src) ((src) & 0xFFFF)
+
+#define CSW_CSWCR 0x0000
+#define CSW_CSWCR_DUALMCB_MASK BIT(0)
+
+#define MCBADDRMR 0x0000
+#define MCBADDRMR_MCU_INTLV_MODE_MASK BIT(3)
+#define MCBADDRMR_DUALMCU_MODE_MASK BIT(2)
+#define MCBADDRMR_MCB_INTLV_MODE_MASK BIT(1)
+#define MCBADDRMR_ADDRESS_MODE_MASK BIT(0)
+
+struct xgene_edac_mc_ctx {
+ struct list_head next;
+ char *name;
+ struct mem_ctl_info *mci;
+ struct xgene_edac *edac;
+ void __iomem *mcu_csr;
+ u32 mcu_id;
+};
+
+static ssize_t xgene_edac_mc_err_inject_write(struct file *file,
+ const char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct mem_ctl_info *mci = file->private_data;
+ struct xgene_edac_mc_ctx *ctx = mci->pvt_info;
+ int i;
+
+ for (i = 0; i < MCU_MAX_RANK; i++) {
+ writel(MCU_ESRR_MULTUCERR_MASK | MCU_ESRR_BACKUCERR_MASK |
+ MCU_ESRR_DEMANDUCERR_MASK | MCU_ESRR_CERR_MASK,
+ ctx->mcu_csr + MCUESRRA0 + i * MCU_RANK_STRIDE);
+ }
+ return count;
+}
+
+static const struct file_operations xgene_edac_mc_debug_inject_fops = {
+ .open = simple_open,
+ .write = xgene_edac_mc_err_inject_write,
+ .llseek = generic_file_llseek,
+};
+
+static void xgene_edac_mc_create_debugfs_node(struct mem_ctl_info *mci)
+{
+ if (!IS_ENABLED(CONFIG_EDAC_DEBUG))
+ return;
+#ifdef CONFIG_EDAC_DEBUG
+ if (!mci->debugfs)
+ return;
+ debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci,
+ &xgene_edac_mc_debug_inject_fops);
+#endif
+}
+
+static void xgene_edac_mc_check(struct mem_ctl_info *mci)
+{
+ struct xgene_edac_mc_ctx *ctx = mci->pvt_info;
+ unsigned int pcp_hp_stat;
+ unsigned int pcp_lp_stat;
+ u32 reg;
+ u32 rank;
+ u32 bank;
+ u32 count;
+ u32 col_row;
+
+ xgene_edac_pcp_rd(ctx->edac, PCPHPERRINTSTS, &pcp_hp_stat);
+ xgene_edac_pcp_rd(ctx->edac, PCPLPERRINTSTS, &pcp_lp_stat);
+ if (!((MCU_UNCORR_ERR_MASK & pcp_hp_stat) ||
+ (MCU_CTL_ERR_MASK & pcp_hp_stat) ||
+ (MCU_CORR_ERR_MASK & pcp_lp_stat)))
+ return;
+
+ for (rank = 0; rank < MCU_MAX_RANK; rank++) {
+ reg = readl(ctx->mcu_csr + MCUESRR0 + rank * MCU_RANK_STRIDE);
+
+ /* Detect uncorrectable memory error */
+ if (reg & (MCU_ESRR_DEMANDUCERR_MASK |
+ MCU_ESRR_BACKUCERR_MASK)) {
+ /* Detected uncorrectable memory error */
+ edac_mc_chipset_printk(mci, KERN_ERR, "X-Gene",
+ "MCU uncorrectable error at rank %d\n", rank);
+
+ edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+ 1, 0, 0, 0, 0, 0, -1, mci->ctl_name, "");
+ }
+
+ /* Detect correctable memory error */
+ if (reg & MCU_ESRR_CERR_MASK) {
+ bank = readl(ctx->mcu_csr + MCUEBLRR0 +
+ rank * MCU_RANK_STRIDE);
+ col_row = readl(ctx->mcu_csr + MCUERCRR0 +
+ rank * MCU_RANK_STRIDE);
+ count = readl(ctx->mcu_csr + MCUSBECNT0 +
+ rank * MCU_RANK_STRIDE);
+ edac_mc_chipset_printk(mci, KERN_WARNING, "X-Gene",
+ "MCU correctable error at rank %d bank %d column %d row %d count %d\n",
+ rank, MCU_EBLRR_ERRBANK_RD(bank),
+ MCU_ERCRR_ERRCOL_RD(col_row),
+ MCU_ERCRR_ERRROW_RD(col_row),
+ MCU_SBECNT_COUNT(count));
+
+ edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+ 1, 0, 0, 0, 0, 0, -1, mci->ctl_name, "");
+ }
+
+ /* Clear all error registers */
+ writel(0x0, ctx->mcu_csr + MCUEBLRR0 + rank * MCU_RANK_STRIDE);
+ writel(0x0, ctx->mcu_csr + MCUERCRR0 + rank * MCU_RANK_STRIDE);
+ writel(0x0, ctx->mcu_csr + MCUSBECNT0 +
+ rank * MCU_RANK_STRIDE);
+ writel(reg, ctx->mcu_csr + MCUESRR0 + rank * MCU_RANK_STRIDE);
+ }
+
+ /* Detect memory controller error */
+ reg = readl(ctx->mcu_csr + MCUGESR);
+ if (reg) {
+ if (reg & MCU_GESR_ADDRNOMATCH_ERR_MASK)
+ edac_mc_chipset_printk(mci, KERN_WARNING, "X-Gene",
+ "MCU address miss-match error\n");
+ if (reg & MCU_GESR_ADDRMULTIMATCH_ERR_MASK)
+ edac_mc_chipset_printk(mci, KERN_WARNING, "X-Gene",
+ "MCU address multi-match error\n");
+
+ writel(reg, ctx->mcu_csr + MCUGESR);
+ }
+}
+
+static void xgene_edac_mc_irq_ctl(struct mem_ctl_info *mci, bool enable)
+{
+ struct xgene_edac_mc_ctx *ctx = mci->pvt_info;
+ unsigned int val;
+
+ if (edac_op_state != EDAC_OPSTATE_INT)
+ return;
+
+ mutex_lock(&ctx->edac->mc_lock);
+
+ /*
+ * As there is only single bit for enable error and interrupt mask,
+ * we must only enable top level interrupt after all MCUs are
+ * registered. Otherwise, if there is an error and the corresponding
+ * MCU has not registered, the interrupt will never get cleared. To
+ * determine all MCU have registered, we will keep track of active
+ * MCUs and registered MCUs.
+ */
+ if (enable) {
+ /* Set registered MCU bit */
+ ctx->edac->mc_registered_mask |= 1 << ctx->mcu_id;
+
+ /* Enable interrupt after all active MCU registered */
+ if (ctx->edac->mc_registered_mask ==
+ ctx->edac->mc_active_mask) {
+ /* Enable memory controller top level interrupt */
+ xgene_edac_pcp_clrbits(ctx->edac, PCPHPERRINTMSK,
+ MCU_UNCORR_ERR_MASK |
+ MCU_CTL_ERR_MASK);
+ xgene_edac_pcp_clrbits(ctx->edac, PCPLPERRINTMSK,
+ MCU_CORR_ERR_MASK);
+ }
+
+ /* Enable MCU interrupt and error reporting */
+ val = readl(ctx->mcu_csr + MCUGECR);
+ val |= MCU_GECR_DEMANDUCINTREN_MASK |
+ MCU_GECR_BACKUCINTREN_MASK |
+ MCU_GECR_CINTREN_MASK |
+ MUC_GECR_MCUADDRERREN_MASK;
+ writel(val, ctx->mcu_csr + MCUGECR);
+ } else {
+ /* Disable MCU interrupt */
+ val = readl(ctx->mcu_csr + MCUGECR);
+ val &= ~(MCU_GECR_DEMANDUCINTREN_MASK |
+ MCU_GECR_BACKUCINTREN_MASK |
+ MCU_GECR_CINTREN_MASK |
+ MUC_GECR_MCUADDRERREN_MASK);
+ writel(val, ctx->mcu_csr + MCUGECR);
+
+ /* Disable memory controller top level interrupt */
+ xgene_edac_pcp_setbits(ctx->edac, PCPHPERRINTMSK,
+ MCU_UNCORR_ERR_MASK | MCU_CTL_ERR_MASK);
+ xgene_edac_pcp_setbits(ctx->edac, PCPLPERRINTMSK,
+ MCU_CORR_ERR_MASK);
+
+ /* Clear registered MCU bit */
+ ctx->edac->mc_registered_mask &= ~(1 << ctx->mcu_id);
+ }
+
+ mutex_unlock(&ctx->edac->mc_lock);
+}
+
+static int xgene_edac_mc_is_active(struct xgene_edac_mc_ctx *ctx, int mc_idx)
+{
+ unsigned int reg;
+ u32 mcu_mask;
+
+ if (regmap_read(ctx->edac->csw_map, CSW_CSWCR, &reg))
+ return 0;
+
+ if (reg & CSW_CSWCR_DUALMCB_MASK) {
+ /*
+ * Dual MCB active - Determine if all 4 active or just MCU0
+ * and MCU2 active
+ */
+ if (regmap_read(ctx->edac->mcbb_map, MCBADDRMR, &reg))
+ return 0;
+ mcu_mask = (reg & MCBADDRMR_DUALMCU_MODE_MASK) ? 0xF : 0x5;
+ } else {
+ /*
+ * Single MCB active - Determine if MCU0/MCU1 or just MCU0
+ * active
+ */
+ if (regmap_read(ctx->edac->mcba_map, MCBADDRMR, &reg))
+ return 0;
+ mcu_mask = (reg & MCBADDRMR_DUALMCU_MODE_MASK) ? 0x3 : 0x1;
+ }
+
+ /* Save active MC mask if hasn't set already */
+ if (!ctx->edac->mc_active_mask)
+ ctx->edac->mc_active_mask = mcu_mask;
+
+ return (mcu_mask & (1 << mc_idx)) ? 1 : 0;
+}
+
+static int xgene_edac_mc_add(struct xgene_edac *edac, struct device_node *np)
+{
+ struct mem_ctl_info *mci;
+ struct edac_mc_layer layers[2];
+ struct xgene_edac_mc_ctx tmp_ctx;
+ struct xgene_edac_mc_ctx *ctx;
+ struct resource res;
+ int rc;
+
+ memset(&tmp_ctx, 0, sizeof(tmp_ctx));
+ tmp_ctx.edac = edac;
+
+ if (!devres_open_group(edac->dev, xgene_edac_mc_add, GFP_KERNEL))
+ return -ENOMEM;
+
+ rc = of_address_to_resource(np, 0, &res);
+ if (rc < 0) {
+ dev_err(edac->dev, "no MCU resource address\n");
+ goto err_group;
+ }
+ tmp_ctx.mcu_csr = devm_ioremap_resource(edac->dev, &res);
+ if (IS_ERR(tmp_ctx.mcu_csr)) {
+ dev_err(edac->dev, "unable to map MCU resource\n");
+ rc = PTR_ERR(tmp_ctx.mcu_csr);
+ goto err_group;
+ }
+
+ /* Ignore non-active MCU */
+ if (of_property_read_u32(np, "memory-controller", &tmp_ctx.mcu_id)) {
+ dev_err(edac->dev, "no memory-controller property\n");
+ rc = -ENODEV;
+ goto err_group;
+ }
+ if (!xgene_edac_mc_is_active(&tmp_ctx, tmp_ctx.mcu_id)) {
+ rc = -ENODEV;
+ goto err_group;
+ }
+
+ layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+ layers[0].size = 4;
+ layers[0].is_virt_csrow = true;
+ layers[1].type = EDAC_MC_LAYER_CHANNEL;
+ layers[1].size = 2;
+ layers[1].is_virt_csrow = false;
+ mci = edac_mc_alloc(tmp_ctx.mcu_id, ARRAY_SIZE(layers), layers,
+ sizeof(*ctx));
+ if (!mci) {
+ rc = -ENOMEM;
+ goto err_group;
+ }
+
+ ctx = mci->pvt_info;
+ *ctx = tmp_ctx; /* Copy over resource value */
+ ctx->name = "xgene_edac_mc_err";
+ ctx->mci = mci;
+ mci->pdev = &mci->dev;
+ mci->ctl_name = ctx->name;
+ mci->dev_name = ctx->name;
+
+ mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_RDDR2 | MEM_FLAG_RDDR3 |
+ MEM_FLAG_DDR | MEM_FLAG_DDR2 | MEM_FLAG_DDR3;
+ mci->edac_ctl_cap = EDAC_FLAG_SECDED;
+ mci->edac_cap = EDAC_FLAG_SECDED;
+ mci->mod_name = EDAC_MOD_STR;
+ mci->mod_ver = "0.1";
+ mci->ctl_page_to_phys = NULL;
+ mci->scrub_cap = SCRUB_FLAG_HW_SRC;
+ mci->scrub_mode = SCRUB_HW_SRC;
+
+ if (edac_op_state == EDAC_OPSTATE_POLL)
+ mci->edac_check = xgene_edac_mc_check;
+
+ if (edac_mc_add_mc(mci)) {
+ dev_err(edac->dev, "edac_mc_add_mc failed\n");
+ rc = -EINVAL;
+ goto err_free;
+ }
+
+ xgene_edac_mc_create_debugfs_node(mci);
+
+ list_add(&ctx->next, &edac->mcus);
+
+ xgene_edac_mc_irq_ctl(mci, true);
+
+ devres_remove_group(edac->dev, xgene_edac_mc_add);
+
+ dev_info(edac->dev, "X-Gene EDAC MC registered\n");
+ return 0;
+
+err_free:
+ edac_mc_free(mci);
+err_group:
+ devres_release_group(edac->dev, xgene_edac_mc_add);
+ return rc;
+}
+
+static int xgene_edac_mc_remove(struct xgene_edac_mc_ctx *mcu)
+{
+ xgene_edac_mc_irq_ctl(mcu->mci, false);
+ edac_mc_del_mc(&mcu->mci->dev);
+ edac_mc_free(mcu->mci);
+ return 0;
+}
+
+/* CPU L1/L2 error CSR */
+#define MAX_CPU_PER_PMD 2
+#define CPU_CSR_STRIDE 0x00100000
+#define CPU_L2C_PAGE 0x000D0000
+#define CPU_MEMERR_L2C_PAGE 0x000E0000
+#define CPU_MEMERR_CPU_PAGE 0x000F0000
+
+#define MEMERR_CPU_ICFECR_PAGE_OFFSET 0x0000
+#define MEMERR_CPU_ICFESR_PAGE_OFFSET 0x0004
+#define MEMERR_CPU_ICFESR_ERRWAY_RD(src) (((src) & 0xFF000000) >> 24)
+#define MEMERR_CPU_ICFESR_ERRINDEX_RD(src) (((src) & 0x003F0000) >> 16)
+#define MEMERR_CPU_ICFESR_ERRINFO_RD(src) (((src) & 0x0000FF00) >> 8)
+#define MEMERR_CPU_ICFESR_ERRTYPE_RD(src) (((src) & 0x00000070) >> 4)
+#define MEMERR_CPU_ICFESR_MULTCERR_MASK BIT(2)
+#define MEMERR_CPU_ICFESR_CERR_MASK BIT(0)
+#define MEMERR_CPU_LSUESR_PAGE_OFFSET 0x000c
+#define MEMERR_CPU_LSUESR_ERRWAY_RD(src) (((src) & 0xFF000000) >> 24)
+#define MEMERR_CPU_LSUESR_ERRINDEX_RD(src) (((src) & 0x003F0000) >> 16)
+#define MEMERR_CPU_LSUESR_ERRINFO_RD(src) (((src) & 0x0000FF00) >> 8)
+#define MEMERR_CPU_LSUESR_ERRTYPE_RD(src) (((src) & 0x00000070) >> 4)
+#define MEMERR_CPU_LSUESR_MULTCERR_MASK BIT(2)
+#define MEMERR_CPU_LSUESR_CERR_MASK BIT(0)
+#define MEMERR_CPU_LSUECR_PAGE_OFFSET 0x0008
+#define MEMERR_CPU_MMUECR_PAGE_OFFSET 0x0010
+#define MEMERR_CPU_MMUESR_PAGE_OFFSET 0x0014
+#define MEMERR_CPU_MMUESR_ERRWAY_RD(src) (((src) & 0xFF000000) >> 24)
+#define MEMERR_CPU_MMUESR_ERRINDEX_RD(src) (((src) & 0x007F0000) >> 16)
+#define MEMERR_CPU_MMUESR_ERRINFO_RD(src) (((src) & 0x0000FF00) >> 8)
+#define MEMERR_CPU_MMUESR_ERRREQSTR_LSU_MASK BIT(7)
+#define MEMERR_CPU_MMUESR_ERRTYPE_RD(src) (((src) & 0x00000070) >> 4)
+#define MEMERR_CPU_MMUESR_MULTCERR_MASK BIT(2)
+#define MEMERR_CPU_MMUESR_CERR_MASK BIT(0)
+#define MEMERR_CPU_ICFESRA_PAGE_OFFSET 0x0804
+#define MEMERR_CPU_LSUESRA_PAGE_OFFSET 0x080c
+#define MEMERR_CPU_MMUESRA_PAGE_OFFSET 0x0814
+
+#define MEMERR_L2C_L2ECR_PAGE_OFFSET 0x0000
+#define MEMERR_L2C_L2ESR_PAGE_OFFSET 0x0004
+#define MEMERR_L2C_L2ESR_ERRSYN_RD(src) (((src) & 0xFF000000) >> 24)
+#define MEMERR_L2C_L2ESR_ERRWAY_RD(src) (((src) & 0x00FC0000) >> 18)
+#define MEMERR_L2C_L2ESR_ERRCPU_RD(src) (((src) & 0x00020000) >> 17)
+#define MEMERR_L2C_L2ESR_ERRGROUP_RD(src) (((src) & 0x0000E000) >> 13)
+#define MEMERR_L2C_L2ESR_ERRACTION_RD(src) (((src) & 0x00001C00) >> 10)
+#define MEMERR_L2C_L2ESR_ERRTYPE_RD(src) (((src) & 0x00000300) >> 8)
+#define MEMERR_L2C_L2ESR_MULTUCERR_MASK BIT(3)
+#define MEMERR_L2C_L2ESR_MULTICERR_MASK BIT(2)
+#define MEMERR_L2C_L2ESR_UCERR_MASK BIT(1)
+#define MEMERR_L2C_L2ESR_ERR_MASK BIT(0)
+#define MEMERR_L2C_L2EALR_PAGE_OFFSET 0x0008
+#define CPUX_L2C_L2RTOCR_PAGE_OFFSET 0x0010
+#define MEMERR_L2C_L2EAHR_PAGE_OFFSET 0x000c
+#define CPUX_L2C_L2RTOSR_PAGE_OFFSET 0x0014
+#define MEMERR_L2C_L2RTOSR_MULTERR_MASK BIT(1)
+#define MEMERR_L2C_L2RTOSR_ERR_MASK BIT(0)
+#define CPUX_L2C_L2RTOALR_PAGE_OFFSET 0x0018
+#define CPUX_L2C_L2RTOAHR_PAGE_OFFSET 0x001c
+#define MEMERR_L2C_L2ESRA_PAGE_OFFSET 0x0804
+
+/*
+ * Processor Module Domain (PMD) context - Context for a pair of processsors.
+ * Each PMD consists of 2 CPUs and a shared L2 cache. Each CPU consists of
+ * its own L1 cache.
+ */
+struct xgene_edac_pmd_ctx {
+ struct list_head next;
+ struct device ddev;
+ char *name;
+ struct xgene_edac *edac;
+ struct edac_device_ctl_info *edac_dev;
+ void __iomem *pmd_csr;
+ u32 pmd;
+ int version;
+};
+
+static void xgene_edac_pmd_l1_check(struct edac_device_ctl_info *edac_dev,
+ int cpu_idx)
+{
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ void __iomem *pg_f;
+ u32 val;
+
+ pg_f = ctx->pmd_csr + cpu_idx * CPU_CSR_STRIDE + CPU_MEMERR_CPU_PAGE;
+
+ val = readl(pg_f + MEMERR_CPU_ICFESR_PAGE_OFFSET);
+ if (val) {
+ dev_err(edac_dev->dev,
+ "CPU%d L1 memory error ICF 0x%08X Way 0x%02X Index 0x%02X Info 0x%02X\n",
+ ctx->pmd * MAX_CPU_PER_PMD + cpu_idx, val,
+ MEMERR_CPU_ICFESR_ERRWAY_RD(val),
+ MEMERR_CPU_ICFESR_ERRINDEX_RD(val),
+ MEMERR_CPU_ICFESR_ERRINFO_RD(val));
+ if (val & MEMERR_CPU_ICFESR_CERR_MASK)
+ dev_err(edac_dev->dev,
+ "One or more correctable error\n");
+ if (val & MEMERR_CPU_ICFESR_MULTCERR_MASK)
+ dev_err(edac_dev->dev, "Multiple correctable error\n");
+ switch (MEMERR_CPU_ICFESR_ERRTYPE_RD(val)) {
+ case 1:
+ dev_err(edac_dev->dev, "L1 TLB multiple hit\n");
+ break;
+ case 2:
+ dev_err(edac_dev->dev, "Way select multiple hit\n");
+ break;
+ case 3:
+ dev_err(edac_dev->dev, "Physical tag parity error\n");
+ break;
+ case 4:
+ case 5:
+ dev_err(edac_dev->dev, "L1 data parity error\n");
+ break;
+ case 6:
+ dev_err(edac_dev->dev, "L1 pre-decode parity error\n");
+ break;
+ }
+
+ /* Clear any HW errors */
+ writel(val, pg_f + MEMERR_CPU_ICFESR_PAGE_OFFSET);
+
+ if (val & (MEMERR_CPU_ICFESR_CERR_MASK |
+ MEMERR_CPU_ICFESR_MULTCERR_MASK))
+ edac_device_handle_ce(edac_dev, 0, 0,
+ edac_dev->ctl_name);
+ }
+
+ val = readl(pg_f + MEMERR_CPU_LSUESR_PAGE_OFFSET);
+ if (val) {
+ dev_err(edac_dev->dev,
+ "CPU%d memory error LSU 0x%08X Way 0x%02X Index 0x%02X Info 0x%02X\n",
+ ctx->pmd * MAX_CPU_PER_PMD + cpu_idx, val,
+ MEMERR_CPU_LSUESR_ERRWAY_RD(val),
+ MEMERR_CPU_LSUESR_ERRINDEX_RD(val),
+ MEMERR_CPU_LSUESR_ERRINFO_RD(val));
+ if (val & MEMERR_CPU_LSUESR_CERR_MASK)
+ dev_err(edac_dev->dev,
+ "One or more correctable error\n");
+ if (val & MEMERR_CPU_LSUESR_MULTCERR_MASK)
+ dev_err(edac_dev->dev, "Multiple correctable error\n");
+ switch (MEMERR_CPU_LSUESR_ERRTYPE_RD(val)) {
+ case 0:
+ dev_err(edac_dev->dev, "Load tag error\n");
+ break;
+ case 1:
+ dev_err(edac_dev->dev, "Load data error\n");
+ break;
+ case 2:
+ dev_err(edac_dev->dev, "WSL multihit error\n");
+ break;
+ case 3:
+ dev_err(edac_dev->dev, "Store tag error\n");
+ break;
+ case 4:
+ dev_err(edac_dev->dev,
+ "DTB multihit from load pipeline error\n");
+ break;
+ case 5:
+ dev_err(edac_dev->dev,
+ "DTB multihit from store pipeline error\n");
+ break;
+ }
+
+ /* Clear any HW errors */
+ writel(val, pg_f + MEMERR_CPU_LSUESR_PAGE_OFFSET);
+
+ if (val & (MEMERR_CPU_LSUESR_CERR_MASK |
+ MEMERR_CPU_LSUESR_MULTCERR_MASK))
+ edac_device_handle_ce(edac_dev, 0, 0,
+ edac_dev->ctl_name);
+ }
+
+ val = readl(pg_f + MEMERR_CPU_MMUESR_PAGE_OFFSET);
+ if (val) {
+ dev_err(edac_dev->dev,
+ "CPU%d memory error MMU 0x%08X Way 0x%02X Index 0x%02X Info 0x%02X %s\n",
+ ctx->pmd * MAX_CPU_PER_PMD + cpu_idx, val,
+ MEMERR_CPU_MMUESR_ERRWAY_RD(val),
+ MEMERR_CPU_MMUESR_ERRINDEX_RD(val),
+ MEMERR_CPU_MMUESR_ERRINFO_RD(val),
+ val & MEMERR_CPU_MMUESR_ERRREQSTR_LSU_MASK ? "LSU" :
+ "ICF");
+ if (val & MEMERR_CPU_MMUESR_CERR_MASK)
+ dev_err(edac_dev->dev,
+ "One or more correctable error\n");
+ if (val & MEMERR_CPU_MMUESR_MULTCERR_MASK)
+ dev_err(edac_dev->dev, "Multiple correctable error\n");
+ switch (MEMERR_CPU_MMUESR_ERRTYPE_RD(val)) {
+ case 0:
+ dev_err(edac_dev->dev, "Stage 1 UTB hit error\n");
+ break;
+ case 1:
+ dev_err(edac_dev->dev, "Stage 1 UTB miss error\n");
+ break;
+ case 2:
+ dev_err(edac_dev->dev, "Stage 1 UTB allocate error\n");
+ break;
+ case 3:
+ dev_err(edac_dev->dev,
+ "TMO operation single bank error\n");
+ break;
+ case 4:
+ dev_err(edac_dev->dev, "Stage 2 UTB error\n");
+ break;
+ case 5:
+ dev_err(edac_dev->dev, "Stage 2 UTB miss error\n");
+ break;
+ case 6:
+ dev_err(edac_dev->dev, "Stage 2 UTB allocate error\n");
+ break;
+ case 7:
+ dev_err(edac_dev->dev,
+ "TMO operation multiple bank error\n");
+ break;
+ }
+
+ /* Clear any HW errors */
+ writel(val, pg_f + MEMERR_CPU_MMUESR_PAGE_OFFSET);
+
+ edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name);
+ }
+}
+
+static void xgene_edac_pmd_l2_check(struct edac_device_ctl_info *edac_dev)
+{
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ void __iomem *pg_d;
+ void __iomem *pg_e;
+ u32 val_hi;
+ u32 val_lo;
+ u32 val;
+
+ /* Check L2 */
+ pg_e = ctx->pmd_csr + CPU_MEMERR_L2C_PAGE;
+ val = readl(pg_e + MEMERR_L2C_L2ESR_PAGE_OFFSET);
+ if (val) {
+ val_lo = readl(pg_e + MEMERR_L2C_L2EALR_PAGE_OFFSET);
+ val_hi = readl(pg_e + MEMERR_L2C_L2EAHR_PAGE_OFFSET);
+ dev_err(edac_dev->dev,
+ "PMD%d memory error L2C L2ESR 0x%08X @ 0x%08X.%08X\n",
+ ctx->pmd, val, val_hi, val_lo);
+ dev_err(edac_dev->dev,
+ "ErrSyndrome 0x%02X ErrWay 0x%02X ErrCpu %d ErrGroup 0x%02X ErrAction 0x%02X\n",
+ MEMERR_L2C_L2ESR_ERRSYN_RD(val),
+ MEMERR_L2C_L2ESR_ERRWAY_RD(val),
+ MEMERR_L2C_L2ESR_ERRCPU_RD(val),
+ MEMERR_L2C_L2ESR_ERRGROUP_RD(val),
+ MEMERR_L2C_L2ESR_ERRACTION_RD(val));
+
+ if (val & MEMERR_L2C_L2ESR_ERR_MASK)
+ dev_err(edac_dev->dev,
+ "One or more correctable error\n");
+ if (val & MEMERR_L2C_L2ESR_MULTICERR_MASK)
+ dev_err(edac_dev->dev, "Multiple correctable error\n");
+ if (val & MEMERR_L2C_L2ESR_UCERR_MASK)
+ dev_err(edac_dev->dev,
+ "One or more uncorrectable error\n");
+ if (val & MEMERR_L2C_L2ESR_MULTUCERR_MASK)
+ dev_err(edac_dev->dev,
+ "Multiple uncorrectable error\n");
+
+ switch (MEMERR_L2C_L2ESR_ERRTYPE_RD(val)) {
+ case 0:
+ dev_err(edac_dev->dev, "Outbound SDB parity error\n");
+ break;
+ case 1:
+ dev_err(edac_dev->dev, "Inbound SDB parity error\n");
+ break;
+ case 2:
+ dev_err(edac_dev->dev, "Tag ECC error\n");
+ break;
+ case 3:
+ dev_err(edac_dev->dev, "Data ECC error\n");
+ break;
+ }
+
+ /* Clear any HW errors */
+ writel(val, pg_e + MEMERR_L2C_L2ESR_PAGE_OFFSET);
+
+ if (val & (MEMERR_L2C_L2ESR_ERR_MASK |
+ MEMERR_L2C_L2ESR_MULTICERR_MASK))
+ edac_device_handle_ce(edac_dev, 0, 0,
+ edac_dev->ctl_name);
+ if (val & (MEMERR_L2C_L2ESR_UCERR_MASK |
+ MEMERR_L2C_L2ESR_MULTUCERR_MASK))
+ edac_device_handle_ue(edac_dev, 0, 0,
+ edac_dev->ctl_name);
+ }
+
+ /* Check if any memory request timed out on L2 cache */
+ pg_d = ctx->pmd_csr + CPU_L2C_PAGE;
+ val = readl(pg_d + CPUX_L2C_L2RTOSR_PAGE_OFFSET);
+ if (val) {
+ val_lo = readl(pg_d + CPUX_L2C_L2RTOALR_PAGE_OFFSET);
+ val_hi = readl(pg_d + CPUX_L2C_L2RTOAHR_PAGE_OFFSET);
+ dev_err(edac_dev->dev,
+ "PMD%d L2C error L2C RTOSR 0x%08X @ 0x%08X.%08X\n",
+ ctx->pmd, val, val_hi, val_lo);
+ writel(val, pg_d + CPUX_L2C_L2RTOSR_PAGE_OFFSET);
+ }
+}
+
+static void xgene_edac_pmd_check(struct edac_device_ctl_info *edac_dev)
+{
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ unsigned int pcp_hp_stat;
+ int i;
+
+ xgene_edac_pcp_rd(ctx->edac, PCPHPERRINTSTS, &pcp_hp_stat);
+ if (!((PMD0_MERR_MASK << ctx->pmd) & pcp_hp_stat))
+ return;
+
+ /* Check CPU L1 error */
+ for (i = 0; i < MAX_CPU_PER_PMD; i++)
+ xgene_edac_pmd_l1_check(edac_dev, i);
+
+ /* Check CPU L2 error */
+ xgene_edac_pmd_l2_check(edac_dev);
+}
+
+static void xgene_edac_pmd_cpu_hw_cfg(struct edac_device_ctl_info *edac_dev,
+ int cpu)
+{
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ void __iomem *pg_f = ctx->pmd_csr + cpu * CPU_CSR_STRIDE +
+ CPU_MEMERR_CPU_PAGE;
+
+ /*
+ * Enable CPU memory error:
+ * MEMERR_CPU_ICFESRA, MEMERR_CPU_LSUESRA, and MEMERR_CPU_MMUESRA
+ */
+ writel(0x00000301, pg_f + MEMERR_CPU_ICFECR_PAGE_OFFSET);
+ writel(0x00000301, pg_f + MEMERR_CPU_LSUECR_PAGE_OFFSET);
+ writel(0x00000101, pg_f + MEMERR_CPU_MMUECR_PAGE_OFFSET);
+}
+
+static void xgene_edac_pmd_hw_cfg(struct edac_device_ctl_info *edac_dev)
+{
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ void __iomem *pg_d = ctx->pmd_csr + CPU_L2C_PAGE;
+ void __iomem *pg_e = ctx->pmd_csr + CPU_MEMERR_L2C_PAGE;
+
+ /* Enable PMD memory error - MEMERR_L2C_L2ECR and L2C_L2RTOCR */
+ writel(0x00000703, pg_e + MEMERR_L2C_L2ECR_PAGE_OFFSET);
+ /* Configure L2C HW request time out feature if supported */
+ if (ctx->version > 1)
+ writel(0x00000119, pg_d + CPUX_L2C_L2RTOCR_PAGE_OFFSET);
+}
+
+static void xgene_edac_pmd_hw_ctl(struct edac_device_ctl_info *edac_dev,
+ bool enable)
+{
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ int i;
+
+ /* Enable PMD error interrupt */
+ if (edac_dev->op_state == OP_RUNNING_INTERRUPT) {
+ if (enable)
+ xgene_edac_pcp_clrbits(ctx->edac, PCPHPERRINTMSK,
+ PMD0_MERR_MASK << ctx->pmd);
+ else
+ xgene_edac_pcp_setbits(ctx->edac, PCPHPERRINTMSK,
+ PMD0_MERR_MASK << ctx->pmd);
+ }
+
+ if (enable) {
+ xgene_edac_pmd_hw_cfg(edac_dev);
+
+ /* Two CPUs per a PMD */
+ for (i = 0; i < MAX_CPU_PER_PMD; i++)
+ xgene_edac_pmd_cpu_hw_cfg(edac_dev, i);
+ }
+}
+
+static ssize_t xgene_edac_pmd_l1_inject_ctrl_write(struct file *file,
+ const char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct edac_device_ctl_info *edac_dev = file->private_data;
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ void __iomem *cpux_pg_f;
+ int i;
+
+ for (i = 0; i < MAX_CPU_PER_PMD; i++) {
+ cpux_pg_f = ctx->pmd_csr + i * CPU_CSR_STRIDE +
+ CPU_MEMERR_CPU_PAGE;
+
+ writel(MEMERR_CPU_ICFESR_MULTCERR_MASK |
+ MEMERR_CPU_ICFESR_CERR_MASK,
+ cpux_pg_f + MEMERR_CPU_ICFESRA_PAGE_OFFSET);
+ writel(MEMERR_CPU_LSUESR_MULTCERR_MASK |
+ MEMERR_CPU_LSUESR_CERR_MASK,
+ cpux_pg_f + MEMERR_CPU_LSUESRA_PAGE_OFFSET);
+ writel(MEMERR_CPU_MMUESR_MULTCERR_MASK |
+ MEMERR_CPU_MMUESR_CERR_MASK,
+ cpux_pg_f + MEMERR_CPU_MMUESRA_PAGE_OFFSET);
+ }
+ return count;
+}
+
+static ssize_t xgene_edac_pmd_l2_inject_ctrl_write(struct file *file,
+ const char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct edac_device_ctl_info *edac_dev = file->private_data;
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ void __iomem *pg_e = ctx->pmd_csr + CPU_MEMERR_L2C_PAGE;
+
+ writel(MEMERR_L2C_L2ESR_MULTUCERR_MASK |
+ MEMERR_L2C_L2ESR_MULTICERR_MASK |
+ MEMERR_L2C_L2ESR_UCERR_MASK |
+ MEMERR_L2C_L2ESR_ERR_MASK,
+ pg_e + MEMERR_L2C_L2ESRA_PAGE_OFFSET);
+ return count;
+}
+
+static const struct file_operations xgene_edac_pmd_debug_inject_fops[] = {
+ {
+ .open = simple_open,
+ .write = xgene_edac_pmd_l1_inject_ctrl_write,
+ .llseek = generic_file_llseek, },
+ {
+ .open = simple_open,
+ .write = xgene_edac_pmd_l2_inject_ctrl_write,
+ .llseek = generic_file_llseek, },
+ { }
+};
+
+static void xgene_edac_pmd_create_debugfs_nodes(
+ struct edac_device_ctl_info *edac_dev)
+{
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ struct dentry *edac_debugfs;
+ char name[30];
+
+ if (!IS_ENABLED(CONFIG_EDAC_DEBUG))
+ return;
+
+ /*
+ * Todo: Switch to common EDAC debug file system for edac device
+ * when available.
+ */
+ if (!ctx->edac->dfs) {
+ ctx->edac->dfs = debugfs_create_dir(edac_dev->dev->kobj.name,
+ NULL);
+ if (!ctx->edac->dfs)
+ return;
+ }
+ sprintf(name, "PMD%d", ctx->pmd);
+ edac_debugfs = debugfs_create_dir(name, ctx->edac->dfs);
+ if (!edac_debugfs)
+ return;
+
+ debugfs_create_file("l1_inject_ctrl", S_IWUSR, edac_debugfs, edac_dev,
+ &xgene_edac_pmd_debug_inject_fops[0]);
+ debugfs_create_file("l2_inject_ctrl", S_IWUSR, edac_debugfs, edac_dev,
+ &xgene_edac_pmd_debug_inject_fops[1]);
+}
+
+static int xgene_edac_pmd_available(u32 efuse, int pmd)
+{
+ return (efuse & (1 << pmd)) ? 0 : 1;
+}
+
+static int xgene_edac_pmd_add(struct xgene_edac *edac, struct device_node *np,
+ int version)
+{
+ struct edac_device_ctl_info *edac_dev;
+ struct xgene_edac_pmd_ctx *ctx;
+ struct resource res;
+ char edac_name[10];
+ u32 pmd;
+ int rc;
+ u32 val;
+
+ if (!devres_open_group(edac->dev, xgene_edac_pmd_add, GFP_KERNEL))
+ return -ENOMEM;
+
+ /* Determine if this PMD is disabled */
+ if (of_property_read_u32(np, "pmd-controller", &pmd)) {
+ dev_err(edac->dev, "no pmd-controller property\n");
+ rc = -ENODEV;
+ goto err_group;
+ }
+ rc = regmap_read(edac->efuse_map, 0, &val);
+ if (rc)
+ goto err_group;
+ if (!xgene_edac_pmd_available(val, pmd)) {
+ rc = -ENODEV;
+ goto err_group;
+ }
+
+ sprintf(edac_name, "l2c%d", pmd);
+ edac_dev = edac_device_alloc_ctl_info(sizeof(*ctx),
+ edac_name, 1, "l2c", 1, 2, NULL,
+ 0, edac_device_alloc_index());
+ if (!edac_dev) {
+ rc = -ENOMEM;
+ goto err_group;
+ }
+
+ ctx = edac_dev->pvt_info;
+ ctx->name = "xgene_pmd_err";
+ ctx->pmd = pmd;
+ ctx->edac = edac;
+ ctx->edac_dev = edac_dev;
+ ctx->ddev = *edac->dev;
+ ctx->version = version;
+ edac_dev->dev = &ctx->ddev;
+ edac_dev->ctl_name = ctx->name;
+ edac_dev->dev_name = ctx->name;
+ edac_dev->mod_name = EDAC_MOD_STR;
+
+ rc = of_address_to_resource(np, 0, &res);
+ if (rc < 0) {
+ dev_err(edac->dev, "no PMD resource address\n");
+ goto err_free;
+ }
+ ctx->pmd_csr = devm_ioremap_resource(edac->dev, &res);
+ if (IS_ERR(ctx->pmd_csr)) {
+ dev_err(edac->dev,
+ "devm_ioremap_resource failed for PMD resource address\n");
+ rc = PTR_ERR(ctx->pmd_csr);
+ goto err_free;
+ }
+
+ if (edac_op_state == EDAC_OPSTATE_POLL)
+ edac_dev->edac_check = xgene_edac_pmd_check;
+
+ xgene_edac_pmd_create_debugfs_nodes(edac_dev);
+
+ rc = edac_device_add_device(edac_dev);
+ if (rc > 0) {
+ dev_err(edac->dev, "edac_device_add_device failed\n");
+ rc = -ENOMEM;
+ goto err_free;
+ }
+
+ if (edac_op_state == EDAC_OPSTATE_INT)
+ edac_dev->op_state = OP_RUNNING_INTERRUPT;
+
+ list_add(&ctx->next, &edac->pmds);
+
+ xgene_edac_pmd_hw_ctl(edac_dev, 1);
+
+ devres_remove_group(edac->dev, xgene_edac_pmd_add);
+
+ dev_info(edac->dev, "X-Gene EDAC PMD%d registered\n", ctx->pmd);
+ return 0;
+
+err_free:
+ edac_device_free_ctl_info(edac_dev);
+err_group:
+ devres_release_group(edac->dev, xgene_edac_pmd_add);
+ return rc;
+}
+
+static int xgene_edac_pmd_remove(struct xgene_edac_pmd_ctx *pmd)
+{
+ struct edac_device_ctl_info *edac_dev = pmd->edac_dev;
+
+ xgene_edac_pmd_hw_ctl(edac_dev, 0);
+ edac_device_del_device(edac_dev->dev);
+ edac_device_free_ctl_info(edac_dev);
+ return 0;
+}
+
+static irqreturn_t xgene_edac_isr(int irq, void *dev_id)
+{
+ struct xgene_edac *ctx = dev_id;
+ struct xgene_edac_pmd_ctx *pmd;
+ unsigned int pcp_hp_stat;
+ unsigned int pcp_lp_stat;
+
+ xgene_edac_pcp_rd(ctx, PCPHPERRINTSTS, &pcp_hp_stat);
+ xgene_edac_pcp_rd(ctx, PCPLPERRINTSTS, &pcp_lp_stat);
+ if ((MCU_UNCORR_ERR_MASK & pcp_hp_stat) ||
+ (MCU_CTL_ERR_MASK & pcp_hp_stat) ||
+ (MCU_CORR_ERR_MASK & pcp_lp_stat)) {
+ struct xgene_edac_mc_ctx *mcu;
+
+ list_for_each_entry(mcu, &ctx->mcus, next) {
+ xgene_edac_mc_check(mcu->mci);
+ }
+ }
+
+ list_for_each_entry(pmd, &ctx->pmds, next) {
+ if ((PMD0_MERR_MASK << pmd->pmd) & pcp_hp_stat)
+ xgene_edac_pmd_check(pmd->edac_dev);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int xgene_edac_probe(struct platform_device *pdev)
+{
+ struct xgene_edac *edac;
+ struct device_node *child;
+ struct resource *res;
+ int rc;
+
+ edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL);
+ if (!edac)
+ return -ENOMEM;
+
+ edac->dev = &pdev->dev;
+ platform_set_drvdata(pdev, edac);
+ INIT_LIST_HEAD(&edac->mcus);
+ INIT_LIST_HEAD(&edac->pmds);
+ spin_lock_init(&edac->lock);
+ mutex_init(&edac->mc_lock);
+
+ edac->csw_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "regmap-csw");
+ if (IS_ERR(edac->csw_map)) {
+ dev_err(edac->dev, "unable to get syscon regmap csw\n");
+ rc = PTR_ERR(edac->csw_map);
+ goto out_err;
+ }
+
+ edac->mcba_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "regmap-mcba");
+ if (IS_ERR(edac->mcba_map)) {
+ dev_err(edac->dev, "unable to get syscon regmap mcba\n");
+ rc = PTR_ERR(edac->mcba_map);
+ goto out_err;
+ }
+
+ edac->mcbb_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "regmap-mcbb");
+ if (IS_ERR(edac->mcbb_map)) {
+ dev_err(edac->dev, "unable to get syscon regmap mcbb\n");
+ rc = PTR_ERR(edac->mcbb_map);
+ goto out_err;
+ }
+ edac->efuse_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "regmap-efuse");
+ if (IS_ERR(edac->efuse_map)) {
+ dev_err(edac->dev, "unable to get syscon regmap efuse\n");
+ rc = PTR_ERR(edac->efuse_map);
+ goto out_err;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ edac->pcp_csr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(edac->pcp_csr)) {
+ dev_err(&pdev->dev, "no PCP resource address\n");
+ rc = PTR_ERR(edac->pcp_csr);
+ goto out_err;
+ }
+
+ if (edac_op_state == EDAC_OPSTATE_INT) {
+ int irq;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "No IRQ resource\n");
+ rc = -EINVAL;
+ goto out_err;
+ }
+ rc = devm_request_irq(&pdev->dev, irq,
+ xgene_edac_isr, IRQF_SHARED,
+ dev_name(&pdev->dev), edac);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "Could not request IRQ %d\n", irq);
+ goto out_err;
+ }
+ }
+ }
+
+ for_each_child_of_node(pdev->dev.of_node, child) {
+ if (!of_device_is_available(child))
+ continue;
+ if (of_device_is_compatible(child, "apm,xgene-edac-mc"))
+ xgene_edac_mc_add(edac, child);
+ if (of_device_is_compatible(child, "apm,xgene-edac-pmd"))
+ xgene_edac_pmd_add(edac, child, 1);
+ if (of_device_is_compatible(child, "apm,xgene-edac-pmd-v2"))
+ xgene_edac_pmd_add(edac, child, 2);
+ }
+
+ return 0;
+
+out_err:
+ return rc;
+}
+
+static int xgene_edac_remove(struct platform_device *pdev)
+{
+ struct xgene_edac *edac = dev_get_drvdata(&pdev->dev);
+ struct xgene_edac_mc_ctx *mcu;
+ struct xgene_edac_mc_ctx *temp_mcu;
+ struct xgene_edac_pmd_ctx *pmd;
+ struct xgene_edac_pmd_ctx *temp_pmd;
+
+ list_for_each_entry_safe(mcu, temp_mcu, &edac->mcus, next) {
+ xgene_edac_mc_remove(mcu);
+ }
+
+ list_for_each_entry_safe(pmd, temp_pmd, &edac->pmds, next) {
+ xgene_edac_pmd_remove(pmd);
+ }
+ return 0;
+}
+
+static const struct of_device_id xgene_edac_of_match[] = {
+ { .compatible = "apm,xgene-edac" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, xgene_edac_of_match);
+
+static struct platform_driver xgene_edac_driver = {
+ .probe = xgene_edac_probe,
+ .remove = xgene_edac_remove,
+ .driver = {
+ .name = "xgene-edac",
+ .owner = THIS_MODULE,
+ .of_match_table = xgene_edac_of_match,
+ },
+};
+
+static int __init xgene_edac_init(void)
+{
+ int rc;
+
+ /* Make sure error reporting method is sane */
+ switch (edac_op_state) {
+ case EDAC_OPSTATE_POLL:
+ case EDAC_OPSTATE_INT:
+ break;
+ default:
+ edac_op_state = EDAC_OPSTATE_INT;
+ break;
+ }
+
+ rc = platform_driver_register(&xgene_edac_driver);
+ if (rc) {
+ edac_printk(KERN_ERR, EDAC_MOD_STR,
+ "EDAC fails to register\n");
+ goto reg_failed;
+ }
+
+ return 0;
+
+reg_failed:
+ return rc;
+}
+module_init(xgene_edac_init);
+
+static void __exit xgene_edac_exit(void)
+{
+ platform_driver_unregister(&xgene_edac_driver);
+}
+module_exit(xgene_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Feng Kan <fkan@apm.com>");
+MODULE_DESCRIPTION("APM X-Gene EDAC driver");
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state,
+ "EDAC error reporting state: 0=Poll, 2=Interrupt");
diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c
index a6e79225886d..8333f878919c 100644
--- a/drivers/gpio/gpio-bcm-kona.c
+++ b/drivers/gpio/gpio-bcm-kona.c
@@ -540,7 +540,7 @@ static void bcm_kona_gpio_irq_unmap(struct irq_domain *d, unsigned int irq)
irq_set_chip_data(irq, NULL);
}
-static struct irq_domain_ops bcm_kona_irq_ops = {
+static const struct irq_domain_ops bcm_kona_irq_ops = {
.map = bcm_kona_gpio_irq_map,
.unmap = bcm_kona_gpio_irq_unmap,
.xlate = irq_domain_xlate_twocell,
diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c
index 3cfcfc620c8e..fbf287307c4c 100644
--- a/drivers/gpio/gpio-em.c
+++ b/drivers/gpio/gpio-em.c
@@ -266,7 +266,7 @@ static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int irq,
return 0;
}
-static struct irq_domain_ops em_gio_irq_domain_ops = {
+static const struct irq_domain_ops em_gio_irq_domain_ops = {
.map = em_gio_irq_domain_map,
.xlate = irq_domain_xlate_twocell,
};
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
index 35a02770c8b0..0a8f7617e72e 100644
--- a/drivers/gpio/gpio-grgpio.c
+++ b/drivers/gpio/gpio-grgpio.c
@@ -332,7 +332,7 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
spin_unlock_irqrestore(&priv->bgc.lock, flags);
}
-static struct irq_domain_ops grgpio_irq_domain_ops = {
+static const struct irq_domain_ops grgpio_irq_domain_ops = {
.map = grgpio_irq_map,
.unmap = grgpio_irq_unmap,
};
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index a65b75161aa4..20aa66f34f6e 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -329,7 +329,7 @@ static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq,
return 0;
}
-static struct irq_domain_ops mpc8xxx_gpio_irq_ops = {
+static const struct irq_domain_ops mpc8xxx_gpio_irq_ops = {
.map = mpc8xxx_gpio_irq_map,
.xlate = irq_domain_xlate_twocell,
};
diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c
index bec397a60204..3fa22dade243 100644
--- a/drivers/gpio/gpio-sa1100.c
+++ b/drivers/gpio/gpio-sa1100.c
@@ -160,7 +160,7 @@ static int sa1100_gpio_irqdomain_map(struct irq_domain *d,
return 0;
}
-static struct irq_domain_ops sa1100_gpio_irqdomain_ops = {
+static const struct irq_domain_ops sa1100_gpio_irqdomain_ops = {
.map = sa1100_gpio_irqdomain_map,
.xlate = irq_domain_xlate_onetwocell,
};
diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c
index d8da36cd8123..65bc9f47a68e 100644
--- a/drivers/gpio/gpio-sodaville.c
+++ b/drivers/gpio/gpio-sodaville.c
@@ -125,7 +125,7 @@ static int sdv_xlate(struct irq_domain *h, struct device_node *node,
return 0;
}
-static struct irq_domain_ops irq_domain_sdv_ops = {
+static const struct irq_domain_ops irq_domain_sdv_ops = {
.xlate = sdv_xlate,
};
diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c
index 62c816af46e4..6eee3d385541 100644
--- a/drivers/infiniband/hw/cxgb4/provider.c
+++ b/drivers/infiniband/hw/cxgb4/provider.c
@@ -453,10 +453,10 @@ static int c4iw_get_mib(struct ib_device *ibdev,
cxgb4_get_tcp_stats(c4iw_dev->rdev.lldi.pdev, &v4, &v6);
memset(stats, 0, sizeof *stats);
- stats->iw.tcpInSegs = v4.tcpInSegs + v6.tcpInSegs;
- stats->iw.tcpOutSegs = v4.tcpOutSegs + v6.tcpOutSegs;
- stats->iw.tcpRetransSegs = v4.tcpRetransSegs + v6.tcpRetransSegs;
- stats->iw.tcpOutRsts = v4.tcpOutRsts + v6.tcpOutSegs;
+ stats->iw.tcpInSegs = v4.tcp_in_segs + v6.tcp_in_segs;
+ stats->iw.tcpOutSegs = v4.tcp_out_segs + v6.tcp_out_segs;
+ stats->iw.tcpRetransSegs = v4.tcp_retrans_segs + v6.tcp_retrans_segs;
+ stats->iw.tcpOutRsts = v4.tcp_out_rsts + v6.tcp_out_rsts;
return 0;
}
diff --git a/drivers/infiniband/hw/mlx4/alias_GUID.c b/drivers/infiniband/hw/mlx4/alias_GUID.c
index 0f00204d2ece..21cb41a60fe8 100644
--- a/drivers/infiniband/hw/mlx4/alias_GUID.c
+++ b/drivers/infiniband/hw/mlx4/alias_GUID.c
@@ -189,7 +189,7 @@ void mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev,
{
int i;
u64 guid_indexes;
- int slave_id;
+ int slave_id, slave_port;
enum slave_port_state new_state;
enum slave_port_state prev_state;
__be64 tmp_cur_ag, form_cache_ag;
@@ -217,6 +217,11 @@ void mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev,
slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ;
if (slave_id >= dev->dev->persist->num_vfs + 1)
return;
+
+ slave_port = mlx4_phys_to_slave_port(dev->dev, slave_id, port_num);
+ if (slave_port < 0) /* this port isn't available for the VF */
+ continue;
+
tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE];
form_cache_ag = get_cached_alias_guid(dev, port_num,
(NUM_ALIAS_GUID_IN_REC * block_num) + i);
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index 3e2dee46caa2..85a50df2f203 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -64,14 +64,6 @@ enum {
#define GUID_TBL_BLK_NUM_ENTRIES 8
#define GUID_TBL_BLK_SIZE (GUID_TBL_ENTRY_SIZE * GUID_TBL_BLK_NUM_ENTRIES)
-/* Counters should be saturate once they reach their maximum value */
-#define ASSIGN_32BIT_COUNTER(counter, value) do {\
- if ((value) > U32_MAX) \
- counter = cpu_to_be32(U32_MAX); \
- else \
- counter = cpu_to_be32(value); \
-} while (0)
-
struct mlx4_mad_rcv_buf {
struct ib_grh grh;
u8 payload[256];
@@ -830,31 +822,25 @@ static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
const struct ib_wc *in_wc, const struct ib_grh *in_grh,
const struct ib_mad *in_mad, struct ib_mad *out_mad)
{
- struct mlx4_cmd_mailbox *mailbox;
+ struct mlx4_counter counter_stats;
struct mlx4_ib_dev *dev = to_mdev(ibdev);
int err;
- u32 inmod = dev->counters[port_num - 1] & 0xffff;
- u8 mode;
if (in_mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_PERF_MGMT)
return -EINVAL;
- mailbox = mlx4_alloc_cmd_mailbox(dev->dev);
- if (IS_ERR(mailbox))
- return IB_MAD_RESULT_FAILURE;
-
- err = mlx4_cmd_box(dev->dev, 0, mailbox->dma, inmod, 0,
- MLX4_CMD_QUERY_IF_STAT, MLX4_CMD_TIME_CLASS_C,
- MLX4_CMD_WRAPPED);
+ memset(&counter_stats, 0, sizeof(counter_stats));
+ err = mlx4_get_counter_stats(dev->dev,
+ dev->counters[port_num - 1].index,
+ &counter_stats, 0);
if (err)
err = IB_MAD_RESULT_FAILURE;
else {
memset(out_mad->data, 0, sizeof out_mad->data);
- mode = ((struct mlx4_counter *)mailbox->buf)->counter_mode;
- switch (mode & 0xf) {
+ switch (counter_stats.counter_mode & 0xf) {
case 0:
- edit_counter(mailbox->buf,
- (void *)(out_mad->data + 40));
+ edit_counter(&counter_stats,
+ (void *)(out_mad->data + 40));
err = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
break;
default:
@@ -862,8 +848,6 @@ static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
}
}
- mlx4_free_cmd_mailbox(dev->dev, mailbox);
-
return err;
}
@@ -873,6 +857,7 @@ int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
struct ib_mad_hdr *out, size_t *out_mad_size,
u16 *out_mad_pkey_index)
{
+ struct mlx4_ib_dev *dev = to_mdev(ibdev);
const struct ib_mad *in_mad = (const struct ib_mad *)in;
struct ib_mad *out_mad = (struct ib_mad *)out;
@@ -881,8 +866,9 @@ int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
switch (rdma_port_get_link_layer(ibdev, port_num)) {
case IB_LINK_LAYER_INFINIBAND:
- return ib_process_mad(ibdev, mad_flags, port_num, in_wc,
- in_grh, in_mad, out_mad);
+ if (!mlx4_is_slave(dev->dev))
+ return ib_process_mad(ibdev, mad_flags, port_num, in_wc,
+ in_grh, in_mad, out_mad);
case IB_LINK_LAYER_ETHERNET:
return iboe_process_mad(ibdev, mad_flags, port_num, in_wc,
in_grh, in_mad, out_mad);
@@ -1375,14 +1361,17 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc
* stadard address handle by decoding the tunnelled mlx4_ah fields */
memcpy(&ah.av, &tunnel->hdr.av, sizeof (struct mlx4_av));
ah.ibah.device = ctx->ib_dev;
+
+ port = be32_to_cpu(ah.av.ib.port_pd) >> 24;
+ port = mlx4_slave_convert_port(dev->dev, slave, port);
+ if (port < 0)
+ return;
+ ah.av.ib.port_pd = cpu_to_be32(port << 24 | (be32_to_cpu(ah.av.ib.port_pd) & 0xffffff));
+
mlx4_ib_query_ah(&ah.ibah, &ah_attr);
if (ah_attr.ah_flags & IB_AH_GRH)
fill_in_real_sgid_index(dev, slave, ctx->port, &ah_attr);
- port = mlx4_slave_convert_port(dev->dev, slave, ah_attr.port_num);
- if (port < 0)
- return;
- ah_attr.port_num = port;
memcpy(ah_attr.dmac, tunnel->hdr.mac, 6);
ah_attr.vlan_id = be16_to_cpu(tunnel->hdr.vlan);
/* if slave have default vlan use it */
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 166da787780c..067a691ecbed 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -1146,7 +1146,7 @@ static int __mlx4_ib_create_flow(struct ib_qp *qp, struct ib_flow_attr *flow_att
ret = mlx4_cmd_imm(mdev->dev, mailbox->dma, reg_id, size >> 2, 0,
MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
- MLX4_CMD_NATIVE);
+ MLX4_CMD_WRAPPED);
if (ret == -ENOMEM)
pr_err("mcg table is full. Fail to register network rule.\n");
else if (ret == -ENXIO)
@@ -1163,7 +1163,7 @@ static int __mlx4_ib_destroy_flow(struct mlx4_dev *dev, u64 reg_id)
int err;
err = mlx4_cmd(dev, reg_id, 0, 0,
MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
- MLX4_CMD_NATIVE);
+ MLX4_CMD_WRAPPED);
if (err)
pr_err("Fail to detach network rule. registration id = 0x%llx\n",
reg_id);
@@ -2098,77 +2098,52 @@ static void init_pkeys(struct mlx4_ib_dev *ibdev)
static void mlx4_ib_alloc_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev)
{
- char name[80];
- int eq_per_port = 0;
- int added_eqs = 0;
- int total_eqs = 0;
- int i, j, eq;
-
- /* Legacy mode or comp_pool is not large enough */
- if (dev->caps.comp_pool == 0 ||
- dev->caps.num_ports > dev->caps.comp_pool)
- return;
-
- eq_per_port = dev->caps.comp_pool / dev->caps.num_ports;
+ int i, j, eq = 0, total_eqs = 0;
- /* Init eq table */
- added_eqs = 0;
- mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
- added_eqs += eq_per_port;
-
- total_eqs = dev->caps.num_comp_vectors + added_eqs;
-
- ibdev->eq_table = kzalloc(total_eqs * sizeof(int), GFP_KERNEL);
+ ibdev->eq_table = kcalloc(dev->caps.num_comp_vectors,
+ sizeof(ibdev->eq_table[0]), GFP_KERNEL);
if (!ibdev->eq_table)
return;
- ibdev->eq_added = added_eqs;
-
- eq = 0;
- mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) {
- for (j = 0; j < eq_per_port; j++) {
- snprintf(name, sizeof(name), "mlx4-ib-%d-%d@%s",
- i, j, dev->persist->pdev->bus->name);
- /* Set IRQ for specific name (per ring) */
- if (mlx4_assign_eq(dev, name, NULL,
- &ibdev->eq_table[eq])) {
- /* Use legacy (same as mlx4_en driver) */
- pr_warn("Can't allocate EQ %d; reverting to legacy\n", eq);
- ibdev->eq_table[eq] =
- (eq % dev->caps.num_comp_vectors);
- }
- eq++;
+ for (i = 1; i <= dev->caps.num_ports; i++) {
+ for (j = 0; j < mlx4_get_eqs_per_port(dev, i);
+ j++, total_eqs++) {
+ if (i > 1 && mlx4_is_eq_shared(dev, total_eqs))
+ continue;
+ ibdev->eq_table[eq] = total_eqs;
+ if (!mlx4_assign_eq(dev, i,
+ &ibdev->eq_table[eq]))
+ eq++;
+ else
+ ibdev->eq_table[eq] = -1;
}
}
- /* Fill the reset of the vector with legacy EQ */
- for (i = 0, eq = added_eqs; i < dev->caps.num_comp_vectors; i++)
- ibdev->eq_table[eq++] = i;
+ for (i = eq; i < dev->caps.num_comp_vectors;
+ ibdev->eq_table[i++] = -1)
+ ;
/* Advertise the new number of EQs to clients */
- ibdev->ib_dev.num_comp_vectors = total_eqs;
+ ibdev->ib_dev.num_comp_vectors = eq;
}
static void mlx4_ib_free_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev)
{
int i;
+ int total_eqs = ibdev->ib_dev.num_comp_vectors;
- /* no additional eqs were added */
+ /* no eqs were allocated */
if (!ibdev->eq_table)
return;
/* Reset the advertised EQ number */
- ibdev->ib_dev.num_comp_vectors = dev->caps.num_comp_vectors;
+ ibdev->ib_dev.num_comp_vectors = 0;
- /* Free only the added eqs */
- for (i = 0; i < ibdev->eq_added; i++) {
- /* Don't free legacy eqs if used */
- if (ibdev->eq_table[i] <= dev->caps.num_comp_vectors)
- continue;
+ for (i = 0; i < total_eqs; i++)
mlx4_release_eq(dev, ibdev->eq_table[i]);
- }
kfree(ibdev->eq_table);
+ ibdev->eq_table = NULL;
}
static int mlx4_port_immutable(struct ib_device *ibdev, u8 port_num,
@@ -2203,6 +2178,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
struct mlx4_ib_iboe *iboe;
int ib_num_ports = 0;
int num_req_counters;
+ int allocated;
+ u32 counter_index;
pr_info_once("%s", mlx4_ib_version);
@@ -2373,19 +2350,31 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
num_req_counters = mlx4_is_bonded(dev) ? 1 : ibdev->num_ports;
for (i = 0; i < num_req_counters; ++i) {
mutex_init(&ibdev->qp1_proxy_lock[i]);
+ allocated = 0;
if (mlx4_ib_port_link_layer(&ibdev->ib_dev, i + 1) ==
IB_LINK_LAYER_ETHERNET) {
- err = mlx4_counter_alloc(ibdev->dev, &ibdev->counters[i]);
+ err = mlx4_counter_alloc(ibdev->dev, &counter_index);
+ /* if failed to allocate a new counter, use default */
if (err)
- ibdev->counters[i] = -1;
- } else {
- ibdev->counters[i] = -1;
+ counter_index =
+ mlx4_get_default_counter_index(dev,
+ i + 1);
+ else
+ allocated = 1;
+ } else { /* IB_LINK_LAYER_INFINIBAND use the default counter */
+ counter_index = mlx4_get_default_counter_index(dev,
+ i + 1);
}
+ ibdev->counters[i].index = counter_index;
+ ibdev->counters[i].allocated = allocated;
+ pr_info("counter index %d for port %d allocated %d\n",
+ counter_index, i + 1, allocated);
}
if (mlx4_is_bonded(dev))
- for (i = 1; i < ibdev->num_ports ; ++i)
- ibdev->counters[i] = ibdev->counters[0];
-
+ for (i = 1; i < ibdev->num_ports ; ++i) {
+ ibdev->counters[i].index = ibdev->counters[0].index;
+ ibdev->counters[i].allocated = 0;
+ }
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
ib_num_ports++;
@@ -2525,10 +2514,12 @@ err_steer_qp_release:
mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
ibdev->steer_qpn_count);
err_counter:
- for (; i; --i)
- if (ibdev->counters[i - 1] != -1)
- mlx4_counter_free(ibdev->dev, ibdev->counters[i - 1]);
-
+ for (i = 0; i < ibdev->num_ports; ++i) {
+ if (ibdev->counters[i].index != -1 &&
+ ibdev->counters[i].allocated)
+ mlx4_counter_free(ibdev->dev,
+ ibdev->counters[i].index);
+ }
err_map:
iounmap(ibdev->uar_map);
@@ -2645,8 +2636,9 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
iounmap(ibdev->uar_map);
for (p = 0; p < ibdev->num_ports; ++p)
- if (ibdev->counters[p] != -1)
- mlx4_counter_free(ibdev->dev, ibdev->counters[p]);
+ if (ibdev->counters[p].index != -1 &&
+ ibdev->counters[p].allocated)
+ mlx4_counter_free(ibdev->dev, ibdev->counters[p].index);
mlx4_foreach_port(p, dev, MLX4_PORT_TYPE_IB)
mlx4_CLOSE_PORT(dev, p);
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index 7933adfff662..334387f63358 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -504,6 +504,11 @@ struct mlx4_ib_iov_port {
struct mlx4_ib_iov_sysfs_attr mcg_dentry;
};
+struct counter_index {
+ u32 index;
+ u8 allocated;
+};
+
struct mlx4_ib_dev {
struct ib_device ib_dev;
struct mlx4_dev *dev;
@@ -522,9 +527,8 @@ struct mlx4_ib_dev {
struct mutex cap_mask_mutex;
bool ib_active;
struct mlx4_ib_iboe iboe;
- int counters[MLX4_MAX_PORTS];
+ struct counter_index counters[MLX4_MAX_PORTS];
int *eq_table;
- int eq_added;
struct kobject *iov_parent;
struct kobject *ports_parent;
struct kobject *dev_ports_parent[MLX4_MFUNC_MAX];
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 02fc91c68027..c5a3a5f0de41 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -1539,12 +1539,13 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
}
if (cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) {
- if (dev->counters[qp->port - 1] != -1) {
+ if (dev->counters[qp->port - 1].index != -1) {
context->pri_path.counter_index =
- dev->counters[qp->port - 1];
+ dev->counters[qp->port - 1].index;
optpar |= MLX4_QP_OPTPAR_COUNTER_INDEX;
} else
- context->pri_path.counter_index = 0xff;
+ context->pri_path.counter_index =
+ MLX4_SINK_COUNTER_INDEX(dev->dev);
if (qp->flags & MLX4_IB_QP_NETIF) {
mlx4_ib_steer_qp_reg(dev, qp, 1);
diff --git a/drivers/infiniband/hw/mlx5/Kconfig b/drivers/infiniband/hw/mlx5/Kconfig
index 10df386c6344..bce263b92821 100644
--- a/drivers/infiniband/hw/mlx5/Kconfig
+++ b/drivers/infiniband/hw/mlx5/Kconfig
@@ -1,8 +1,6 @@
config MLX5_INFINIBAND
tristate "Mellanox Connect-IB HCA support"
- depends on NETDEVICES && ETHERNET && PCI
- select NET_VENDOR_MELLANOX
- select MLX5_CORE
+ depends on NETDEVICES && ETHERNET && PCI && MLX5_CORE
---help---
This driver provides low-level InfiniBand support for
Mellanox Connect-IB PCI Express host channel adapters (HCAs).
diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c
index 09fbae618d35..5c9eeea62805 100644
--- a/drivers/infiniband/hw/mlx5/cq.c
+++ b/drivers/infiniband/hw/mlx5/cq.c
@@ -590,8 +590,7 @@ static int alloc_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf,
{
int err;
- err = mlx5_buf_alloc(dev->mdev, nent * cqe_size,
- PAGE_SIZE * 2, &buf->buf);
+ err = mlx5_buf_alloc(dev->mdev, nent * cqe_size, &buf->buf);
if (err)
return err;
@@ -760,7 +759,7 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev,
return ERR_PTR(-EINVAL);
entries = roundup_pow_of_two(entries + 1);
- if (entries > dev->mdev->caps.gen.max_cqes)
+ if (entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz)))
return ERR_PTR(-EINVAL);
cq = kzalloc(sizeof(*cq), GFP_KERNEL);
@@ -927,7 +926,7 @@ int mlx5_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period)
int err;
u32 fsel;
- if (!(dev->mdev->caps.gen.flags & MLX5_DEV_CAP_FLAG_CQ_MODER))
+ if (!MLX5_CAP_GEN(dev->mdev, cq_moderation))
return -ENOSYS;
in = kzalloc(sizeof(*in), GFP_KERNEL);
@@ -1082,7 +1081,7 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
int uninitialized_var(cqe_size);
unsigned long flags;
- if (!(dev->mdev->caps.gen.flags & MLX5_DEV_CAP_FLAG_RESIZE_CQ)) {
+ if (!MLX5_CAP_GEN(dev->mdev, cq_resize)) {
pr_info("Firmware does not support resize CQ\n");
return -ENOSYS;
}
@@ -1091,7 +1090,7 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
return -EINVAL;
entries = roundup_pow_of_two(entries + 1);
- if (entries > dev->mdev->caps.gen.max_cqes + 1)
+ if (entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz)) + 1)
return -EINVAL;
if (entries == ibcq->cqe + 1)
diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c
index 8e45714fa369..01fc97db45d6 100644
--- a/drivers/infiniband/hw/mlx5/mad.c
+++ b/drivers/infiniband/hw/mlx5/mad.c
@@ -136,7 +136,7 @@ int mlx5_query_ext_port_caps(struct mlx5_ib_dev *dev, u8 port)
packet_error = be16_to_cpu(out_mad->status);
- dev->mdev->caps.gen.ext_port_cap[port - 1] = (!err && !packet_error) ?
+ dev->mdev->port_caps[port - 1].ext_port_cap = (!err && !packet_error) ?
MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO : 0;
out:
@@ -144,3 +144,300 @@ out:
kfree(out_mad);
return err;
}
+
+int mlx5_query_mad_ifc_smp_attr_node_info(struct ib_device *ibdev,
+ struct ib_smp *out_mad)
+{
+ struct ib_smp *in_mad = NULL;
+ int err = -ENOMEM;
+
+ in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+ if (!in_mad)
+ return -ENOMEM;
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
+
+ err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, 1, NULL, NULL, in_mad,
+ out_mad);
+
+ kfree(in_mad);
+ return err;
+}
+
+int mlx5_query_mad_ifc_system_image_guid(struct ib_device *ibdev,
+ __be64 *sys_image_guid)
+{
+ struct ib_smp *out_mad = NULL;
+ int err = -ENOMEM;
+
+ out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+ if (!out_mad)
+ return -ENOMEM;
+
+ err = mlx5_query_mad_ifc_smp_attr_node_info(ibdev, out_mad);
+ if (err)
+ goto out;
+
+ memcpy(sys_image_guid, out_mad->data + 4, 8);
+
+out:
+ kfree(out_mad);
+
+ return err;
+}
+
+int mlx5_query_mad_ifc_max_pkeys(struct ib_device *ibdev,
+ u16 *max_pkeys)
+{
+ struct ib_smp *out_mad = NULL;
+ int err = -ENOMEM;
+
+ out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+ if (!out_mad)
+ return -ENOMEM;
+
+ err = mlx5_query_mad_ifc_smp_attr_node_info(ibdev, out_mad);
+ if (err)
+ goto out;
+
+ *max_pkeys = be16_to_cpup((__be16 *)(out_mad->data + 28));
+
+out:
+ kfree(out_mad);
+
+ return err;
+}
+
+int mlx5_query_mad_ifc_vendor_id(struct ib_device *ibdev,
+ u32 *vendor_id)
+{
+ struct ib_smp *out_mad = NULL;
+ int err = -ENOMEM;
+
+ out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+ if (!out_mad)
+ return -ENOMEM;
+
+ err = mlx5_query_mad_ifc_smp_attr_node_info(ibdev, out_mad);
+ if (err)
+ goto out;
+
+ *vendor_id = be32_to_cpup((__be32 *)(out_mad->data + 36)) & 0xffff;
+
+out:
+ kfree(out_mad);
+
+ return err;
+}
+
+int mlx5_query_mad_ifc_node_desc(struct mlx5_ib_dev *dev, char *node_desc)
+{
+ struct ib_smp *in_mad = NULL;
+ struct ib_smp *out_mad = NULL;
+ int err = -ENOMEM;
+
+ in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+ out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+ if (!in_mad || !out_mad)
+ goto out;
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_NODE_DESC;
+
+ err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
+ if (err)
+ goto out;
+
+ memcpy(node_desc, out_mad->data, 64);
+out:
+ kfree(in_mad);
+ kfree(out_mad);
+ return err;
+}
+
+int mlx5_query_mad_ifc_node_guid(struct mlx5_ib_dev *dev, __be64 *node_guid)
+{
+ struct ib_smp *in_mad = NULL;
+ struct ib_smp *out_mad = NULL;
+ int err = -ENOMEM;
+
+ in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+ out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+ if (!in_mad || !out_mad)
+ goto out;
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
+
+ err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
+ if (err)
+ goto out;
+
+ memcpy(node_guid, out_mad->data + 12, 8);
+out:
+ kfree(in_mad);
+ kfree(out_mad);
+ return err;
+}
+
+int mlx5_query_mad_ifc_pkey(struct ib_device *ibdev, u8 port, u16 index,
+ u16 *pkey)
+{
+ struct ib_smp *in_mad = NULL;
+ struct ib_smp *out_mad = NULL;
+ int err = -ENOMEM;
+
+ in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+ out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+ if (!in_mad || !out_mad)
+ goto out;
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_PKEY_TABLE;
+ in_mad->attr_mod = cpu_to_be32(index / 32);
+
+ err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad,
+ out_mad);
+ if (err)
+ goto out;
+
+ *pkey = be16_to_cpu(((__be16 *)out_mad->data)[index % 32]);
+
+out:
+ kfree(in_mad);
+ kfree(out_mad);
+ return err;
+}
+
+int mlx5_query_mad_ifc_gids(struct ib_device *ibdev, u8 port, int index,
+ union ib_gid *gid)
+{
+ struct ib_smp *in_mad = NULL;
+ struct ib_smp *out_mad = NULL;
+ int err = -ENOMEM;
+
+ in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+ out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+ if (!in_mad || !out_mad)
+ goto out;
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_PORT_INFO;
+ in_mad->attr_mod = cpu_to_be32(port);
+
+ err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad,
+ out_mad);
+ if (err)
+ goto out;
+
+ memcpy(gid->raw, out_mad->data + 8, 8);
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_GUID_INFO;
+ in_mad->attr_mod = cpu_to_be32(index / 8);
+
+ err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad,
+ out_mad);
+ if (err)
+ goto out;
+
+ memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8);
+
+out:
+ kfree(in_mad);
+ kfree(out_mad);
+ return err;
+}
+
+int mlx5_query_mad_ifc_port(struct ib_device *ibdev, u8 port,
+ struct ib_port_attr *props)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibdev);
+ struct mlx5_core_dev *mdev = dev->mdev;
+ struct ib_smp *in_mad = NULL;
+ struct ib_smp *out_mad = NULL;
+ int ext_active_speed;
+ int err = -ENOMEM;
+
+ if (port < 1 || port > MLX5_CAP_GEN(mdev, num_ports)) {
+ mlx5_ib_warn(dev, "invalid port number %d\n", port);
+ return -EINVAL;
+ }
+
+ in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+ out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+ if (!in_mad || !out_mad)
+ goto out;
+
+ memset(props, 0, sizeof(*props));
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_PORT_INFO;
+ in_mad->attr_mod = cpu_to_be32(port);
+
+ err = mlx5_MAD_IFC(dev, 1, 1, port, NULL, NULL, in_mad, out_mad);
+ if (err) {
+ mlx5_ib_warn(dev, "err %d\n", err);
+ goto out;
+ }
+
+ props->lid = be16_to_cpup((__be16 *)(out_mad->data + 16));
+ props->lmc = out_mad->data[34] & 0x7;
+ props->sm_lid = be16_to_cpup((__be16 *)(out_mad->data + 18));
+ props->sm_sl = out_mad->data[36] & 0xf;
+ props->state = out_mad->data[32] & 0xf;
+ props->phys_state = out_mad->data[33] >> 4;
+ props->port_cap_flags = be32_to_cpup((__be32 *)(out_mad->data + 20));
+ props->gid_tbl_len = out_mad->data[50];
+ props->max_msg_sz = 1 << MLX5_CAP_GEN(mdev, log_max_msg);
+ props->pkey_tbl_len = mdev->port_caps[port - 1].pkey_table_len;
+ props->bad_pkey_cntr = be16_to_cpup((__be16 *)(out_mad->data + 46));
+ props->qkey_viol_cntr = be16_to_cpup((__be16 *)(out_mad->data + 48));
+ props->active_width = out_mad->data[31] & 0xf;
+ props->active_speed = out_mad->data[35] >> 4;
+ props->max_mtu = out_mad->data[41] & 0xf;
+ props->active_mtu = out_mad->data[36] >> 4;
+ props->subnet_timeout = out_mad->data[51] & 0x1f;
+ props->max_vl_num = out_mad->data[37] >> 4;
+ props->init_type_reply = out_mad->data[41] >> 4;
+
+ /* Check if extended speeds (EDR/FDR/...) are supported */
+ if (props->port_cap_flags & IB_PORT_EXTENDED_SPEEDS_SUP) {
+ ext_active_speed = out_mad->data[62] >> 4;
+
+ switch (ext_active_speed) {
+ case 1:
+ props->active_speed = 16; /* FDR */
+ break;
+ case 2:
+ props->active_speed = 32; /* EDR */
+ break;
+ }
+ }
+
+ /* If reported active speed is QDR, check if is FDR-10 */
+ if (props->active_speed == 4) {
+ if (mdev->port_caps[port - 1].ext_port_cap &
+ MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO) {
+ init_query_mad(in_mad);
+ in_mad->attr_id = MLX5_ATTR_EXTENDED_PORT_INFO;
+ in_mad->attr_mod = cpu_to_be32(port);
+
+ err = mlx5_MAD_IFC(dev, 1, 1, port,
+ NULL, NULL, in_mad, out_mad);
+ if (err)
+ goto out;
+
+ /* Checking LinkSpeedActive for FDR-10 */
+ if (out_mad->data[15] & 0x1)
+ props->active_speed = 8;
+ }
+ }
+
+out:
+ kfree(in_mad);
+ kfree(out_mad);
+
+ return err;
+}
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index c6cb26e0c866..085c24b4b603 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -40,6 +40,7 @@
#include <linux/io-mapping.h>
#include <linux/sched.h>
#include <rdma/ib_user_verbs.h>
+#include <linux/mlx5/vport.h>
#include <rdma/ib_smi.h>
#include <rdma/ib_umem.h>
#include "user.h"
@@ -62,36 +63,172 @@ static char mlx5_version[] =
DRIVER_NAME ": Mellanox Connect-IB Infiniband driver v"
DRIVER_VERSION " (" DRIVER_RELDATE ")\n";
+static enum rdma_link_layer
+mlx5_ib_port_link_layer(struct ib_device *device)
+{
+ struct mlx5_ib_dev *dev = to_mdev(device);
+
+ switch (MLX5_CAP_GEN(dev->mdev, port_type)) {
+ case MLX5_CAP_PORT_TYPE_IB:
+ return IB_LINK_LAYER_INFINIBAND;
+ case MLX5_CAP_PORT_TYPE_ETH:
+ return IB_LINK_LAYER_ETHERNET;
+ default:
+ return IB_LINK_LAYER_UNSPECIFIED;
+ }
+}
+
+static int mlx5_use_mad_ifc(struct mlx5_ib_dev *dev)
+{
+ return !dev->mdev->issi;
+}
+
+enum {
+ MLX5_VPORT_ACCESS_METHOD_MAD,
+ MLX5_VPORT_ACCESS_METHOD_HCA,
+ MLX5_VPORT_ACCESS_METHOD_NIC,
+};
+
+static int mlx5_get_vport_access_method(struct ib_device *ibdev)
+{
+ if (mlx5_use_mad_ifc(to_mdev(ibdev)))
+ return MLX5_VPORT_ACCESS_METHOD_MAD;
+
+ if (mlx5_ib_port_link_layer(ibdev) ==
+ IB_LINK_LAYER_ETHERNET)
+ return MLX5_VPORT_ACCESS_METHOD_NIC;
+
+ return MLX5_VPORT_ACCESS_METHOD_HCA;
+}
+
+static int mlx5_query_system_image_guid(struct ib_device *ibdev,
+ __be64 *sys_image_guid)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibdev);
+ struct mlx5_core_dev *mdev = dev->mdev;
+ u64 tmp;
+ int err;
+
+ switch (mlx5_get_vport_access_method(ibdev)) {
+ case MLX5_VPORT_ACCESS_METHOD_MAD:
+ return mlx5_query_mad_ifc_system_image_guid(ibdev,
+ sys_image_guid);
+
+ case MLX5_VPORT_ACCESS_METHOD_HCA:
+ err = mlx5_query_hca_vport_system_image_guid(mdev, &tmp);
+ if (!err)
+ *sys_image_guid = cpu_to_be64(tmp);
+ return err;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mlx5_query_max_pkeys(struct ib_device *ibdev,
+ u16 *max_pkeys)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibdev);
+ struct mlx5_core_dev *mdev = dev->mdev;
+
+ switch (mlx5_get_vport_access_method(ibdev)) {
+ case MLX5_VPORT_ACCESS_METHOD_MAD:
+ return mlx5_query_mad_ifc_max_pkeys(ibdev, max_pkeys);
+
+ case MLX5_VPORT_ACCESS_METHOD_HCA:
+ case MLX5_VPORT_ACCESS_METHOD_NIC:
+ *max_pkeys = mlx5_to_sw_pkey_sz(MLX5_CAP_GEN(mdev,
+ pkey_table_size));
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mlx5_query_vendor_id(struct ib_device *ibdev,
+ u32 *vendor_id)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibdev);
+
+ switch (mlx5_get_vport_access_method(ibdev)) {
+ case MLX5_VPORT_ACCESS_METHOD_MAD:
+ return mlx5_query_mad_ifc_vendor_id(ibdev, vendor_id);
+
+ case MLX5_VPORT_ACCESS_METHOD_HCA:
+ case MLX5_VPORT_ACCESS_METHOD_NIC:
+ return mlx5_core_query_vendor_id(dev->mdev, vendor_id);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mlx5_query_node_guid(struct mlx5_ib_dev *dev,
+ __be64 *node_guid)
+{
+ u64 tmp;
+ int err;
+
+ switch (mlx5_get_vport_access_method(&dev->ib_dev)) {
+ case MLX5_VPORT_ACCESS_METHOD_MAD:
+ return mlx5_query_mad_ifc_node_guid(dev, node_guid);
+
+ case MLX5_VPORT_ACCESS_METHOD_HCA:
+ err = mlx5_query_hca_vport_node_guid(dev->mdev, &tmp);
+ if (!err)
+ *node_guid = cpu_to_be64(tmp);
+ return err;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+struct mlx5_reg_node_desc {
+ u8 desc[64];
+};
+
+static int mlx5_query_node_desc(struct mlx5_ib_dev *dev, char *node_desc)
+{
+ struct mlx5_reg_node_desc in;
+
+ if (mlx5_use_mad_ifc(dev))
+ return mlx5_query_mad_ifc_node_desc(dev, node_desc);
+
+ memset(&in, 0, sizeof(in));
+
+ return mlx5_core_access_reg(dev->mdev, &in, sizeof(in), node_desc,
+ sizeof(struct mlx5_reg_node_desc),
+ MLX5_REG_NODE_DESC, 0, 0);
+}
+
static int mlx5_ib_query_device(struct ib_device *ibdev,
struct ib_device_attr *props,
struct ib_udata *uhw)
{
struct mlx5_ib_dev *dev = to_mdev(ibdev);
- struct ib_smp *in_mad = NULL;
- struct ib_smp *out_mad = NULL;
- struct mlx5_general_caps *gen;
+ struct mlx5_core_dev *mdev = dev->mdev;
int err = -ENOMEM;
int max_rq_sg;
int max_sq_sg;
- u64 flags;
if (uhw->inlen || uhw->outlen)
return -EINVAL;
- gen = &dev->mdev->caps.gen;
- in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
- out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
- if (!in_mad || !out_mad)
- goto out;
-
- init_query_mad(in_mad);
- in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
+ memset(props, 0, sizeof(*props));
+ err = mlx5_query_system_image_guid(ibdev,
+ &props->sys_image_guid);
+ if (err)
+ return err;
- err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, 1, NULL, NULL, in_mad, out_mad);
+ err = mlx5_query_max_pkeys(ibdev, &props->max_pkeys);
if (err)
- goto out;
+ return err;
- memset(props, 0, sizeof(*props));
+ err = mlx5_query_vendor_id(ibdev, &props->vendor_id);
+ if (err)
+ return err;
props->fw_ver = ((u64)fw_rev_maj(dev->mdev) << 32) |
(fw_rev_min(dev->mdev) << 16) |
@@ -100,18 +237,18 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
IB_DEVICE_PORT_ACTIVE_EVENT |
IB_DEVICE_SYS_IMAGE_GUID |
IB_DEVICE_RC_RNR_NAK_GEN;
- flags = gen->flags;
- if (flags & MLX5_DEV_CAP_FLAG_BAD_PKEY_CNTR)
+
+ if (MLX5_CAP_GEN(mdev, pkv))
props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR;
- if (flags & MLX5_DEV_CAP_FLAG_BAD_QKEY_CNTR)
+ if (MLX5_CAP_GEN(mdev, qkv))
props->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR;
- if (flags & MLX5_DEV_CAP_FLAG_APM)
+ if (MLX5_CAP_GEN(mdev, apm))
props->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG;
props->device_cap_flags |= IB_DEVICE_LOCAL_DMA_LKEY;
- if (flags & MLX5_DEV_CAP_FLAG_XRC)
+ if (MLX5_CAP_GEN(mdev, xrc))
props->device_cap_flags |= IB_DEVICE_XRC;
props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS;
- if (flags & MLX5_DEV_CAP_FLAG_SIG_HAND_OVER) {
+ if (MLX5_CAP_GEN(mdev, sho)) {
props->device_cap_flags |= IB_DEVICE_SIGNATURE_HANDOVER;
/* At this stage no support for signature handover */
props->sig_prot_cap = IB_PROT_T10DIF_TYPE_1 |
@@ -120,221 +257,270 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
props->sig_guard_cap = IB_GUARD_T10DIF_CRC |
IB_GUARD_T10DIF_CSUM;
}
- if (flags & MLX5_DEV_CAP_FLAG_BLOCK_MCAST)
+ if (MLX5_CAP_GEN(mdev, block_lb_mc))
props->device_cap_flags |= IB_DEVICE_BLOCK_MULTICAST_LOOPBACK;
- props->vendor_id = be32_to_cpup((__be32 *)(out_mad->data + 36)) &
- 0xffffff;
- props->vendor_part_id = be16_to_cpup((__be16 *)(out_mad->data + 30));
- props->hw_ver = be32_to_cpup((__be32 *)(out_mad->data + 32));
- memcpy(&props->sys_image_guid, out_mad->data + 4, 8);
+ props->vendor_part_id = mdev->pdev->device;
+ props->hw_ver = mdev->pdev->revision;
props->max_mr_size = ~0ull;
- props->page_size_cap = gen->min_page_sz;
- props->max_qp = 1 << gen->log_max_qp;
- props->max_qp_wr = gen->max_wqes;
- max_rq_sg = gen->max_rq_desc_sz / sizeof(struct mlx5_wqe_data_seg);
- max_sq_sg = (gen->max_sq_desc_sz - sizeof(struct mlx5_wqe_ctrl_seg)) /
- sizeof(struct mlx5_wqe_data_seg);
+ props->page_size_cap = 1ull << MLX5_CAP_GEN(mdev, log_pg_sz);
+ props->max_qp = 1 << MLX5_CAP_GEN(mdev, log_max_qp);
+ props->max_qp_wr = 1 << MLX5_CAP_GEN(mdev, log_max_qp_sz);
+ max_rq_sg = MLX5_CAP_GEN(mdev, max_wqe_sz_rq) /
+ sizeof(struct mlx5_wqe_data_seg);
+ max_sq_sg = (MLX5_CAP_GEN(mdev, max_wqe_sz_sq) -
+ sizeof(struct mlx5_wqe_ctrl_seg)) /
+ sizeof(struct mlx5_wqe_data_seg);
props->max_sge = min(max_rq_sg, max_sq_sg);
- props->max_cq = 1 << gen->log_max_cq;
- props->max_cqe = gen->max_cqes - 1;
- props->max_mr = 1 << gen->log_max_mkey;
- props->max_pd = 1 << gen->log_max_pd;
- props->max_qp_rd_atom = 1 << gen->log_max_ra_req_qp;
- props->max_qp_init_rd_atom = 1 << gen->log_max_ra_res_qp;
- props->max_srq = 1 << gen->log_max_srq;
- props->max_srq_wr = gen->max_srq_wqes - 1;
- props->local_ca_ack_delay = gen->local_ca_ack_delay;
+ props->max_cq = 1 << MLX5_CAP_GEN(mdev, log_max_cq);
+ props->max_cqe = (1 << MLX5_CAP_GEN(mdev, log_max_eq_sz)) - 1;
+ props->max_mr = 1 << MLX5_CAP_GEN(mdev, log_max_mkey);
+ props->max_pd = 1 << MLX5_CAP_GEN(mdev, log_max_pd);
+ props->max_qp_rd_atom = 1 << MLX5_CAP_GEN(mdev, log_max_ra_req_qp);
+ props->max_qp_init_rd_atom = 1 << MLX5_CAP_GEN(mdev, log_max_ra_res_qp);
+ props->max_srq = 1 << MLX5_CAP_GEN(mdev, log_max_srq);
+ props->max_srq_wr = (1 << MLX5_CAP_GEN(mdev, log_max_srq_sz)) - 1;
+ props->local_ca_ack_delay = MLX5_CAP_GEN(mdev, local_ca_ack_delay);
props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp;
props->max_srq_sge = max_rq_sg - 1;
props->max_fast_reg_page_list_len = (unsigned int)-1;
- props->local_ca_ack_delay = gen->local_ca_ack_delay;
props->atomic_cap = IB_ATOMIC_NONE;
props->masked_atomic_cap = IB_ATOMIC_NONE;
- props->max_pkeys = be16_to_cpup((__be16 *)(out_mad->data + 28));
- props->max_mcast_grp = 1 << gen->log_max_mcg;
- props->max_mcast_qp_attach = gen->max_qp_mcg;
+ props->max_mcast_grp = 1 << MLX5_CAP_GEN(mdev, log_max_mcg);
+ props->max_mcast_qp_attach = MLX5_CAP_GEN(mdev, max_qp_mcg);
props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
props->max_mcast_grp;
props->max_map_per_fmr = INT_MAX; /* no limit in ConnectIB */
#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
- if (dev->mdev->caps.gen.flags & MLX5_DEV_CAP_FLAG_ON_DMND_PG)
+ if (MLX5_CAP_GEN(mdev, pg))
props->device_cap_flags |= IB_DEVICE_ON_DEMAND_PAGING;
props->odp_caps = dev->odp_caps;
#endif
-out:
- kfree(in_mad);
- kfree(out_mad);
-
- return err;
+ return 0;
}
-int mlx5_ib_query_port(struct ib_device *ibdev, u8 port,
- struct ib_port_attr *props)
+enum mlx5_ib_width {
+ MLX5_IB_WIDTH_1X = 1 << 0,
+ MLX5_IB_WIDTH_2X = 1 << 1,
+ MLX5_IB_WIDTH_4X = 1 << 2,
+ MLX5_IB_WIDTH_8X = 1 << 3,
+ MLX5_IB_WIDTH_12X = 1 << 4
+};
+
+static int translate_active_width(struct ib_device *ibdev, u8 active_width,
+ u8 *ib_width)
{
struct mlx5_ib_dev *dev = to_mdev(ibdev);
- struct ib_smp *in_mad = NULL;
- struct ib_smp *out_mad = NULL;
- struct mlx5_general_caps *gen;
- int ext_active_speed;
- int err = -ENOMEM;
-
- gen = &dev->mdev->caps.gen;
- if (port < 1 || port > gen->num_ports) {
- mlx5_ib_warn(dev, "invalid port number %d\n", port);
- return -EINVAL;
+ int err = 0;
+
+ if (active_width & MLX5_IB_WIDTH_1X) {
+ *ib_width = IB_WIDTH_1X;
+ } else if (active_width & MLX5_IB_WIDTH_2X) {
+ mlx5_ib_dbg(dev, "active_width %d is not supported by IB spec\n",
+ (int)active_width);
+ err = -EINVAL;
+ } else if (active_width & MLX5_IB_WIDTH_4X) {
+ *ib_width = IB_WIDTH_4X;
+ } else if (active_width & MLX5_IB_WIDTH_8X) {
+ *ib_width = IB_WIDTH_8X;
+ } else if (active_width & MLX5_IB_WIDTH_12X) {
+ *ib_width = IB_WIDTH_12X;
+ } else {
+ mlx5_ib_dbg(dev, "Invalid active_width %d\n",
+ (int)active_width);
+ err = -EINVAL;
}
- in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
- out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
- if (!in_mad || !out_mad)
- goto out;
-
- memset(props, 0, sizeof(*props));
-
- init_query_mad(in_mad);
- in_mad->attr_id = IB_SMP_ATTR_PORT_INFO;
- in_mad->attr_mod = cpu_to_be32(port);
+ return err;
+}
- err = mlx5_MAD_IFC(dev, 1, 1, port, NULL, NULL, in_mad, out_mad);
- if (err) {
- mlx5_ib_warn(dev, "err %d\n", err);
- goto out;
+static int mlx5_mtu_to_ib_mtu(int mtu)
+{
+ switch (mtu) {
+ case 256: return 1;
+ case 512: return 2;
+ case 1024: return 3;
+ case 2048: return 4;
+ case 4096: return 5;
+ default:
+ pr_warn("invalid mtu\n");
+ return -1;
}
+}
+enum ib_max_vl_num {
+ __IB_MAX_VL_0 = 1,
+ __IB_MAX_VL_0_1 = 2,
+ __IB_MAX_VL_0_3 = 3,
+ __IB_MAX_VL_0_7 = 4,
+ __IB_MAX_VL_0_14 = 5,
+};
- props->lid = be16_to_cpup((__be16 *)(out_mad->data + 16));
- props->lmc = out_mad->data[34] & 0x7;
- props->sm_lid = be16_to_cpup((__be16 *)(out_mad->data + 18));
- props->sm_sl = out_mad->data[36] & 0xf;
- props->state = out_mad->data[32] & 0xf;
- props->phys_state = out_mad->data[33] >> 4;
- props->port_cap_flags = be32_to_cpup((__be32 *)(out_mad->data + 20));
- props->gid_tbl_len = out_mad->data[50];
- props->max_msg_sz = 1 << gen->log_max_msg;
- props->pkey_tbl_len = gen->port[port - 1].pkey_table_len;
- props->bad_pkey_cntr = be16_to_cpup((__be16 *)(out_mad->data + 46));
- props->qkey_viol_cntr = be16_to_cpup((__be16 *)(out_mad->data + 48));
- props->active_width = out_mad->data[31] & 0xf;
- props->active_speed = out_mad->data[35] >> 4;
- props->max_mtu = out_mad->data[41] & 0xf;
- props->active_mtu = out_mad->data[36] >> 4;
- props->subnet_timeout = out_mad->data[51] & 0x1f;
- props->max_vl_num = out_mad->data[37] >> 4;
- props->init_type_reply = out_mad->data[41] >> 4;
-
- /* Check if extended speeds (EDR/FDR/...) are supported */
- if (props->port_cap_flags & IB_PORT_EXTENDED_SPEEDS_SUP) {
- ext_active_speed = out_mad->data[62] >> 4;
-
- switch (ext_active_speed) {
- case 1:
- props->active_speed = 16; /* FDR */
- break;
- case 2:
- props->active_speed = 32; /* EDR */
- break;
- }
- }
+enum mlx5_vl_hw_cap {
+ MLX5_VL_HW_0 = 1,
+ MLX5_VL_HW_0_1 = 2,
+ MLX5_VL_HW_0_2 = 3,
+ MLX5_VL_HW_0_3 = 4,
+ MLX5_VL_HW_0_4 = 5,
+ MLX5_VL_HW_0_5 = 6,
+ MLX5_VL_HW_0_6 = 7,
+ MLX5_VL_HW_0_7 = 8,
+ MLX5_VL_HW_0_14 = 15
+};
- /* If reported active speed is QDR, check if is FDR-10 */
- if (props->active_speed == 4) {
- if (gen->ext_port_cap[port - 1] &
- MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO) {
- init_query_mad(in_mad);
- in_mad->attr_id = MLX5_ATTR_EXTENDED_PORT_INFO;
- in_mad->attr_mod = cpu_to_be32(port);
-
- err = mlx5_MAD_IFC(dev, 1, 1, port,
- NULL, NULL, in_mad, out_mad);
- if (err)
- goto out;
-
- /* Checking LinkSpeedActive for FDR-10 */
- if (out_mad->data[15] & 0x1)
- props->active_speed = 8;
- }
- }
+static int translate_max_vl_num(struct ib_device *ibdev, u8 vl_hw_cap,
+ u8 *max_vl_num)
+{
+ switch (vl_hw_cap) {
+ case MLX5_VL_HW_0:
+ *max_vl_num = __IB_MAX_VL_0;
+ break;
+ case MLX5_VL_HW_0_1:
+ *max_vl_num = __IB_MAX_VL_0_1;
+ break;
+ case MLX5_VL_HW_0_3:
+ *max_vl_num = __IB_MAX_VL_0_3;
+ break;
+ case MLX5_VL_HW_0_7:
+ *max_vl_num = __IB_MAX_VL_0_7;
+ break;
+ case MLX5_VL_HW_0_14:
+ *max_vl_num = __IB_MAX_VL_0_14;
+ break;
-out:
- kfree(in_mad);
- kfree(out_mad);
+ default:
+ return -EINVAL;
+ }
- return err;
+ return 0;
}
-static int mlx5_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
- union ib_gid *gid)
+static int mlx5_query_hca_port(struct ib_device *ibdev, u8 port,
+ struct ib_port_attr *props)
{
- struct ib_smp *in_mad = NULL;
- struct ib_smp *out_mad = NULL;
- int err = -ENOMEM;
+ struct mlx5_ib_dev *dev = to_mdev(ibdev);
+ struct mlx5_core_dev *mdev = dev->mdev;
+ struct mlx5_hca_vport_context *rep;
+ int max_mtu;
+ int oper_mtu;
+ int err;
+ u8 ib_link_width_oper;
+ u8 vl_hw_cap;
- in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
- out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
- if (!in_mad || !out_mad)
+ rep = kzalloc(sizeof(*rep), GFP_KERNEL);
+ if (!rep) {
+ err = -ENOMEM;
goto out;
+ }
- init_query_mad(in_mad);
- in_mad->attr_id = IB_SMP_ATTR_PORT_INFO;
- in_mad->attr_mod = cpu_to_be32(port);
+ memset(props, 0, sizeof(*props));
- err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
+ err = mlx5_query_hca_vport_context(mdev, 0, port, 0, rep);
if (err)
goto out;
- memcpy(gid->raw, out_mad->data + 8, 8);
-
- init_query_mad(in_mad);
- in_mad->attr_id = IB_SMP_ATTR_GUID_INFO;
- in_mad->attr_mod = cpu_to_be32(index / 8);
+ props->lid = rep->lid;
+ props->lmc = rep->lmc;
+ props->sm_lid = rep->sm_lid;
+ props->sm_sl = rep->sm_sl;
+ props->state = rep->vport_state;
+ props->phys_state = rep->port_physical_state;
+ props->port_cap_flags = rep->cap_mask1;
+ props->gid_tbl_len = mlx5_get_gid_table_len(MLX5_CAP_GEN(mdev, gid_table_size));
+ props->max_msg_sz = 1 << MLX5_CAP_GEN(mdev, log_max_msg);
+ props->pkey_tbl_len = mlx5_to_sw_pkey_sz(MLX5_CAP_GEN(mdev, pkey_table_size));
+ props->bad_pkey_cntr = rep->pkey_violation_counter;
+ props->qkey_viol_cntr = rep->qkey_violation_counter;
+ props->subnet_timeout = rep->subnet_timeout;
+ props->init_type_reply = rep->init_type_reply;
+
+ err = mlx5_query_port_link_width_oper(mdev, &ib_link_width_oper, port);
+ if (err)
+ goto out;
- err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
+ err = translate_active_width(ibdev, ib_link_width_oper,
+ &props->active_width);
+ if (err)
+ goto out;
+ err = mlx5_query_port_proto_oper(mdev, &props->active_speed, MLX5_PTYS_IB,
+ port);
if (err)
goto out;
- memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8);
+ mlx5_query_port_max_mtu(mdev, &max_mtu, port);
+
+ props->max_mtu = mlx5_mtu_to_ib_mtu(max_mtu);
+
+ mlx5_query_port_oper_mtu(mdev, &oper_mtu, port);
+
+ props->active_mtu = mlx5_mtu_to_ib_mtu(oper_mtu);
+ err = mlx5_query_port_vl_hw_cap(mdev, &vl_hw_cap, port);
+ if (err)
+ goto out;
+
+ err = translate_max_vl_num(ibdev, vl_hw_cap,
+ &props->max_vl_num);
out:
- kfree(in_mad);
- kfree(out_mad);
+ kfree(rep);
return err;
}
-static int mlx5_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index,
- u16 *pkey)
+int mlx5_ib_query_port(struct ib_device *ibdev, u8 port,
+ struct ib_port_attr *props)
{
- struct ib_smp *in_mad = NULL;
- struct ib_smp *out_mad = NULL;
- int err = -ENOMEM;
+ switch (mlx5_get_vport_access_method(ibdev)) {
+ case MLX5_VPORT_ACCESS_METHOD_MAD:
+ return mlx5_query_mad_ifc_port(ibdev, port, props);
- in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
- out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
- if (!in_mad || !out_mad)
- goto out;
+ case MLX5_VPORT_ACCESS_METHOD_HCA:
+ return mlx5_query_hca_port(ibdev, port, props);
+
+ default:
+ return -EINVAL;
+ }
+}
- init_query_mad(in_mad);
- in_mad->attr_id = IB_SMP_ATTR_PKEY_TABLE;
- in_mad->attr_mod = cpu_to_be32(index / 32);
+static int mlx5_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
+ union ib_gid *gid)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibdev);
+ struct mlx5_core_dev *mdev = dev->mdev;
- err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
- if (err)
- goto out;
+ switch (mlx5_get_vport_access_method(ibdev)) {
+ case MLX5_VPORT_ACCESS_METHOD_MAD:
+ return mlx5_query_mad_ifc_gids(ibdev, port, index, gid);
- *pkey = be16_to_cpu(((__be16 *)out_mad->data)[index % 32]);
+ case MLX5_VPORT_ACCESS_METHOD_HCA:
+ return mlx5_query_hca_vport_gid(mdev, 0, port, 0, index, gid);
+
+ default:
+ return -EINVAL;
+ }
-out:
- kfree(in_mad);
- kfree(out_mad);
- return err;
}
-struct mlx5_reg_node_desc {
- u8 desc[64];
-};
+static int mlx5_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index,
+ u16 *pkey)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibdev);
+ struct mlx5_core_dev *mdev = dev->mdev;
+
+ switch (mlx5_get_vport_access_method(ibdev)) {
+ case MLX5_VPORT_ACCESS_METHOD_MAD:
+ return mlx5_query_mad_ifc_pkey(ibdev, port, index, pkey);
+
+ case MLX5_VPORT_ACCESS_METHOD_HCA:
+ case MLX5_VPORT_ACCESS_METHOD_NIC:
+ return mlx5_query_hca_vport_pkey(mdev, 0, port, 0, index,
+ pkey);
+ default:
+ return -EINVAL;
+ }
+}
static int mlx5_ib_modify_device(struct ib_device *ibdev, int mask,
struct ib_device_modify *props)
@@ -396,7 +582,6 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
struct mlx5_ib_alloc_ucontext_req_v2 req;
struct mlx5_ib_alloc_ucontext_resp resp;
struct mlx5_ib_ucontext *context;
- struct mlx5_general_caps *gen;
struct mlx5_uuar_info *uuari;
struct mlx5_uar *uars;
int gross_uuars;
@@ -407,7 +592,6 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
int i;
size_t reqlen;
- gen = &dev->mdev->caps.gen;
if (!dev->ib_active)
return ERR_PTR(-EAGAIN);
@@ -440,14 +624,14 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
num_uars = req.total_num_uuars / MLX5_NON_FP_BF_REGS_PER_PAGE;
gross_uuars = num_uars * MLX5_BF_REGS_PER_PAGE;
- resp.qp_tab_size = 1 << gen->log_max_qp;
- resp.bf_reg_size = gen->bf_reg_size;
- resp.cache_line_size = L1_CACHE_BYTES;
- resp.max_sq_desc_sz = gen->max_sq_desc_sz;
- resp.max_rq_desc_sz = gen->max_rq_desc_sz;
- resp.max_send_wqebb = gen->max_wqes;
- resp.max_recv_wr = gen->max_wqes;
- resp.max_srq_recv_wr = gen->max_srq_wqes;
+ resp.qp_tab_size = 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp);
+ resp.bf_reg_size = 1 << MLX5_CAP_GEN(dev->mdev, log_bf_reg_size);
+ resp.cache_line_size = L1_CACHE_BYTES;
+ resp.max_sq_desc_sz = MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq);
+ resp.max_rq_desc_sz = MLX5_CAP_GEN(dev->mdev, max_wqe_sz_rq);
+ resp.max_send_wqebb = 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz);
+ resp.max_recv_wr = 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz);
+ resp.max_srq_recv_wr = 1 << MLX5_CAP_GEN(dev->mdev, log_max_srq_sz);
context = kzalloc(sizeof(*context), GFP_KERNEL);
if (!context)
@@ -497,7 +681,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
mutex_init(&context->db_page_mutex);
resp.tot_uuars = req.total_num_uuars;
- resp.num_ports = gen->num_ports;
+ resp.num_ports = MLX5_CAP_GEN(dev->mdev, num_ports);
err = ib_copy_to_udata(udata, &resp,
sizeof(resp) - sizeof(resp.reserved));
if (err)
@@ -735,37 +919,15 @@ static int mlx5_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
static int init_node_data(struct mlx5_ib_dev *dev)
{
- struct ib_smp *in_mad = NULL;
- struct ib_smp *out_mad = NULL;
- int err = -ENOMEM;
-
- in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
- out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
- if (!in_mad || !out_mad)
- goto out;
-
- init_query_mad(in_mad);
- in_mad->attr_id = IB_SMP_ATTR_NODE_DESC;
-
- err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
- if (err)
- goto out;
-
- memcpy(dev->ib_dev.node_desc, out_mad->data, 64);
-
- in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
+ int err;
- err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
+ err = mlx5_query_node_desc(dev, dev->ib_dev.node_desc);
if (err)
- goto out;
+ return err;
- dev->mdev->rev_id = be32_to_cpup((__be32 *)(out_mad->data + 32));
- memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);
+ dev->mdev->rev_id = dev->mdev->pdev->revision;
-out:
- kfree(in_mad);
- kfree(out_mad);
- return err;
+ return mlx5_query_node_guid(dev, &dev->ib_dev.node_guid);
}
static ssize_t show_fw_pages(struct device *device, struct device_attribute *attr,
@@ -899,11 +1061,9 @@ static void mlx5_ib_event(struct mlx5_core_dev *dev, void *context,
static void get_ext_port_caps(struct mlx5_ib_dev *dev)
{
- struct mlx5_general_caps *gen;
int port;
- gen = &dev->mdev->caps.gen;
- for (port = 1; port <= gen->num_ports; port++)
+ for (port = 1; port <= MLX5_CAP_GEN(dev->mdev, num_ports); port++)
mlx5_query_ext_port_caps(dev, port);
}
@@ -911,12 +1071,10 @@ static int get_port_caps(struct mlx5_ib_dev *dev)
{
struct ib_device_attr *dprops = NULL;
struct ib_port_attr *pprops = NULL;
- struct mlx5_general_caps *gen;
int err = -ENOMEM;
int port;
struct ib_udata uhw = {.inlen = 0, .outlen = 0};
- gen = &dev->mdev->caps.gen;
pprops = kmalloc(sizeof(*pprops), GFP_KERNEL);
if (!pprops)
goto out;
@@ -931,14 +1089,17 @@ static int get_port_caps(struct mlx5_ib_dev *dev)
goto out;
}
- for (port = 1; port <= gen->num_ports; port++) {
+ for (port = 1; port <= MLX5_CAP_GEN(dev->mdev, num_ports); port++) {
err = mlx5_ib_query_port(&dev->ib_dev, port, pprops);
if (err) {
- mlx5_ib_warn(dev, "query_port %d failed %d\n", port, err);
+ mlx5_ib_warn(dev, "query_port %d failed %d\n",
+ port, err);
break;
}
- gen->port[port - 1].pkey_table_len = dprops->max_pkeys;
- gen->port[port - 1].gid_table_len = pprops->gid_tbl_len;
+ dev->mdev->port_caps[port - 1].pkey_table_len =
+ dprops->max_pkeys;
+ dev->mdev->port_caps[port - 1].gid_table_len =
+ pprops->gid_tbl_len;
mlx5_ib_dbg(dev, "pkey_table_len %d, gid_table_len %d\n",
dprops->max_pkeys, pprops->gid_tbl_len);
}
@@ -1167,8 +1328,29 @@ static int create_dev_resources(struct mlx5_ib_resources *devr)
atomic_inc(&devr->p0->usecnt);
atomic_set(&devr->s0->usecnt, 0);
+ memset(&attr, 0, sizeof(attr));
+ attr.attr.max_sge = 1;
+ attr.attr.max_wr = 1;
+ attr.srq_type = IB_SRQT_BASIC;
+ devr->s1 = mlx5_ib_create_srq(devr->p0, &attr, NULL);
+ if (IS_ERR(devr->s1)) {
+ ret = PTR_ERR(devr->s1);
+ goto error5;
+ }
+ devr->s1->device = &dev->ib_dev;
+ devr->s1->pd = devr->p0;
+ devr->s1->uobject = NULL;
+ devr->s1->event_handler = NULL;
+ devr->s1->srq_context = NULL;
+ devr->s1->srq_type = IB_SRQT_BASIC;
+ devr->s1->ext.xrc.cq = devr->c0;
+ atomic_inc(&devr->p0->usecnt);
+ atomic_set(&devr->s0->usecnt, 0);
+
return 0;
+error5:
+ mlx5_ib_destroy_srq(devr->s0);
error4:
mlx5_ib_dealloc_xrcd(devr->x1);
error3:
@@ -1183,6 +1365,7 @@ error0:
static void destroy_dev_resources(struct mlx5_ib_resources *devr)
{
+ mlx5_ib_destroy_srq(devr->s1);
mlx5_ib_destroy_srq(devr->s0);
mlx5_ib_dealloc_xrcd(devr->x0);
mlx5_ib_dealloc_xrcd(devr->x1);
@@ -1214,6 +1397,10 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
int err;
int i;
+ /* don't create IB instance over Eth ports, no RoCE yet! */
+ if (MLX5_CAP_GEN(mdev, port_type) == MLX5_CAP_PORT_TYPE_ETH)
+ return NULL;
+
printk_once(KERN_INFO "%s", mlx5_version);
dev = (struct mlx5_ib_dev *)ib_alloc_device(sizeof(*dev));
@@ -1226,15 +1413,16 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
if (err)
goto err_dealloc;
- get_ext_port_caps(dev);
+ if (mlx5_use_mad_ifc(dev))
+ get_ext_port_caps(dev);
MLX5_INIT_DOORBELL_LOCK(&dev->uar_lock);
strlcpy(dev->ib_dev.name, "mlx5_%d", IB_DEVICE_NAME_MAX);
dev->ib_dev.owner = THIS_MODULE;
dev->ib_dev.node_type = RDMA_NODE_IB_CA;
- dev->ib_dev.local_dma_lkey = mdev->caps.gen.reserved_lkey;
- dev->num_ports = mdev->caps.gen.num_ports;
+ dev->ib_dev.local_dma_lkey = 0 /* not supported for now */;
+ dev->num_ports = MLX5_CAP_GEN(mdev, num_ports);
dev->ib_dev.phys_port_cnt = dev->num_ports;
dev->ib_dev.num_comp_vectors =
dev->mdev->priv.eq_table.num_comp_vectors;
@@ -1313,9 +1501,9 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
dev->ib_dev.check_mr_status = mlx5_ib_check_mr_status;
dev->ib_dev.get_port_immutable = mlx5_port_immutable;
- mlx5_ib_internal_query_odp_caps(dev);
+ mlx5_ib_internal_fill_odp_caps(dev);
- if (mdev->caps.gen.flags & MLX5_DEV_CAP_FLAG_XRC) {
+ if (MLX5_CAP_GEN(mdev, xrc)) {
dev->ib_dev.alloc_xrcd = mlx5_ib_alloc_xrcd;
dev->ib_dev.dealloc_xrcd = mlx5_ib_dealloc_xrcd;
dev->ib_dev.uverbs_cmd_mask |=
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
index 178314e764da..7cae09836481 100644
--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -415,6 +415,7 @@ struct mlx5_ib_resources {
struct ib_xrcd *x1;
struct ib_pd *p0;
struct ib_srq *s0;
+ struct ib_srq *s1;
};
struct mlx5_ib_dev {
@@ -597,6 +598,22 @@ struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev,
int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd);
int mlx5_ib_get_buf_offset(u64 addr, int page_shift, u32 *offset);
int mlx5_query_ext_port_caps(struct mlx5_ib_dev *dev, u8 port);
+int mlx5_query_mad_ifc_smp_attr_node_info(struct ib_device *ibdev,
+ struct ib_smp *out_mad);
+int mlx5_query_mad_ifc_system_image_guid(struct ib_device *ibdev,
+ __be64 *sys_image_guid);
+int mlx5_query_mad_ifc_max_pkeys(struct ib_device *ibdev,
+ u16 *max_pkeys);
+int mlx5_query_mad_ifc_vendor_id(struct ib_device *ibdev,
+ u32 *vendor_id);
+int mlx5_query_mad_ifc_node_desc(struct mlx5_ib_dev *dev, char *node_desc);
+int mlx5_query_mad_ifc_node_guid(struct mlx5_ib_dev *dev, __be64 *node_guid);
+int mlx5_query_mad_ifc_pkey(struct ib_device *ibdev, u8 port, u16 index,
+ u16 *pkey);
+int mlx5_query_mad_ifc_gids(struct ib_device *ibdev, u8 port, int index,
+ union ib_gid *gid);
+int mlx5_query_mad_ifc_port(struct ib_device *ibdev, u8 port,
+ struct ib_port_attr *props);
int mlx5_ib_query_port(struct ib_device *ibdev, u8 port,
struct ib_port_attr *props);
int mlx5_ib_init_fmr(struct mlx5_ib_dev *dev);
@@ -620,7 +637,7 @@ int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
extern struct workqueue_struct *mlx5_ib_page_fault_wq;
-int mlx5_ib_internal_query_odp_caps(struct mlx5_ib_dev *dev);
+void mlx5_ib_internal_fill_odp_caps(struct mlx5_ib_dev *dev);
void mlx5_ib_mr_pfault_handler(struct mlx5_ib_qp *qp,
struct mlx5_ib_pfault *pfault);
void mlx5_ib_odp_create_qp(struct mlx5_ib_qp *qp);
@@ -634,9 +651,9 @@ void mlx5_ib_invalidate_range(struct ib_umem *umem, unsigned long start,
unsigned long end);
#else /* CONFIG_INFINIBAND_ON_DEMAND_PAGING */
-static inline int mlx5_ib_internal_query_odp_caps(struct mlx5_ib_dev *dev)
+static inline void mlx5_ib_internal_fill_odp_caps(struct mlx5_ib_dev *dev)
{
- return 0;
+ return;
}
static inline void mlx5_ib_odp_create_qp(struct mlx5_ib_qp *qp) {}
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index 71c593583864..bc9a0de897cb 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -975,8 +975,7 @@ static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, u64 virt_addr,
struct mlx5_ib_mr *mr;
int inlen;
int err;
- bool pg_cap = !!(dev->mdev->caps.gen.flags &
- MLX5_DEV_CAP_FLAG_ON_DMND_PG);
+ bool pg_cap = !!(MLX5_CAP_GEN(dev->mdev, pg));
mr = kzalloc(sizeof(*mr), GFP_KERNEL);
if (!mr)
diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c
index 5099db08afd2..aa8391e75385 100644
--- a/drivers/infiniband/hw/mlx5/odp.c
+++ b/drivers/infiniband/hw/mlx5/odp.c
@@ -109,40 +109,33 @@ void mlx5_ib_invalidate_range(struct ib_umem *umem, unsigned long start,
ib_umem_odp_unmap_dma_pages(umem, start, end);
}
-#define COPY_ODP_BIT_MLX_TO_IB(reg, ib_caps, field_name, bit_name) do { \
- if (be32_to_cpu(reg.field_name) & MLX5_ODP_SUPPORT_##bit_name) \
- ib_caps->field_name |= IB_ODP_SUPPORT_##bit_name; \
-} while (0)
-
-int mlx5_ib_internal_query_odp_caps(struct mlx5_ib_dev *dev)
+void mlx5_ib_internal_fill_odp_caps(struct mlx5_ib_dev *dev)
{
- int err;
- struct mlx5_odp_caps hw_caps;
struct ib_odp_caps *caps = &dev->odp_caps;
memset(caps, 0, sizeof(*caps));
- if (!(dev->mdev->caps.gen.flags & MLX5_DEV_CAP_FLAG_ON_DMND_PG))
- return 0;
-
- err = mlx5_query_odp_caps(dev->mdev, &hw_caps);
- if (err)
- goto out;
+ if (!MLX5_CAP_GEN(dev->mdev, pg))
+ return;
caps->general_caps = IB_ODP_SUPPORT;
- COPY_ODP_BIT_MLX_TO_IB(hw_caps, caps, per_transport_caps.ud_odp_caps,
- SEND);
- COPY_ODP_BIT_MLX_TO_IB(hw_caps, caps, per_transport_caps.rc_odp_caps,
- SEND);
- COPY_ODP_BIT_MLX_TO_IB(hw_caps, caps, per_transport_caps.rc_odp_caps,
- RECV);
- COPY_ODP_BIT_MLX_TO_IB(hw_caps, caps, per_transport_caps.rc_odp_caps,
- WRITE);
- COPY_ODP_BIT_MLX_TO_IB(hw_caps, caps, per_transport_caps.rc_odp_caps,
- READ);
-
-out:
- return err;
+
+ if (MLX5_CAP_ODP(dev->mdev, ud_odp_caps.send))
+ caps->per_transport_caps.ud_odp_caps |= IB_ODP_SUPPORT_SEND;
+
+ if (MLX5_CAP_ODP(dev->mdev, rc_odp_caps.send))
+ caps->per_transport_caps.rc_odp_caps |= IB_ODP_SUPPORT_SEND;
+
+ if (MLX5_CAP_ODP(dev->mdev, rc_odp_caps.receive))
+ caps->per_transport_caps.rc_odp_caps |= IB_ODP_SUPPORT_RECV;
+
+ if (MLX5_CAP_ODP(dev->mdev, rc_odp_caps.write))
+ caps->per_transport_caps.rc_odp_caps |= IB_ODP_SUPPORT_WRITE;
+
+ if (MLX5_CAP_ODP(dev->mdev, rc_odp_caps.read))
+ caps->per_transport_caps.rc_odp_caps |= IB_ODP_SUPPORT_READ;
+
+ return;
}
static struct mlx5_ib_mr *mlx5_ib_odp_find_mr_lkey(struct mlx5_ib_dev *dev,
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
index d35f62d4f4c5..203c8a45e095 100644
--- a/drivers/infiniband/hw/mlx5/qp.c
+++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -220,13 +220,11 @@ static void mlx5_ib_qp_event(struct mlx5_core_qp *qp, int type)
static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap,
int has_rq, struct mlx5_ib_qp *qp, struct mlx5_ib_create_qp *ucmd)
{
- struct mlx5_general_caps *gen;
int wqe_size;
int wq_size;
- gen = &dev->mdev->caps.gen;
/* Sanity check RQ size before proceeding */
- if (cap->max_recv_wr > gen->max_wqes)
+ if (cap->max_recv_wr > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz)))
return -EINVAL;
if (!has_rq) {
@@ -246,10 +244,11 @@ static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap,
wq_size = roundup_pow_of_two(cap->max_recv_wr) * wqe_size;
wq_size = max_t(int, wq_size, MLX5_SEND_WQE_BB);
qp->rq.wqe_cnt = wq_size / wqe_size;
- if (wqe_size > gen->max_rq_desc_sz) {
+ if (wqe_size > MLX5_CAP_GEN(dev->mdev, max_wqe_sz_rq)) {
mlx5_ib_dbg(dev, "wqe_size %d, max %d\n",
wqe_size,
- gen->max_rq_desc_sz);
+ MLX5_CAP_GEN(dev->mdev,
+ max_wqe_sz_rq));
return -EINVAL;
}
qp->rq.wqe_shift = ilog2(wqe_size);
@@ -330,11 +329,9 @@ static int calc_send_wqe(struct ib_qp_init_attr *attr)
static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr,
struct mlx5_ib_qp *qp)
{
- struct mlx5_general_caps *gen;
int wqe_size;
int wq_size;
- gen = &dev->mdev->caps.gen;
if (!attr->cap.max_send_wr)
return 0;
@@ -343,9 +340,9 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr,
if (wqe_size < 0)
return wqe_size;
- if (wqe_size > gen->max_sq_desc_sz) {
+ if (wqe_size > MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq)) {
mlx5_ib_dbg(dev, "wqe_size(%d) > max_sq_desc_sz(%d)\n",
- wqe_size, gen->max_sq_desc_sz);
+ wqe_size, MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq));
return -EINVAL;
}
@@ -358,9 +355,10 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr,
wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size);
qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB;
- if (qp->sq.wqe_cnt > gen->max_wqes) {
+ if (qp->sq.wqe_cnt > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz))) {
mlx5_ib_dbg(dev, "wqe count(%d) exceeds limits(%d)\n",
- qp->sq.wqe_cnt, gen->max_wqes);
+ qp->sq.wqe_cnt,
+ 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz));
return -ENOMEM;
}
qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB);
@@ -375,13 +373,11 @@ static int set_user_buf_size(struct mlx5_ib_dev *dev,
struct mlx5_ib_qp *qp,
struct mlx5_ib_create_qp *ucmd)
{
- struct mlx5_general_caps *gen;
int desc_sz = 1 << qp->sq.wqe_shift;
- gen = &dev->mdev->caps.gen;
- if (desc_sz > gen->max_sq_desc_sz) {
+ if (desc_sz > MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq)) {
mlx5_ib_warn(dev, "desc_sz %d, max_sq_desc_sz %d\n",
- desc_sz, gen->max_sq_desc_sz);
+ desc_sz, MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq));
return -EINVAL;
}
@@ -393,9 +389,10 @@ static int set_user_buf_size(struct mlx5_ib_dev *dev,
qp->sq.wqe_cnt = ucmd->sq_wqe_count;
- if (qp->sq.wqe_cnt > gen->max_wqes) {
+ if (qp->sq.wqe_cnt > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz))) {
mlx5_ib_warn(dev, "wqe_cnt %d, max_wqes %d\n",
- qp->sq.wqe_cnt, gen->max_wqes);
+ qp->sq.wqe_cnt,
+ 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz));
return -EINVAL;
}
@@ -768,7 +765,7 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev,
qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift;
qp->buf_size = err + (qp->rq.wqe_cnt << qp->rq.wqe_shift);
- err = mlx5_buf_alloc(dev->mdev, qp->buf_size, PAGE_SIZE * 2, &qp->buf);
+ err = mlx5_buf_alloc(dev->mdev, qp->buf_size, &qp->buf);
if (err) {
mlx5_ib_dbg(dev, "err %d\n", err);
goto err_uuar;
@@ -866,22 +863,21 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
struct ib_udata *udata, struct mlx5_ib_qp *qp)
{
struct mlx5_ib_resources *devr = &dev->devr;
+ struct mlx5_core_dev *mdev = dev->mdev;
struct mlx5_ib_create_qp_resp resp;
struct mlx5_create_qp_mbox_in *in;
- struct mlx5_general_caps *gen;
struct mlx5_ib_create_qp ucmd;
int inlen = sizeof(*in);
int err;
mlx5_ib_odp_create_qp(qp);
- gen = &dev->mdev->caps.gen;
mutex_init(&qp->mutex);
spin_lock_init(&qp->sq.lock);
spin_lock_init(&qp->rq.lock);
if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) {
- if (!(gen->flags & MLX5_DEV_CAP_FLAG_BLOCK_MCAST)) {
+ if (!MLX5_CAP_GEN(mdev, block_lb_mc)) {
mlx5_ib_dbg(dev, "block multicast loopback isn't supported\n");
return -EINVAL;
} else {
@@ -914,15 +910,17 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
if (pd) {
if (pd->uobject) {
+ __u32 max_wqes =
+ 1 << MLX5_CAP_GEN(mdev, log_max_qp_sz);
mlx5_ib_dbg(dev, "requested sq_wqe_count (%d)\n", ucmd.sq_wqe_count);
if (ucmd.rq_wqe_shift != qp->rq.wqe_shift ||
ucmd.rq_wqe_count != qp->rq.wqe_cnt) {
mlx5_ib_dbg(dev, "invalid rq params\n");
return -EINVAL;
}
- if (ucmd.sq_wqe_count > gen->max_wqes) {
+ if (ucmd.sq_wqe_count > max_wqes) {
mlx5_ib_dbg(dev, "requested sq_wqe_count (%d) > max allowed (%d)\n",
- ucmd.sq_wqe_count, gen->max_wqes);
+ ucmd.sq_wqe_count, max_wqes);
return -EINVAL;
}
err = create_user_qp(dev, pd, qp, udata, &in, &resp, &inlen);
@@ -1014,7 +1012,8 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
in->ctx.rq_type_srqn |= cpu_to_be32(to_msrq(init_attr->srq)->msrq.srqn);
} else {
in->ctx.xrcd = cpu_to_be32(to_mxrcd(devr->x1)->xrcdn);
- in->ctx.rq_type_srqn |= cpu_to_be32(to_msrq(devr->s0)->msrq.srqn);
+ in->ctx.rq_type_srqn |=
+ cpu_to_be32(to_msrq(devr->s1)->msrq.srqn);
}
}
@@ -1226,7 +1225,6 @@ struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd,
struct ib_qp_init_attr *init_attr,
struct ib_udata *udata)
{
- struct mlx5_general_caps *gen;
struct mlx5_ib_dev *dev;
struct mlx5_ib_qp *qp;
u16 xrcdn = 0;
@@ -1244,12 +1242,11 @@ struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd,
}
dev = to_mdev(to_mxrcd(init_attr->xrcd)->ibxrcd.device);
}
- gen = &dev->mdev->caps.gen;
switch (init_attr->qp_type) {
case IB_QPT_XRC_TGT:
case IB_QPT_XRC_INI:
- if (!(gen->flags & MLX5_DEV_CAP_FLAG_XRC)) {
+ if (!MLX5_CAP_GEN(dev->mdev, xrc)) {
mlx5_ib_dbg(dev, "XRC not supported\n");
return ERR_PTR(-ENOSYS);
}
@@ -1356,9 +1353,6 @@ enum {
static int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate)
{
- struct mlx5_general_caps *gen;
-
- gen = &dev->mdev->caps.gen;
if (rate == IB_RATE_PORT_CURRENT) {
return 0;
} else if (rate < IB_RATE_2_5_GBPS || rate > IB_RATE_300_GBPS) {
@@ -1366,7 +1360,7 @@ static int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate)
} else {
while (rate != IB_RATE_2_5_GBPS &&
!(1 << (rate + MLX5_STAT_RATE_OFFSET) &
- gen->stat_rate_support))
+ MLX5_CAP_GEN(dev->mdev, stat_rate_support)))
--rate;
}
@@ -1377,10 +1371,8 @@ static int mlx5_set_path(struct mlx5_ib_dev *dev, const struct ib_ah_attr *ah,
struct mlx5_qp_path *path, u8 port, int attr_mask,
u32 path_flags, const struct ib_qp_attr *attr)
{
- struct mlx5_general_caps *gen;
int err;
- gen = &dev->mdev->caps.gen;
path->fl = (path_flags & MLX5_PATH_FLAG_FL) ? 0x80 : 0;
path->free_ar = (path_flags & MLX5_PATH_FLAG_FREE_AR) ? 0x80 : 0;
@@ -1391,9 +1383,11 @@ static int mlx5_set_path(struct mlx5_ib_dev *dev, const struct ib_ah_attr *ah,
path->rlid = cpu_to_be16(ah->dlid);
if (ah->ah_flags & IB_AH_GRH) {
- if (ah->grh.sgid_index >= gen->port[port - 1].gid_table_len) {
+ if (ah->grh.sgid_index >=
+ dev->mdev->port_caps[port - 1].gid_table_len) {
pr_err("sgid_index (%u) too large. max is %d\n",
- ah->grh.sgid_index, gen->port[port - 1].gid_table_len);
+ ah->grh.sgid_index,
+ dev->mdev->port_caps[port - 1].gid_table_len);
return -EINVAL;
}
path->grh_mlid |= 1 << 7;
@@ -1570,7 +1564,6 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
struct mlx5_ib_qp *qp = to_mqp(ibqp);
struct mlx5_ib_cq *send_cq, *recv_cq;
struct mlx5_qp_context *context;
- struct mlx5_general_caps *gen;
struct mlx5_modify_qp_mbox_in *in;
struct mlx5_ib_pd *pd;
enum mlx5_qp_state mlx5_cur, mlx5_new;
@@ -1579,7 +1572,6 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
int mlx5_st;
int err;
- gen = &dev->mdev->caps.gen;
in = kzalloc(sizeof(*in), GFP_KERNEL);
if (!in)
return -ENOMEM;
@@ -1619,7 +1611,8 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
err = -EINVAL;
goto out;
}
- context->mtu_msgmax = (attr->path_mtu << 5) | gen->log_max_msg;
+ context->mtu_msgmax = (attr->path_mtu << 5) |
+ (u8)MLX5_CAP_GEN(dev->mdev, log_max_msg);
}
if (attr_mask & IB_QP_DEST_QPN)
@@ -1777,11 +1770,9 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
struct mlx5_ib_qp *qp = to_mqp(ibqp);
enum ib_qp_state cur_state, new_state;
- struct mlx5_general_caps *gen;
int err = -EINVAL;
int port;
- gen = &dev->mdev->caps.gen;
mutex_lock(&qp->mutex);
cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state;
@@ -1793,21 +1784,25 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
goto out;
if ((attr_mask & IB_QP_PORT) &&
- (attr->port_num == 0 || attr->port_num > gen->num_ports))
+ (attr->port_num == 0 ||
+ attr->port_num > MLX5_CAP_GEN(dev->mdev, num_ports)))
goto out;
if (attr_mask & IB_QP_PKEY_INDEX) {
port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port;
- if (attr->pkey_index >= gen->port[port - 1].pkey_table_len)
+ if (attr->pkey_index >=
+ dev->mdev->port_caps[port - 1].pkey_table_len)
goto out;
}
if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
- attr->max_rd_atomic > (1 << gen->log_max_ra_res_qp))
+ attr->max_rd_atomic >
+ (1 << MLX5_CAP_GEN(dev->mdev, log_max_ra_res_qp)))
goto out;
if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
- attr->max_dest_rd_atomic > (1 << gen->log_max_ra_req_qp))
+ attr->max_dest_rd_atomic >
+ (1 << MLX5_CAP_GEN(dev->mdev, log_max_ra_req_qp)))
goto out;
if (cur_state == new_state && cur_state == IB_QPS_RESET) {
@@ -3009,7 +3004,7 @@ static void to_ib_ah_attr(struct mlx5_ib_dev *ibdev, struct ib_ah_attr *ib_ah_at
ib_ah_attr->port_num = path->port;
if (ib_ah_attr->port_num == 0 ||
- ib_ah_attr->port_num > dev->caps.gen.num_ports)
+ ib_ah_attr->port_num > MLX5_CAP_GEN(dev, num_ports))
return;
ib_ah_attr->sl = path->sl & 0xf;
@@ -3135,12 +3130,10 @@ struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev,
struct ib_udata *udata)
{
struct mlx5_ib_dev *dev = to_mdev(ibdev);
- struct mlx5_general_caps *gen;
struct mlx5_ib_xrcd *xrcd;
int err;
- gen = &dev->mdev->caps.gen;
- if (!(gen->flags & MLX5_DEV_CAP_FLAG_XRC))
+ if (!MLX5_CAP_GEN(dev->mdev, xrc))
return ERR_PTR(-ENOSYS);
xrcd = kmalloc(sizeof(*xrcd), GFP_KERNEL);
diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c
index 02d77a29764d..e008505e96e9 100644
--- a/drivers/infiniband/hw/mlx5/srq.c
+++ b/drivers/infiniband/hw/mlx5/srq.c
@@ -165,7 +165,7 @@ static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq,
return err;
}
- if (mlx5_buf_alloc(dev->mdev, buf_size, PAGE_SIZE * 2, &srq->buf)) {
+ if (mlx5_buf_alloc(dev->mdev, buf_size, &srq->buf)) {
mlx5_ib_dbg(dev, "buf alloc failed\n");
err = -ENOMEM;
goto err_db;
@@ -236,7 +236,6 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
struct ib_udata *udata)
{
struct mlx5_ib_dev *dev = to_mdev(pd->device);
- struct mlx5_general_caps *gen;
struct mlx5_ib_srq *srq;
int desc_size;
int buf_size;
@@ -245,13 +244,13 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
int uninitialized_var(inlen);
int is_xrc;
u32 flgs, xrcdn;
+ __u32 max_srq_wqes = 1 << MLX5_CAP_GEN(dev->mdev, log_max_srq_sz);
- gen = &dev->mdev->caps.gen;
/* Sanity check SRQ size before proceeding */
- if (init_attr->attr.max_wr >= gen->max_srq_wqes) {
+ if (init_attr->attr.max_wr >= max_srq_wqes) {
mlx5_ib_dbg(dev, "max_wr %d, cap %d\n",
init_attr->attr.max_wr,
- gen->max_srq_wqes);
+ max_srq_wqes);
return ERR_PTR(-EINVAL);
}
@@ -303,7 +302,7 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
in->ctx.pd = cpu_to_be32(to_mpd(pd)->pdn);
in->ctx.db_record = cpu_to_be64(srq->db.dma);
- err = mlx5_core_create_srq(dev->mdev, &srq->msrq, in, inlen);
+ err = mlx5_core_create_srq(dev->mdev, &srq->msrq, in, inlen, is_xrc);
kvfree(in);
if (err) {
mlx5_ib_dbg(dev, "create SRQ failed, err %d\n", err);
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index a11ff74a5127..a35532ec00e4 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -25,6 +25,19 @@ config INPUT
if INPUT
+config INPUT_LEDS
+ tristate "Export input device LEDs in sysfs"
+ depends on LEDS_CLASS
+ default INPUT
+ help
+ Say Y here if you would like to export LEDs on input devices
+ as standard LED class devices in sysfs.
+
+ If unsure, say Y.
+
+ To compile this driver as a module, choose M here: the
+ module will be called input-leds.
+
config INPUT_FF_MEMLESS
tristate "Support for memoryless force-feedback devices"
help
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 5ca3f631497f..0c9302ca9954 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o
+obj-$(CONFIG_INPUT_LEDS) += input-leds.o
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index a18f41b89b6a..9d35499faca4 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -422,10 +422,7 @@ static int evdev_release(struct inode *inode, struct file *file)
evdev_detach_client(evdev, client);
- if (is_vmalloc_addr(client))
- vfree(client);
- else
- kfree(client);
+ kvfree(client);
evdev_close_device(evdev);
diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c
index b81c88c43452..8f4a30fccbb6 100644
--- a/drivers/input/ff-core.c
+++ b/drivers/input/ff-core.c
@@ -70,7 +70,7 @@ static int compat_effect(struct ff_device *ff, struct ff_effect *effect)
return -EINVAL;
/*
- * calculate manginude of sine wave as average of rumble's
+ * calculate magnitude of sine wave as average of rumble's
* 2/3 of strong magnitude and 1/3 of weak magnitude
*/
magnitude = effect->u.rumble.strong_magnitude / 3 +
@@ -213,7 +213,7 @@ static int erase_effect(struct input_dev *dev, int effect_id,
/**
* input_ff_erase - erase a force-feedback effect from device
* @dev: input device to erase effect from
- * @effect_id: id of the ffect to be erased
+ * @effect_id: id of the effect to be erased
* @file: purported owner of the request
*
* This function erases a force-feedback effect from specified device.
diff --git a/drivers/input/input-leds.c b/drivers/input/input-leds.c
new file mode 100644
index 000000000000..074a65ed17bb
--- /dev/null
+++ b/drivers/input/input-leds.c
@@ -0,0 +1,212 @@
+/*
+ * LED support for the input layer
+ *
+ * Copyright 2010-2015 Samuel Thibault <samuel.thibault@ens-lyon.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/input.h>
+
+#if IS_ENABLED(CONFIG_VT)
+#define VT_TRIGGER(_name) .trigger = _name
+#else
+#define VT_TRIGGER(_name) .trigger = NULL
+#endif
+
+static const struct {
+ const char *name;
+ const char *trigger;
+} input_led_info[LED_CNT] = {
+ [LED_NUML] = { "numlock", VT_TRIGGER("kbd-numlock") },
+ [LED_CAPSL] = { "capslock", VT_TRIGGER("kbd-capslock") },
+ [LED_SCROLLL] = { "scrolllock", VT_TRIGGER("kbd-scrolllock") },
+ [LED_COMPOSE] = { "compose" },
+ [LED_KANA] = { "kana", VT_TRIGGER("kbd-kanalock") },
+ [LED_SLEEP] = { "sleep" } ,
+ [LED_SUSPEND] = { "suspend" },
+ [LED_MUTE] = { "mute" },
+ [LED_MISC] = { "misc" },
+ [LED_MAIL] = { "mail" },
+ [LED_CHARGING] = { "charging" },
+};
+
+struct input_led {
+ struct led_classdev cdev;
+ struct input_handle *handle;
+ unsigned int code; /* One of LED_* constants */
+};
+
+struct input_leds {
+ struct input_handle handle;
+ unsigned int num_leds;
+ struct input_led leds[];
+};
+
+static enum led_brightness input_leds_brightness_get(struct led_classdev *cdev)
+{
+ struct input_led *led = container_of(cdev, struct input_led, cdev);
+ struct input_dev *input = led->handle->dev;
+
+ return test_bit(led->code, input->led) ? cdev->max_brightness : 0;
+}
+
+static void input_leds_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct input_led *led = container_of(cdev, struct input_led, cdev);
+
+ input_inject_event(led->handle, EV_LED, led->code, !!brightness);
+}
+
+static void input_leds_event(struct input_handle *handle, unsigned int type,
+ unsigned int code, int value)
+{
+}
+
+static int input_leds_connect(struct input_handler *handler,
+ struct input_dev *dev,
+ const struct input_device_id *id)
+{
+ struct input_leds *leds;
+ unsigned int num_leds;
+ unsigned int led_code;
+ int led_no;
+ int error;
+
+ num_leds = bitmap_weight(dev->ledbit, LED_CNT);
+ if (!num_leds)
+ return -ENXIO;
+
+ leds = kzalloc(sizeof(*leds) + num_leds * sizeof(*leds->leds),
+ GFP_KERNEL);
+ if (!leds)
+ return -ENOMEM;
+
+ leds->num_leds = num_leds;
+
+ leds->handle.dev = dev;
+ leds->handle.handler = handler;
+ leds->handle.name = "leds";
+ leds->handle.private = leds;
+
+ error = input_register_handle(&leds->handle);
+ if (error)
+ goto err_free_mem;
+
+ error = input_open_device(&leds->handle);
+ if (error)
+ goto err_unregister_handle;
+
+ led_no = 0;
+ for_each_set_bit(led_code, dev->ledbit, LED_CNT) {
+ struct input_led *led = &leds->leds[led_no];
+
+ led->handle = &leds->handle;
+ led->code = led_code;
+
+ if (WARN_ON(!input_led_info[led_code].name))
+ continue;
+
+ led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s",
+ dev_name(&dev->dev),
+ input_led_info[led_code].name);
+ if (!led->cdev.name) {
+ error = -ENOMEM;
+ goto err_unregister_leds;
+ }
+
+ led->cdev.max_brightness = 1;
+ led->cdev.brightness_get = input_leds_brightness_get;
+ led->cdev.brightness_set = input_leds_brightness_set;
+ led->cdev.default_trigger = input_led_info[led_code].trigger;
+
+ error = led_classdev_register(&dev->dev, &led->cdev);
+ if (error) {
+ dev_err(&dev->dev, "failed to register LED %s: %d\n",
+ led->cdev.name, error);
+ kfree(led->cdev.name);
+ goto err_unregister_leds;
+ }
+
+ led_no++;
+ }
+
+ return 0;
+
+err_unregister_leds:
+ while (--led_no >= 0) {
+ struct input_led *led = &leds->leds[led_no];
+
+ led_classdev_unregister(&led->cdev);
+ kfree(led->cdev.name);
+ }
+
+ input_close_device(&leds->handle);
+
+err_unregister_handle:
+ input_unregister_handle(&leds->handle);
+
+err_free_mem:
+ kfree(leds);
+ return error;
+}
+
+static void input_leds_disconnect(struct input_handle *handle)
+{
+ struct input_leds *leds = handle->private;
+ int i;
+
+ for (i = 0; i < leds->num_leds; i++) {
+ struct input_led *led = &leds->leds[i];
+
+ led_classdev_unregister(&led->cdev);
+ kfree(led->cdev.name);
+ }
+
+ input_close_device(handle);
+ input_unregister_handle(handle);
+
+ kfree(leds);
+}
+
+static const struct input_device_id input_leds_ids[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+ .evbit = { BIT_MASK(EV_LED) },
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(input, input_leds_ids);
+
+static struct input_handler input_leds_handler = {
+ .event = input_leds_event,
+ .connect = input_leds_connect,
+ .disconnect = input_leds_disconnect,
+ .name = "leds",
+ .id_table = input_leds_ids,
+};
+
+static int __init input_leds_init(void)
+{
+ return input_register_handler(&input_leds_handler);
+}
+module_init(input_leds_init);
+
+static void __exit input_leds_exit(void)
+{
+ input_unregister_handler(&input_leds_handler);
+}
+module_exit(input_leds_exit);
+
+MODULE_AUTHOR("Samuel Thibault <samuel.thibault@ens-lyon.org>");
+MODULE_AUTHOR("Dmitry Torokhov <dmitry.torokhov@gmail.com>");
+MODULE_DESCRIPTION("Input -> LEDs Bridge");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/input.c b/drivers/input/input.c
index cc357f1516a7..f31578423636 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -2262,7 +2262,7 @@ EXPORT_SYMBOL(input_unregister_handler);
*
* Iterate over @bus's list of devices, and call @fn for each, passing
* it @data and stop when @fn returns a non-zero value. The function is
- * using RCU to traverse the list and therefore may be usind in atonic
+ * using RCU to traverse the list and therefore may be using in atomic
* contexts. The @fn callback is invoked from RCU critical section and
* thus must not sleep.
*/
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index e8eb60c6d83e..4cd94fd6cbad 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -367,6 +367,7 @@ config KEYBOARD_MAPLE
config KEYBOARD_MAX7359
tristate "Maxim MAX7359 Key Switch Controller"
+ select INPUT_MATRIXKMAP
depends on I2C
help
If you say yes here you get support for the Maxim MAX7359 Key
diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c
index a45267729dfc..6ed83cf8b74e 100644
--- a/drivers/input/keyboard/adp5589-keys.c
+++ b/drivers/input/keyboard/adp5589-keys.c
@@ -180,7 +180,7 @@
#define LOGIC2_STAT (1 << 7) /* ADP5589 only */
#define LOGIC1_STAT (1 << 6)
#define LOCK_STAT (1 << 5) /* ADP5589 only */
-#define KEC 0xF
+#define KEC 0x1F
/* PIN_CONFIG_D Register */
#define C4_EXTEND_CFG (1 << 6) /* RESET2 */
@@ -726,7 +726,7 @@ static int adp5589_setup(struct adp5589_kpad *kpad)
pull_mask |= val << (2 * (i & 0x3));
- if (i == 3 || i == kpad->var->max_row_num) {
+ if (i % 4 == 3 || i == kpad->var->max_row_num) {
ret |= adp5589_write(client, reg(ADP5585_RPULL_CONFIG_A)
+ (i >> 2), pull_mask);
pull_mask = 0;
@@ -746,7 +746,7 @@ static int adp5589_setup(struct adp5589_kpad *kpad)
pull_mask |= val << (2 * (i & 0x3));
- if (i == 3 || i == kpad->var->max_col_num) {
+ if (i % 4 == 3 || i == kpad->var->max_col_num) {
ret |= adp5589_write(client,
reg(ADP5585_RPULL_CONFIG_C) +
(i >> 2), pull_mask);
diff --git a/drivers/input/keyboard/clps711x-keypad.c b/drivers/input/keyboard/clps711x-keypad.c
index 27ef29f8fe6a..b637f1af842e 100644
--- a/drivers/input/keyboard/clps711x-keypad.c
+++ b/drivers/input/keyboard/clps711x-keypad.c
@@ -120,14 +120,9 @@ static int clps711x_keypad_probe(struct platform_device *pdev)
for (i = 0; i < priv->row_count; i++) {
struct clps711x_gpio_data *data = &priv->gpio_data[i];
- data->desc = devm_gpiod_get_index(dev, "row", i);
- if (!data->desc)
- return -EINVAL;
-
+ data->desc = devm_gpiod_get_index(dev, "row", i, GPIOD_IN);
if (IS_ERR(data->desc))
return PTR_ERR(data->desc);
-
- gpiod_direction_input(data->desc);
}
err = of_property_read_u32(np, "poll-interval", &poll_interval);
diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c
index faa6da53eba8..5091133b7b8e 100644
--- a/drivers/input/keyboard/max7359_keypad.c
+++ b/drivers/input/keyboard/max7359_keypad.c
@@ -84,26 +84,6 @@ static int max7359_read_reg(struct i2c_client *client, int reg)
return ret;
}
-static void max7359_build_keycode(struct max7359_keypad *keypad,
- const struct matrix_keymap_data *keymap_data)
-{
- struct input_dev *input_dev = keypad->input_dev;
- int i;
-
- for (i = 0; i < keymap_data->keymap_size; i++) {
- unsigned int key = keymap_data->keymap[i];
- unsigned int row = KEY_ROW(key);
- unsigned int col = KEY_COL(key);
- unsigned int scancode = MATRIX_SCAN_CODE(row, col,
- MAX7359_ROW_SHIFT);
- unsigned short keycode = KEY_VAL(key);
-
- keypad->keycodes[scancode] = keycode;
- __set_bit(keycode, input_dev->keybit);
- }
- __clear_bit(KEY_RESERVED, input_dev->keybit);
-}
-
/* runs in an IRQ thread -- can (and will!) sleep */
static irqreturn_t max7359_interrupt(int irq, void *dev_id)
{
@@ -166,7 +146,6 @@ static void max7359_close(struct input_dev *dev)
static void max7359_initialize(struct i2c_client *client)
{
max7359_write_reg(client, MAX7359_REG_CONFIG,
- MAX7359_CFG_INTERRUPT | /* Irq clears after host read */
MAX7359_CFG_KEY_RELEASE | /* Key release enable */
MAX7359_CFG_WAKEUP); /* Key press wakeup enable */
@@ -233,7 +212,15 @@ static int max7359_probe(struct i2c_client *client,
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, keypad);
- max7359_build_keycode(keypad, keymap_data);
+ error = matrix_keypad_build_keymap(keymap_data, NULL,
+ MAX7359_MAX_KEY_ROWS,
+ MAX7359_MAX_KEY_COLS,
+ keypad->keycodes,
+ input_dev);
+ if (error) {
+ dev_err(&client->dev, "failed to build keymap\n");
+ return error;
+ }
error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
max7359_interrupt,
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
index 6b9fdf6cf8e8..43e48dac7687 100644
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -585,7 +585,7 @@ static const struct of_device_id samsung_keypad_dt_match[] = {
MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match);
#endif
-static struct platform_device_id samsung_keypad_driver_ids[] = {
+static const struct platform_device_id samsung_keypad_driver_ids[] = {
{
.name = "samsung-keypad",
.driver_data = KEYPAD_TYPE_SAMSUNG,
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index f42a543db043..623d451767e3 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -3,7 +3,7 @@
* Based on omap-keypad driver
*
* Copyright (C) 2010 ST Microelectronics
- * Rajeev Kumar<rajeev-dlh.kumar@st.com>
+ * Rajeev Kumar <rajeevkumar.linux@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 4436ab1b9735..d4f0a817e858 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -610,6 +610,16 @@ config INPUT_DA9055_ONKEY
To compile this driver as a module, choose M here: the module
will be called da9055_onkey.
+config INPUT_DA9063_ONKEY
+ tristate "Dialog DA9063 OnKey"
+ depends on MFD_DA9063
+ help
+ Support the ONKEY of Dialog DA9063 Power Management IC as an
+ input device reporting power button statue.
+
+ To compile this driver as a module, choose M here: the module
+ will be called da9063_onkey.
+
config INPUT_DM355EVM
tristate "TI DaVinci DM355 EVM Keypad and IR Remote"
depends on MFD_DM355EVM_MSP
@@ -775,6 +785,17 @@ config INPUT_DRV260X_HAPTICS
To compile this driver as a module, choose M here: the
module will be called drv260x-haptics.
+config INPUT_DRV2665_HAPTICS
+ tristate "TI DRV2665 haptics support"
+ depends on INPUT && I2C
+ select INPUT_FF_MEMLESS
+ select REGMAP_I2C
+ help
+ Say Y to enable support for the TI DRV2665 haptics driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called drv2665-haptics.
+
config INPUT_DRV2667_HAPTICS
tristate "TI DRV2667 haptics support"
depends on INPUT && I2C
@@ -784,6 +805,6 @@ config INPUT_DRV2667_HAPTICS
Say Y to enable support for the TI DRV2667 haptics driver.
To compile this driver as a module, choose M here: the
- module will be called drv260x-haptics.
+ module will be called drv2667-haptics.
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 78ba4c1b8532..53df07dcc23c 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -25,9 +25,11 @@ obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o
obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o
+obj-$(CONFIG_INPUT_DA9063_ONKEY) += da9063_onkey.o
obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
obj-$(CONFIG_INPUT_E3X0_BUTTON) += e3x0-button.o
obj-$(CONFIG_INPUT_DRV260X_HAPTICS) += drv260x.o
+obj-$(CONFIG_INPUT_DRV2665_HAPTICS) += drv2665.o
obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o
diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c
index 470bfd6f0830..bdb5d03b296e 100644
--- a/drivers/input/misc/adxl34x-i2c.c
+++ b/drivers/input/misc/adxl34x-i2c.c
@@ -10,6 +10,7 @@
#include <linux/input.h> /* BUS_I2C */
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/types.h>
#include <linux/pm.h>
#include "adxl34x.h"
@@ -135,11 +136,31 @@ static const struct i2c_device_id adxl34x_id[] = {
MODULE_DEVICE_TABLE(i2c, adxl34x_id);
+#ifdef CONFIG_OF
+static const struct of_device_id adxl34x_of_id[] = {
+ /*
+ * The ADXL346 is backward-compatible with the ADXL345. Differences are
+ * handled by runtime detection of the device model, there's thus no
+ * need for listing the "adi,adxl346" compatible value explicitly.
+ */
+ { .compatible = "adi,adxl345", },
+ /*
+ * Deprecated, DT nodes should use one or more of the device-specific
+ * compatible values "adi,adxl345" and "adi,adxl346".
+ */
+ { .compatible = "adi,adxl34x", },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, adxl34x_of_id);
+#endif
+
static struct i2c_driver adxl34x_driver = {
.driver = {
.name = "adxl34x",
.owner = THIS_MODULE,
.pm = &adxl34x_i2c_pm,
+ .of_match_table = of_match_ptr(adxl34x_of_id),
},
.probe = adxl34x_i2c_probe,
.remove = adxl34x_i2c_remove,
diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c
new file mode 100644
index 000000000000..f577585ef999
--- /dev/null
+++ b/drivers/input/misc/da9063_onkey.c
@@ -0,0 +1,226 @@
+/*
+ * OnKey device driver for DA9063
+ * Copyright (C) 2015 Dialog Semiconductor Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/mfd/da9063/core.h>
+#include <linux/mfd/da9063/pdata.h>
+#include <linux/mfd/da9063/registers.h>
+
+struct da9063_onkey {
+ struct da9063 *hw;
+ struct delayed_work work;
+ struct input_dev *input;
+ struct device *dev;
+ bool key_power;
+};
+
+static void da9063_poll_on(struct work_struct *work)
+{
+ struct da9063_onkey *onkey = container_of(work, struct da9063_onkey,
+ work.work);
+ unsigned int val;
+ int fault_log = 0;
+ bool poll = true;
+ int error;
+
+ /* Poll to see when the pin is released */
+ error = regmap_read(onkey->hw->regmap, DA9063_REG_STATUS_A, &val);
+ if (error) {
+ dev_err(onkey->dev,
+ "Failed to read ON status: %d\n", error);
+ goto err_poll;
+ }
+
+ if (!(val & DA9063_NONKEY)) {
+ error = regmap_update_bits(onkey->hw->regmap,
+ DA9063_REG_CONTROL_B,
+ DA9063_NONKEY_LOCK, 0);
+ if (error) {
+ dev_err(onkey->dev,
+ "Failed to reset the Key Delay %d\n", error);
+ goto err_poll;
+ }
+
+ input_report_key(onkey->input, KEY_POWER, 0);
+ input_sync(onkey->input);
+
+ poll = false;
+ }
+
+ /*
+ * If the fault log KEY_RESET is detected, then clear it
+ * and shut down the system.
+ */
+ error = regmap_read(onkey->hw->regmap,
+ DA9063_REG_FAULT_LOG, &fault_log);
+ if (error) {
+ dev_warn(&onkey->input->dev,
+ "Cannot read FAULT_LOG: %d\n", error);
+ } else if (fault_log & DA9063_KEY_RESET) {
+ error = regmap_write(onkey->hw->regmap,
+ DA9063_REG_FAULT_LOG,
+ DA9063_KEY_RESET);
+ if (error) {
+ dev_warn(&onkey->input->dev,
+ "Cannot reset KEY_RESET fault log: %d\n",
+ error);
+ } else {
+ /* at this point we do any S/W housekeeping
+ * and then send shutdown command
+ */
+ dev_dbg(&onkey->input->dev,
+ "Sending SHUTDOWN to DA9063 ...\n");
+ error = regmap_write(onkey->hw->regmap,
+ DA9063_REG_CONTROL_F,
+ DA9063_SHUTDOWN);
+ if (error)
+ dev_err(&onkey->input->dev,
+ "Cannot SHUTDOWN DA9063: %d\n",
+ error);
+ }
+ }
+
+err_poll:
+ if (poll)
+ schedule_delayed_work(&onkey->work, msecs_to_jiffies(50));
+}
+
+static irqreturn_t da9063_onkey_irq_handler(int irq, void *data)
+{
+ struct da9063_onkey *onkey = data;
+ unsigned int val;
+ int error;
+
+ error = regmap_read(onkey->hw->regmap, DA9063_REG_STATUS_A, &val);
+ if (onkey->key_power && !error && (val & DA9063_NONKEY)) {
+ input_report_key(onkey->input, KEY_POWER, 1);
+ input_sync(onkey->input);
+ schedule_delayed_work(&onkey->work, 0);
+ dev_dbg(onkey->dev, "KEY_POWER pressed.\n");
+ } else {
+ input_report_key(onkey->input, KEY_SLEEP, 1);
+ input_sync(onkey->input);
+ input_report_key(onkey->input, KEY_SLEEP, 0);
+ input_sync(onkey->input);
+ dev_dbg(onkey->dev, "KEY_SLEEP pressed.\n");
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void da9063_cancel_poll(void *data)
+{
+ struct da9063_onkey *onkey = data;
+
+ cancel_delayed_work_sync(&onkey->work);
+}
+
+static int da9063_onkey_probe(struct platform_device *pdev)
+{
+ struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);
+ struct da9063_pdata *pdata = dev_get_platdata(da9063->dev);
+ struct da9063_onkey *onkey;
+ int irq;
+ int error;
+
+ onkey = devm_kzalloc(&pdev->dev, sizeof(struct da9063_onkey),
+ GFP_KERNEL);
+ if (!onkey) {
+ dev_err(&pdev->dev, "Failed to allocate memory.\n");
+ return -ENOMEM;
+ }
+
+ onkey->dev = &pdev->dev;
+ onkey->hw = da9063;
+
+ if (pdata)
+ onkey->key_power = pdata->key_power;
+ else
+ onkey->key_power =
+ !of_property_read_bool(pdev->dev.of_node,
+ "dlg,disable-key-power");
+
+ onkey->input = devm_input_allocate_device(&pdev->dev);
+ if (!onkey->input) {
+ dev_err(&pdev->dev, "Failed to allocated input device.\n");
+ return -ENOMEM;
+ }
+
+ onkey->input->name = DA9063_DRVNAME_ONKEY;
+ onkey->input->phys = DA9063_DRVNAME_ONKEY "/input0";
+ onkey->input->dev.parent = &pdev->dev;
+
+ if (onkey->key_power)
+ input_set_capability(onkey->input, EV_KEY, KEY_POWER);
+
+ input_set_capability(onkey->input, EV_KEY, KEY_SLEEP);
+
+ INIT_DELAYED_WORK(&onkey->work, da9063_poll_on);
+
+ error = devm_add_action(&pdev->dev, da9063_cancel_poll, onkey);
+ if (error) {
+ dev_err(&pdev->dev,
+ "Failed to add cancel poll action: %d\n",
+ error);
+ return error;
+ }
+
+ irq = platform_get_irq_byname(pdev, "ONKEY");
+ if (irq < 0) {
+ error = irq;
+ dev_err(&pdev->dev, "Failed to get platform IRQ: %d\n", error);
+ return error;
+ }
+
+ error = devm_request_threaded_irq(&pdev->dev, irq,
+ NULL, da9063_onkey_irq_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "ONKEY", onkey);
+ if (error) {
+ dev_err(&pdev->dev,
+ "Failed to request IRQ %d: %d\n", irq, error);
+ return error;
+ }
+
+ error = input_register_device(onkey->input);
+ if (error) {
+ dev_err(&pdev->dev,
+ "Failed to register input device: %d\n", error);
+ return error;
+ }
+
+ platform_set_drvdata(pdev, onkey);
+ return 0;
+}
+
+static struct platform_driver da9063_onkey_driver = {
+ .probe = da9063_onkey_probe,
+ .driver = {
+ .name = DA9063_DRVNAME_ONKEY,
+ },
+};
+module_platform_driver(da9063_onkey_driver);
+
+MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
+MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY);
diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
index 599578042ea0..e5d60ecd29a4 100644
--- a/drivers/input/misc/drv260x.c
+++ b/drivers/input/misc/drv260x.c
@@ -580,15 +580,10 @@ static int drv260x_probe(struct i2c_client *client,
return error;
}
- haptics->enable_gpio = devm_gpiod_get(&client->dev, "enable");
- if (IS_ERR(haptics->enable_gpio)) {
- error = PTR_ERR(haptics->enable_gpio);
- if (error != -ENOENT && error != -ENOSYS)
- return error;
- haptics->enable_gpio = NULL;
- } else {
- gpiod_direction_output(haptics->enable_gpio, 1);
- }
+ haptics->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(haptics->enable_gpio))
+ return PTR_ERR(haptics->enable_gpio);
haptics->input_dev = devm_input_allocate_device(&client->dev);
if (!haptics->input_dev) {
diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c
new file mode 100644
index 000000000000..0afaa33de07d
--- /dev/null
+++ b/drivers/input/misc/drv2665.c
@@ -0,0 +1,322 @@
+/*
+ * DRV2665 haptics driver family
+ *
+ * Author: Dan Murphy <dmurphy@ti.com>
+ *
+ * Copyright: (C) 2015 Texas Instruments, 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+
+/* Contol registers */
+#define DRV2665_STATUS 0x00
+#define DRV2665_CTRL_1 0x01
+#define DRV2665_CTRL_2 0x02
+#define DRV2665_FIFO 0x0b
+
+/* Status Register */
+#define DRV2665_FIFO_FULL BIT(0)
+#define DRV2665_FIFO_EMPTY BIT(1)
+
+/* Control 1 Register */
+#define DRV2665_25_VPP_GAIN 0x00
+#define DRV2665_50_VPP_GAIN 0x01
+#define DRV2665_75_VPP_GAIN 0x02
+#define DRV2665_100_VPP_GAIN 0x03
+#define DRV2665_DIGITAL_IN 0xfc
+#define DRV2665_ANALOG_IN BIT(2)
+
+/* Control 2 Register */
+#define DRV2665_BOOST_EN BIT(1)
+#define DRV2665_STANDBY BIT(6)
+#define DRV2665_DEV_RST BIT(7)
+#define DRV2665_5_MS_IDLE_TOUT 0x00
+#define DRV2665_10_MS_IDLE_TOUT 0x04
+#define DRV2665_15_MS_IDLE_TOUT 0x08
+#define DRV2665_20_MS_IDLE_TOUT 0x0c
+
+/**
+ * struct drv2665_data -
+ * @input_dev - Pointer to the input device
+ * @client - Pointer to the I2C client
+ * @regmap - Register map of the device
+ * @work - Work item used to off load the enable/disable of the vibration
+ * @regulator - Pointer to the regulator for the IC
+ */
+struct drv2665_data {
+ struct input_dev *input_dev;
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct work_struct work;
+ struct regulator *regulator;
+};
+
+/* 8kHz Sine wave to stream to the FIFO */
+static const u8 drv2665_sine_wave_form[] = {
+ 0x00, 0x10, 0x20, 0x2e, 0x3c, 0x48, 0x53, 0x5b, 0x61, 0x65, 0x66,
+ 0x65, 0x61, 0x5b, 0x53, 0x48, 0x3c, 0x2e, 0x20, 0x10,
+ 0x00, 0xf0, 0xe0, 0xd2, 0xc4, 0xb8, 0xad, 0xa5, 0x9f, 0x9b, 0x9a,
+ 0x9b, 0x9f, 0xa5, 0xad, 0xb8, 0xc4, 0xd2, 0xe0, 0xf0, 0x00,
+};
+
+static struct reg_default drv2665_reg_defs[] = {
+ { DRV2665_STATUS, 0x02 },
+ { DRV2665_CTRL_1, 0x28 },
+ { DRV2665_CTRL_2, 0x40 },
+ { DRV2665_FIFO, 0x00 },
+};
+
+static void drv2665_worker(struct work_struct *work)
+{
+ struct drv2665_data *haptics =
+ container_of(work, struct drv2665_data, work);
+ unsigned int read_buf;
+ int error;
+
+ error = regmap_read(haptics->regmap, DRV2665_STATUS, &read_buf);
+ if (error) {
+ dev_err(&haptics->client->dev,
+ "Failed to read status: %d\n", error);
+ return;
+ }
+
+ if (read_buf & DRV2665_FIFO_EMPTY) {
+ error = regmap_bulk_write(haptics->regmap,
+ DRV2665_FIFO,
+ drv2665_sine_wave_form,
+ ARRAY_SIZE(drv2665_sine_wave_form));
+ if (error) {
+ dev_err(&haptics->client->dev,
+ "Failed to write FIFO: %d\n", error);
+ return;
+ }
+ }
+}
+
+static int drv2665_haptics_play(struct input_dev *input, void *data,
+ struct ff_effect *effect)
+{
+ struct drv2665_data *haptics = input_get_drvdata(input);
+
+ schedule_work(&haptics->work);
+
+ return 0;
+}
+
+static void drv2665_close(struct input_dev *input)
+{
+ struct drv2665_data *haptics = input_get_drvdata(input);
+ int error;
+
+ cancel_work_sync(&haptics->work);
+
+ error = regmap_update_bits(haptics->regmap,
+ DRV2665_CTRL_2, DRV2665_STANDBY, 1);
+ if (error)
+ dev_err(&haptics->client->dev,
+ "Failed to enter standby mode: %d\n", error);
+}
+
+static const struct reg_default drv2665_init_regs[] = {
+ { DRV2665_CTRL_2, 0 | DRV2665_10_MS_IDLE_TOUT },
+ { DRV2665_CTRL_1, DRV2665_25_VPP_GAIN },
+};
+
+static int drv2665_init(struct drv2665_data *haptics)
+{
+ int error;
+
+ error = regmap_register_patch(haptics->regmap,
+ drv2665_init_regs,
+ ARRAY_SIZE(drv2665_init_regs));
+ if (error) {
+ dev_err(&haptics->client->dev,
+ "Failed to write init registers: %d\n",
+ error);
+ return error;
+ }
+
+ return 0;
+}
+
+static const struct regmap_config drv2665_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = DRV2665_FIFO,
+ .reg_defaults = drv2665_reg_defs,
+ .num_reg_defaults = ARRAY_SIZE(drv2665_reg_defs),
+ .cache_type = REGCACHE_NONE,
+};
+
+static int drv2665_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct drv2665_data *haptics;
+ int error;
+
+ haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL);
+ if (!haptics)
+ return -ENOMEM;
+
+ haptics->regulator = devm_regulator_get(&client->dev, "vbat");
+ if (IS_ERR(haptics->regulator)) {
+ error = PTR_ERR(haptics->regulator);
+ dev_err(&client->dev,
+ "unable to get regulator, error: %d\n", error);
+ return error;
+ }
+
+ haptics->input_dev = devm_input_allocate_device(&client->dev);
+ if (!haptics->input_dev) {
+ dev_err(&client->dev, "Failed to allocate input device\n");
+ return -ENOMEM;
+ }
+
+ haptics->input_dev->name = "drv2665:haptics";
+ haptics->input_dev->dev.parent = client->dev.parent;
+ haptics->input_dev->close = drv2665_close;
+ input_set_drvdata(haptics->input_dev, haptics);
+ input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
+
+ error = input_ff_create_memless(haptics->input_dev, NULL,
+ drv2665_haptics_play);
+ if (error) {
+ dev_err(&client->dev, "input_ff_create() failed: %d\n",
+ error);
+ return error;
+ }
+
+ INIT_WORK(&haptics->work, drv2665_worker);
+
+ haptics->client = client;
+ i2c_set_clientdata(client, haptics);
+
+ haptics->regmap = devm_regmap_init_i2c(client, &drv2665_regmap_config);
+ if (IS_ERR(haptics->regmap)) {
+ error = PTR_ERR(haptics->regmap);
+ dev_err(&client->dev, "Failed to allocate register map: %d\n",
+ error);
+ return error;
+ }
+
+ error = drv2665_init(haptics);
+ if (error) {
+ dev_err(&client->dev, "Device init failed: %d\n", error);
+ return error;
+ }
+
+ error = input_register_device(haptics->input_dev);
+ if (error) {
+ dev_err(&client->dev, "couldn't register input device: %d\n",
+ error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int __maybe_unused drv2665_suspend(struct device *dev)
+{
+ struct drv2665_data *haptics = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&haptics->input_dev->mutex);
+
+ if (haptics->input_dev->users) {
+ ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
+ DRV2665_STANDBY, 1);
+ if (ret) {
+ dev_err(dev, "Failed to set standby mode\n");
+ regulator_disable(haptics->regulator);
+ goto out;
+ }
+
+ ret = regulator_disable(haptics->regulator);
+ if (ret) {
+ dev_err(dev, "Failed to disable regulator\n");
+ regmap_update_bits(haptics->regmap,
+ DRV2665_CTRL_2,
+ DRV2665_STANDBY, 0);
+ }
+ }
+out:
+ mutex_unlock(&haptics->input_dev->mutex);
+ return ret;
+}
+
+static int __maybe_unused drv2665_resume(struct device *dev)
+{
+ struct drv2665_data *haptics = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&haptics->input_dev->mutex);
+
+ if (haptics->input_dev->users) {
+ ret = regulator_enable(haptics->regulator);
+ if (ret) {
+ dev_err(dev, "Failed to enable regulator\n");
+ goto out;
+ }
+
+ ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
+ DRV2665_STANDBY, 0);
+ if (ret) {
+ dev_err(dev, "Failed to unset standby mode\n");
+ regulator_disable(haptics->regulator);
+ goto out;
+ }
+
+ }
+
+out:
+ mutex_unlock(&haptics->input_dev->mutex);
+ return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume);
+
+static const struct i2c_device_id drv2665_id[] = {
+ { "drv2665", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, drv2665_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id drv2665_of_match[] = {
+ { .compatible = "ti,drv2665", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, drv2665_of_match);
+#endif
+
+static struct i2c_driver drv2665_driver = {
+ .probe = drv2665_probe,
+ .driver = {
+ .name = "drv2665-haptics",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(drv2665_of_match),
+ .pm = &drv2665_pm_ops,
+ },
+ .id_table = drv2665_id,
+};
+module_i2c_driver(drv2665_driver);
+
+MODULE_DESCRIPTION("TI DRV2665 haptics driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
diff --git a/drivers/input/misc/gpio-beeper.c b/drivers/input/misc/gpio-beeper.c
index 4817c5f0c3e4..16272fffeb7e 100644
--- a/drivers/input/misc/gpio-beeper.c
+++ b/drivers/input/misc/gpio-beeper.c
@@ -66,13 +66,12 @@ static int gpio_beeper_probe(struct platform_device *pdev)
{
struct gpio_beeper *beep;
struct input_dev *input;
- int err;
beep = devm_kzalloc(&pdev->dev, sizeof(*beep), GFP_KERNEL);
if (!beep)
return -ENOMEM;
- beep->desc = devm_gpiod_get(&pdev->dev, NULL);
+ beep->desc = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW);
if (IS_ERR(beep->desc))
return PTR_ERR(beep->desc);
@@ -92,10 +91,6 @@ static int gpio_beeper_probe(struct platform_device *pdev)
input_set_capability(input, EV_SND, SND_BELL);
- err = gpiod_direction_output(beep->desc, 0);
- if (err)
- return err;
-
input_set_drvdata(input, beep);
return input_register_device(input);
diff --git a/drivers/input/misc/retu-pwrbutton.c b/drivers/input/misc/retu-pwrbutton.c
index 0c8ac60e2639..30b459b6b344 100644
--- a/drivers/input/misc/retu-pwrbutton.c
+++ b/drivers/input/misc/retu-pwrbutton.c
@@ -63,7 +63,8 @@ static int retu_pwrbutton_probe(struct platform_device *pdev)
input_set_drvdata(idev, rdev);
error = devm_request_threaded_irq(&pdev->dev, irq,
- NULL, retu_pwrbutton_irq, 0,
+ NULL, retu_pwrbutton_irq,
+ IRQF_ONESHOT,
"retu-pwrbutton", idev);
if (error)
return error;
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index e8e010a85484..c14b82709b0f 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -18,7 +18,6 @@
#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
#include <linux/platform_device.h>
-#include <linux/acpi.h>
/*
* Definition of buttons on the tablet. The ACPI index of each button
diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c
index e98cc81a84c6..603fc2fadf05 100644
--- a/drivers/input/misc/twl4030-pwrbutton.c
+++ b/drivers/input/misc/twl4030-pwrbutton.c
@@ -71,7 +71,8 @@ static int twl4030_pwrbutton_probe(struct platform_device *pdev)
pwr->dev.parent = &pdev->dev;
err = devm_request_threaded_irq(&pwr->dev, irq, NULL, powerbutton_irq,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
+ IRQF_ONESHOT,
"twl4030_pwrbutton", pwr);
if (err < 0) {
dev_err(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err);
diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c
index 0e0d094df2e6..ea63fad48de6 100644
--- a/drivers/input/misc/twl6040-vibra.c
+++ b/drivers/input/misc/twl6040-vibra.c
@@ -308,7 +308,8 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
mutex_init(&info->mutex);
error = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
- twl6040_vib_irq_handler, 0,
+ twl6040_vib_irq_handler,
+ IRQF_ONESHOT,
"twl6040_irq_vib", info);
if (error) {
dev_err(info->dev, "VIB IRQ request failed: %d\n", error);
diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c
index 59d4f7bcb4a3..1b44de265a0a 100644
--- a/drivers/input/misc/wm831x-on.c
+++ b/drivers/input/misc/wm831x-on.c
@@ -99,7 +99,8 @@ static int wm831x_on_probe(struct platform_device *pdev)
wm831x_on->dev->dev.parent = &pdev->dev;
ret = request_threaded_irq(irq, NULL, wm831x_on_irq,
- IRQF_TRIGGER_RISING, "wm831x_on",
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "wm831x_on",
wm831x_on);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to request IRQ: %d\n", ret);
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index a353b7de6d22..113d6f1516a5 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -159,8 +159,8 @@ static const struct alps_protocol_info alps_v8_protocol_data = {
static void alps_set_abs_params_st(struct alps_data *priv,
struct input_dev *dev1);
-static void alps_set_abs_params_mt(struct alps_data *priv,
- struct input_dev *dev1);
+static void alps_set_abs_params_semi_mt(struct alps_data *priv,
+ struct input_dev *dev1);
static void alps_set_abs_params_v7(struct alps_data *priv,
struct input_dev *dev1);
static void alps_set_abs_params_ss4_v2(struct alps_data *priv,
@@ -310,53 +310,6 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
input_sync(dev);
}
-/*
- * Process bitmap data for V5 protocols. Return value is null.
- *
- * The bitmaps don't have enough data to track fingers, so this function
- * only generates points representing a bounding box of at most two contacts.
- * These two points are returned in fields->mt.
- */
-static void alps_process_bitmap_dolphin(struct alps_data *priv,
- struct alps_fields *fields)
-{
- int box_middle_x, box_middle_y;
- unsigned int x_map, y_map;
- unsigned char start_bit, end_bit;
- unsigned char x_msb, x_lsb, y_msb, y_lsb;
-
- x_map = fields->x_map;
- y_map = fields->y_map;
-
- if (!x_map || !y_map)
- return;
-
- /* Get Most-significant and Least-significant bit */
- x_msb = fls(x_map);
- x_lsb = ffs(x_map);
- y_msb = fls(y_map);
- y_lsb = ffs(y_map);
-
- /* Most-significant bit should never exceed max sensor line number */
- if (x_msb > priv->x_bits || y_msb > priv->y_bits)
- return;
-
- if (fields->fingers > 1) {
- start_bit = priv->x_bits - x_msb;
- end_bit = priv->x_bits - x_lsb;
- box_middle_x = (priv->x_max * (start_bit + end_bit)) /
- (2 * (priv->x_bits - 1));
-
- start_bit = y_lsb - 1;
- end_bit = y_msb - 1;
- box_middle_y = (priv->y_max * (start_bit + end_bit)) /
- (2 * (priv->y_bits - 1));
- fields->mt[0] = fields->st;
- fields->mt[1].x = 2 * box_middle_x - fields->mt[0].x;
- fields->mt[1].y = 2 * box_middle_y - fields->mt[0].y;
- }
-}
-
static void alps_get_bitmap_points(unsigned int map,
struct alps_bitmap_point *low,
struct alps_bitmap_point *high,
@@ -384,7 +337,7 @@ static void alps_get_bitmap_points(unsigned int map,
}
/*
- * Process bitmap data from v3 and v4 protocols. Returns the number of
+ * Process bitmap data from semi-mt protocols. Returns the number of
* fingers detected. A return value of 0 means at least one of the
* bitmaps was empty.
*
@@ -396,9 +349,10 @@ static void alps_get_bitmap_points(unsigned int map,
static int alps_process_bitmap(struct alps_data *priv,
struct alps_fields *fields)
{
- int i, fingers_x = 0, fingers_y = 0, fingers;
+ int i, fingers_x = 0, fingers_y = 0, fingers, closest;
struct alps_bitmap_point x_low = {0,}, x_high = {0,};
struct alps_bitmap_point y_low = {0,}, y_high = {0,};
+ struct input_mt_pos corner[4];
if (!fields->x_map || !fields->y_map)
return 0;
@@ -429,26 +383,76 @@ static int alps_process_bitmap(struct alps_data *priv,
y_high.num_bits = max(i, 1);
}
- fields->mt[0].x =
+ /* top-left corner */
+ corner[0].x =
(priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
(2 * (priv->x_bits - 1));
- fields->mt[0].y =
+ corner[0].y =
(priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
(2 * (priv->y_bits - 1));
- fields->mt[1].x =
+ /* top-right corner */
+ corner[1].x =
(priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
(2 * (priv->x_bits - 1));
- fields->mt[1].y =
+ corner[1].y =
+ (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
+ (2 * (priv->y_bits - 1));
+
+ /* bottom-right corner */
+ corner[2].x =
+ (priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
+ (2 * (priv->x_bits - 1));
+ corner[2].y =
+ (priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
+ (2 * (priv->y_bits - 1));
+
+ /* bottom-left corner */
+ corner[3].x =
+ (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
+ (2 * (priv->x_bits - 1));
+ corner[3].y =
(priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
(2 * (priv->y_bits - 1));
- /* y-bitmap order is reversed, except on rushmore */
- if (priv->proto_version != ALPS_PROTO_V3_RUSHMORE) {
- fields->mt[0].y = priv->y_max - fields->mt[0].y;
- fields->mt[1].y = priv->y_max - fields->mt[1].y;
+ /* x-bitmap order is reversed on v5 touchpads */
+ if (priv->proto_version == ALPS_PROTO_V5) {
+ for (i = 0; i < 4; i++)
+ corner[i].x = priv->x_max - corner[i].x;
+ }
+
+ /* y-bitmap order is reversed on v3 and v4 touchpads */
+ if (priv->proto_version == ALPS_PROTO_V3 ||
+ priv->proto_version == ALPS_PROTO_V4) {
+ for (i = 0; i < 4; i++)
+ corner[i].y = priv->y_max - corner[i].y;
+ }
+
+ /*
+ * We only select a corner for the second touch once per 2 finger
+ * touch sequence to avoid the chosen corner (and thus the coordinates)
+ * jumping around when the first touch is in the middle.
+ */
+ if (priv->second_touch == -1) {
+ /* Find corner closest to our st coordinates */
+ closest = 0x7fffffff;
+ for (i = 0; i < 4; i++) {
+ int dx = fields->st.x - corner[i].x;
+ int dy = fields->st.y - corner[i].y;
+ int distance = dx * dx + dy * dy;
+
+ if (distance < closest) {
+ priv->second_touch = i;
+ closest = distance;
+ }
+ }
+ /* And select the opposite corner to use for the 2nd touch */
+ priv->second_touch = (priv->second_touch + 2) % 4;
}
+ fields->mt[0] = fields->st;
+ fields->mt[1] = corner[priv->second_touch];
+
return fingers;
}
@@ -485,9 +489,14 @@ static void alps_report_semi_mt_data(struct psmouse *psmouse, int fingers)
f->mt[0].x = f->st.x;
f->mt[0].y = f->st.y;
fingers = f->pressure > 0 ? 1 : 0;
+ priv->second_touch = -1;
}
- alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 2);
+ if (fingers >= 1)
+ alps_set_slot(dev, 0, f->mt[0].x, f->mt[0].y);
+ if (fingers >= 2)
+ alps_set_slot(dev, 1, f->mt[1].x, f->mt[1].y);
+ input_mt_sync_frame(dev);
input_mt_report_finger_count(dev, fingers);
@@ -584,20 +593,22 @@ static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
f->first_mp = !!(p[4] & 0x40);
f->is_mp = !!(p[0] & 0x40);
- f->fingers = (p[5] & 0x3) + 1;
- f->x_map = ((p[4] & 0x7e) << 8) |
- ((p[1] & 0x7f) << 2) |
- ((p[0] & 0x30) >> 4);
- f->y_map = ((p[3] & 0x70) << 4) |
- ((p[2] & 0x7f) << 1) |
- (p[4] & 0x01);
-
- f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
- ((p[0] & 0x30) >> 4);
- f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
- f->pressure = p[5] & 0x7f;
+ if (f->is_mp) {
+ f->fingers = (p[5] & 0x3) + 1;
+ f->x_map = ((p[4] & 0x7e) << 8) |
+ ((p[1] & 0x7f) << 2) |
+ ((p[0] & 0x30) >> 4);
+ f->y_map = ((p[3] & 0x70) << 4) |
+ ((p[2] & 0x7f) << 1) |
+ (p[4] & 0x01);
+ } else {
+ f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
+ ((p[0] & 0x30) >> 4);
+ f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
+ f->pressure = p[5] & 0x7f;
- alps_decode_buttons_v3(f, p);
+ alps_decode_buttons_v3(f, p);
+ }
return 0;
}
@@ -605,13 +616,27 @@ static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
struct psmouse *psmouse)
{
- alps_decode_pinnacle(f, p, psmouse);
-
- /* Rushmore's packet decode has a bit difference with Pinnacle's */
+ f->first_mp = !!(p[4] & 0x40);
f->is_mp = !!(p[5] & 0x40);
- f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1;
- f->x_map |= (p[5] & 0x10) << 11;
- f->y_map |= (p[5] & 0x20) << 6;
+
+ if (f->is_mp) {
+ f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1;
+ f->x_map = ((p[5] & 0x10) << 11) |
+ ((p[4] & 0x7e) << 8) |
+ ((p[1] & 0x7f) << 2) |
+ ((p[0] & 0x30) >> 4);
+ f->y_map = ((p[5] & 0x20) << 6) |
+ ((p[3] & 0x70) << 4) |
+ ((p[2] & 0x7f) << 1) |
+ (p[4] & 0x01);
+ } else {
+ f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
+ ((p[0] & 0x30) >> 4);
+ f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
+ f->pressure = p[5] & 0x7f;
+
+ alps_decode_buttons_v3(f, p);
+ }
return 0;
}
@@ -680,30 +705,13 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
*/
if (f->is_mp) {
fingers = f->fingers;
- if (priv->proto_version == ALPS_PROTO_V3 ||
- priv->proto_version == ALPS_PROTO_V3_RUSHMORE) {
- if (alps_process_bitmap(priv, f) == 0)
- fingers = 0; /* Use st data */
-
- /* Now process position packet */
- priv->decode_fields(f, priv->multi_data,
- psmouse);
- } else {
- /*
- * Because Dolphin uses position packet's
- * coordinate data as Pt1 and uses it to
- * calculate Pt2, so we need to do position
- * packet decode first.
- */
- priv->decode_fields(f, priv->multi_data,
- psmouse);
-
- /*
- * Since Dolphin's finger number is reliable,
- * there is no need to compare with bmap_fn.
- */
- alps_process_bitmap_dolphin(priv, f);
- }
+ /*
+ * Bitmap processing uses position packet's coordinate
+ * data, so we need to do decode it first.
+ */
+ priv->decode_fields(f, priv->multi_data, psmouse);
+ if (alps_process_bitmap(priv, f) == 0)
+ fingers = 0; /* Use st data */
} else {
priv->multi_packet = 0;
}
@@ -865,6 +873,14 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
priv->multi_data[offset] = packet[6];
priv->multi_data[offset + 1] = packet[7];
+ f->left = !!(packet[4] & 0x01);
+ f->right = !!(packet[4] & 0x02);
+
+ f->st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
+ ((packet[0] & 0x30) >> 4);
+ f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
+ f->pressure = packet[5] & 0x7f;
+
if (++priv->multi_packet > 2) {
priv->multi_packet = 0;
@@ -879,14 +895,6 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
f->fingers = alps_process_bitmap(priv, f);
}
- f->left = !!(packet[4] & 0x01);
- f->right = !!(packet[4] & 0x02);
-
- f->st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
- ((packet[0] & 0x30) >> 4);
- f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
- f->pressure = packet[5] & 0x7f;
-
alps_report_semi_mt_data(psmouse, f->fingers);
}
@@ -2561,7 +2569,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
case ALPS_PROTO_V3:
priv->hw_init = alps_hw_init_v3;
priv->process_packet = alps_process_packet_v3;
- priv->set_abs_params = alps_set_abs_params_mt;
+ priv->set_abs_params = alps_set_abs_params_semi_mt;
priv->decode_fields = alps_decode_pinnacle;
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
@@ -2570,7 +2578,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
case ALPS_PROTO_V3_RUSHMORE:
priv->hw_init = alps_hw_init_rushmore_v3;
priv->process_packet = alps_process_packet_v3;
- priv->set_abs_params = alps_set_abs_params_mt;
+ priv->set_abs_params = alps_set_abs_params_semi_mt;
priv->decode_fields = alps_decode_rushmore;
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
@@ -2586,7 +2594,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
case ALPS_PROTO_V4:
priv->hw_init = alps_hw_init_v4;
priv->process_packet = alps_process_packet_v4;
- priv->set_abs_params = alps_set_abs_params_mt;
+ priv->set_abs_params = alps_set_abs_params_semi_mt;
priv->nibble_commands = alps_v4_nibble_commands;
priv->addr_command = PSMOUSE_CMD_DISABLE;
break;
@@ -2595,7 +2603,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
priv->hw_init = alps_hw_init_dolphin_v1;
priv->process_packet = alps_process_touchpad_packet_v3_v5;
priv->decode_fields = alps_decode_dolphin;
- priv->set_abs_params = alps_set_abs_params_mt;
+ priv->set_abs_params = alps_set_abs_params_semi_mt;
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
priv->x_bits = 23;
@@ -2777,15 +2785,15 @@ static void alps_set_abs_params_mt_common(struct alps_data *priv,
set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
}
-static void alps_set_abs_params_mt(struct alps_data *priv,
- struct input_dev *dev1)
+static void alps_set_abs_params_semi_mt(struct alps_data *priv,
+ struct input_dev *dev1)
{
alps_set_abs_params_mt_common(priv, dev1);
input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
input_mt_init_slots(dev1, MAX_TOUCHES,
INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
- INPUT_MT_TRACK | INPUT_MT_SEMI_MT);
+ INPUT_MT_SEMI_MT);
}
static void alps_set_abs_params_v7(struct alps_data *priv,
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 6dfdccc3a7c6..d37f814dc447 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -278,6 +278,7 @@ struct alps_data {
int prev_fin;
int multi_packet;
+ int second_touch;
unsigned char multi_data[6];
struct alps_fields f;
u8 quirks;
diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c
index 1e2291c378fe..3faf01c1b191 100644
--- a/drivers/input/mouse/cyapa_gen3.c
+++ b/drivers/input/mouse/cyapa_gen3.c
@@ -950,14 +950,13 @@ static u16 cyapa_get_wait_time_for_pwr_cmd(u8 pwr_mode)
* Device power mode can only be set when device is in operational mode.
*/
static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode,
- u16 always_unused)
+ u16 always_unused)
{
int ret;
u8 power;
int tries;
u16 sleep_time;
- always_unused = 0;
if (cyapa->state != CYAPA_STATE_OP)
return 0;
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
index 5b611dd71e79..afc39e799da2 100644
--- a/drivers/input/mouse/cyapa_gen5.c
+++ b/drivers/input/mouse/cyapa_gen5.c
@@ -352,7 +352,7 @@ struct gen5_app_cmd_head {
u8 parameter_data[0]; /* Parameter data variable based on cmd_code */
} __packed;
-/* Applicaton get/set parameter command data structure */
+/* Application get/set parameter command data structure */
struct gen5_app_set_parameter_data {
u8 parameter_id;
u8 parameter_size;
@@ -832,7 +832,7 @@ static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data)
int ret;
/* 0x20 0x00 0xF7 is Gen5 Application HID Description Header;
- * 0x20 0x00 0xFF is Gen5 Booloader HID Description Header.
+ * 0x20 0x00 0xFF is Gen5 Bootloader HID Description Header.
*
* Must read HID Description content through out,
* otherwise Gen5 trackpad cannot response next command
@@ -1654,8 +1654,8 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
* that trackpad unable to report signal to wake system up
* in the special situation that system is in suspending, and
* at the same time, user touch trackpad to wake system up.
- * This function can avoid the data to be buffured when system
- * is suspending which may cause interrput line unable to be
+ * This function can avoid the data to be buffered when system
+ * is suspending which may cause interrupt line unable to be
* asserted again.
*/
cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
@@ -2546,16 +2546,11 @@ static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa)
gen5_pip->resp_sort_func(cyapa,
gen5_pip->irq_cmd_buf, length))) {
/*
- * Cover the Gen5 V1 firmware issue.
- * The issue is there is no interrut will be
- * asserted to notityf host to read a command
- * data out when always has finger touch on
- * trackpad during the command is issued to
- * trackad device.
- * This issue has the scenario is that,
- * user always has his fingers touched on
- * trackpad device when booting/rebooting
- * their chrome book.
+ * Work around the Gen5 V1 firmware
+ * that does not assert interrupt signalling
+ * that command response is ready if user
+ * keeps touching the trackpad while command
+ * is sent to the device.
*/
length = 0;
if (gen5_pip->resp_len)
diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h
index 6d5f8a4c1748..73670f2aebfd 100644
--- a/drivers/input/mouse/elan_i2c.h
+++ b/drivers/input/mouse/elan_i2c.h
@@ -28,14 +28,13 @@
#define ETP_PRESSURE_OFFSET 25
/* IAP Firmware handling */
-#define ETP_FW_NAME "elan_i2c.bin"
+#define ETP_PRODUCT_ID_FORMAT_STRING "%d.0"
+#define ETP_FW_NAME "elan_i2c_" ETP_PRODUCT_ID_FORMAT_STRING ".bin"
#define ETP_IAP_START_ADDR 0x0083
#define ETP_FW_IAP_PAGE_ERR (1 << 5)
#define ETP_FW_IAP_INTF_ERR (1 << 4)
#define ETP_FW_PAGE_SIZE 64
-#define ETP_FW_VAILDPAGE_COUNT 768
#define ETP_FW_SIGNATURE_SIZE 6
-#define ETP_FW_SIGNATURE_ADDRESS 0xBFFA
struct i2c_client;
struct completion;
@@ -58,7 +57,8 @@ struct elan_transport_ops {
bool max_baseliune, u8 *value);
int (*get_version)(struct i2c_client *client, bool iap, u8 *version);
- int (*get_sm_version)(struct i2c_client *client, u8 *version);
+ int (*get_sm_version)(struct i2c_client *client,
+ u8* ic_type, u8 *version);
int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum);
int (*get_product_id)(struct i2c_client *client, u8 *id);
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index fd5068b2542d..62641f2adaf7 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -4,7 +4,7 @@
* Copyright (c) 2013 ELAN Microelectronics Corp.
*
* Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
- * Version: 1.5.7
+ * Version: 1.5.9
*
* Based on cyapa driver:
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
@@ -40,7 +40,7 @@
#include "elan_i2c.h"
#define DRIVER_NAME "elan_i2c"
-#define ELAN_DRIVER_VERSION "1.5.7"
+#define ELAN_DRIVER_VERSION "1.5.9"
#define ETP_MAX_PRESSURE 255
#define ETP_FWIDTH_REDUCE 90
#define ETP_FINGER_WIDTH 15
@@ -83,6 +83,9 @@ struct elan_tp_data {
u16 fw_checksum;
int pressure_adjustment;
u8 mode;
+ u8 ic_type;
+ u16 fw_vaildpage_count;
+ u16 fw_signature_address;
bool irq_wake;
@@ -91,6 +94,29 @@ struct elan_tp_data {
bool baseline_ready;
};
+static int elan_get_fwinfo(u8 ic_type, u16 *vaildpage_count,
+ u16 *signature_address)
+{
+ switch(ic_type) {
+ case 0x09:
+ *vaildpage_count = 768;
+ break;
+ case 0x0D:
+ *vaildpage_count = 896;
+ break;
+ default:
+ /* unknown ic type clear value */
+ *vaildpage_count = 0;
+ *signature_address = 0;
+ return -ENXIO;
+ }
+
+ *signature_address =
+ (*vaildpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE;
+
+ return 0;
+}
+
static int elan_enable_power(struct elan_tp_data *data)
{
int repeat = ETP_RETRY_COUNT;
@@ -221,7 +247,8 @@ static int elan_query_device_info(struct elan_tp_data *data)
if (error)
return error;
- error = data->ops->get_sm_version(data->client, &data->sm_version);
+ error = data->ops->get_sm_version(data->client, &data->ic_type,
+ &data->sm_version);
if (error)
return error;
@@ -234,6 +261,14 @@ static int elan_query_device_info(struct elan_tp_data *data)
if (error)
return error;
+ error = elan_get_fwinfo(data->ic_type, &data->fw_vaildpage_count,
+ &data->fw_signature_address);
+ if (error) {
+ dev_err(&data->client->dev,
+ "unknown ic type %d\n", data->ic_type);
+ return error;
+ }
+
return 0;
}
@@ -318,7 +353,7 @@ static int __elan_update_firmware(struct elan_tp_data *data,
iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]);
boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE;
- for (i = boot_page_count; i < ETP_FW_VAILDPAGE_COUNT; i++) {
+ for (i = boot_page_count; i < data->fw_vaildpage_count; i++) {
u16 checksum = 0;
const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE];
@@ -403,7 +438,8 @@ static ssize_t elan_sysfs_read_product_id(struct device *dev,
struct i2c_client *client = to_i2c_client(dev);
struct elan_tp_data *data = i2c_get_clientdata(client);
- return sprintf(buf, "%d.0\n", data->product_id);
+ return sprintf(buf, ETP_PRODUCT_ID_FORMAT_STRING "\n",
+ data->product_id);
}
static ssize_t elan_sysfs_read_fw_ver(struct device *dev,
@@ -442,19 +478,28 @@ static ssize_t elan_sysfs_update_fw(struct device *dev,
{
struct elan_tp_data *data = dev_get_drvdata(dev);
const struct firmware *fw;
+ char *fw_name;
int error;
const u8 *fw_signature;
static const u8 signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF};
- error = request_firmware(&fw, ETP_FW_NAME, dev);
+ /* Look for a firmware with the product id appended. */
+ fw_name = kasprintf(GFP_KERNEL, ETP_FW_NAME, data->product_id);
+ if (!fw_name) {
+ dev_err(dev, "failed to allocate memory for firmware name\n");
+ return -ENOMEM;
+ }
+
+ dev_info(dev, "requesting fw '%s'\n", fw_name);
+ error = request_firmware(&fw, fw_name, dev);
+ kfree(fw_name);
if (error) {
- dev_err(dev, "cannot load firmware %s: %d\n",
- ETP_FW_NAME, error);
+ dev_err(dev, "failed to request firmware: %d\n", error);
return error;
}
/* Firmware file must match signature data */
- fw_signature = &fw->data[ETP_FW_SIGNATURE_ADDRESS];
+ fw_signature = &fw->data[data->fw_signature_address];
if (memcmp(fw_signature, signature, sizeof(signature)) != 0) {
dev_err(dev, "signature mismatch (expected %*ph, got %*ph)\n",
(int)sizeof(signature), signature,
diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c
index a0acbbf83bfd..683c840c9dd7 100644
--- a/drivers/input/mouse/elan_i2c_i2c.c
+++ b/drivers/input/mouse/elan_i2c_i2c.c
@@ -259,7 +259,8 @@ static int elan_i2c_get_version(struct i2c_client *client,
return 0;
}
-static int elan_i2c_get_sm_version(struct i2c_client *client, u8 *version)
+static int elan_i2c_get_sm_version(struct i2c_client *client,
+ u8 *ic_type, u8 *version)
{
int error;
u8 val[3];
@@ -271,6 +272,7 @@ static int elan_i2c_get_sm_version(struct i2c_client *client, u8 *version)
}
*version = val[0];
+ *ic_type = val[1];
return 0;
}
diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c
index 30ab80dbcdd6..ff36a366b2aa 100644
--- a/drivers/input/mouse/elan_i2c_smbus.c
+++ b/drivers/input/mouse/elan_i2c_smbus.c
@@ -165,7 +165,8 @@ static int elan_smbus_get_version(struct i2c_client *client,
return 0;
}
-static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *version)
+static int elan_smbus_get_sm_version(struct i2c_client *client,
+ u8 *ic_type, u8 *version)
{
int error;
u8 val[3];
@@ -177,7 +178,8 @@ static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *version)
return error;
}
- *version = val[0]; /* XXX Why 0 and not 2 as in IAP/FW versions? */
+ *version = val[0];
+ *ic_type = val[1];
return 0;
}
diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c
index 23d259416f2f..4d5576de81be 100644
--- a/drivers/input/mouse/focaltech.c
+++ b/drivers/input/mouse/focaltech.c
@@ -103,6 +103,16 @@ struct focaltech_hw_state {
*/
struct focaltech_finger_state fingers[FOC_MAX_FINGERS];
+ /*
+ * Finger width 0-7 and 15 for a very big contact area.
+ * 15 value stays until the finger is released.
+ * Width is reported only in absolute packets.
+ * Since hardware reports width only for last touching finger,
+ * there is no need to store width for every specific finger,
+ * so we keep only last value reported.
+ */
+ unsigned int width;
+
/* True if the clickpad has been pressed. */
bool pressed;
};
@@ -137,6 +147,7 @@ static void focaltech_report_state(struct psmouse *psmouse)
input_report_abs(dev, ABS_MT_POSITION_X, clamped_x);
input_report_abs(dev, ABS_MT_POSITION_Y,
priv->y_max - clamped_y);
+ input_report_abs(dev, ABS_TOOL_WIDTH, state->width);
}
}
input_mt_report_pointer_emulation(dev, true);
@@ -187,6 +198,7 @@ static void focaltech_process_abs_packet(struct psmouse *psmouse,
state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2];
state->fingers[finger].y = (packet[3] << 8) | packet[4];
+ state->width = packet[5] >> 4;
state->fingers[finger].valid = true;
}
@@ -331,6 +343,7 @@ static void focaltech_set_input_params(struct psmouse *psmouse)
__set_bit(EV_ABS, dev->evbit);
input_set_abs_params(dev, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
+ input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
input_mt_init_slots(dev, 5, INPUT_MT_POINTER);
__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
}
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 5bb1658f60c7..7c4ba43d253e 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -63,7 +63,7 @@ static unsigned int psmouse_rate = 100;
module_param_named(rate, psmouse_rate, uint, 0644);
MODULE_PARM_DESC(rate, "Report rate, in reports per second.");
-static bool psmouse_smartscroll = 1;
+static bool psmouse_smartscroll = true;
module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h
index aa697ece405b..42df9e3beae8 100644
--- a/drivers/input/mouse/sentelic.h
+++ b/drivers/input/mouse/sentelic.h
@@ -123,11 +123,11 @@ struct fsp_data {
extern int fsp_detect(struct psmouse *psmouse, bool set_properties);
extern int fsp_init(struct psmouse *psmouse);
#else
-inline int fsp_detect(struct psmouse *psmouse, bool set_properties)
+static inline int fsp_detect(struct psmouse *psmouse, bool set_properties)
{
return -ENOSYS;
}
-inline int fsp_init(struct psmouse *psmouse)
+static inline int fsp_init(struct psmouse *psmouse)
{
return -ENOSYS;
}
diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c
index 878f18498f3b..ffceedcaf3c8 100644
--- a/drivers/input/mouse/synaptics_i2c.c
+++ b/drivers/input/mouse/synaptics_i2c.c
@@ -185,7 +185,7 @@
#define NO_DATA_SLEEP_MSECS (MSEC_PER_SEC / 4)
/* Control touchpad's No Deceleration option */
-static bool no_decel = 1;
+static bool no_decel = true;
module_param(no_decel, bool, 0644);
MODULE_PARM_DESC(no_decel, "No Deceleration. Default = 1 (on)");
@@ -340,9 +340,9 @@ static bool synaptics_i2c_get_input(struct synaptics_i2c *touch)
s32 data;
s8 x_delta, y_delta;
- /* Deal with spontanious resets and errors */
+ /* Deal with spontaneous resets and errors */
if (synaptics_i2c_check_error(touch->client))
- return 0;
+ return false;
/* Get Gesture Bit */
data = synaptics_i2c_reg_get(touch->client, DATA_REG0);
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 80f6386709bf..7afa6a2b776c 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -958,6 +958,7 @@ config TOUCHSCREEN_ST1232
config TOUCHSCREEN_STMPE
tristate "STMicroelectronics STMPE touchscreens"
depends on MFD_STMPE
+ depends on (OF || COMPILE_TEST)
help
Say Y here if you want support for STMicroelectronics
STMPE touchscreen controllers.
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 40b98dda8f38..dfc7309e3d38 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -726,15 +726,15 @@ static void mxt_input_button(struct mxt_data *data, u8 *message)
{
struct input_dev *input = data->input_dev;
const struct mxt_platform_data *pdata = data->pdata;
- bool button;
int i;
- /* Active-low switch */
for (i = 0; i < pdata->t19_num_keys; i++) {
if (pdata->t19_keymap[i] == KEY_RESERVED)
continue;
- button = !(message[1] & (1 << i));
- input_report_key(input, pdata->t19_keymap[i], button);
+
+ /* Active-low switch */
+ input_report_key(input, pdata->t19_keymap[i],
+ !(message[1] & BIT(i)));
}
}
diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c
index 568a3d340c8a..5ed31057430c 100644
--- a/drivers/input/touchscreen/cyttsp4_core.c
+++ b/drivers/input/touchscreen/cyttsp4_core.c
@@ -775,7 +775,6 @@ static void cyttsp4_get_touch(struct cyttsp4_mt_data *md,
struct device *dev = &md->input->dev;
struct cyttsp4_sysinfo *si = md->si;
enum cyttsp4_tch_abs abs;
- int tmp;
bool flipped;
for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) {
@@ -790,9 +789,7 @@ static void cyttsp4_get_touch(struct cyttsp4_mt_data *md,
}
if (md->pdata->flags & CY_FLAG_FLIP) {
- tmp = touch->abs[CY_TCH_X];
- touch->abs[CY_TCH_X] = touch->abs[CY_TCH_Y];
- touch->abs[CY_TCH_Y] = tmp;
+ swap(touch->abs[CY_TCH_X], touch->abs[CY_TCH_Y]);
flipped = true;
} else
flipped = false;
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index 3af16984d57c..b4d12e29abff 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -47,7 +47,7 @@ struct goodix_ts_data {
/* Register defines */
#define GOODIX_READ_COOR_ADDR 0x814E
#define GOODIX_REG_CONFIG_DATA 0x8047
-#define GOODIX_REG_VERSION 0x8140
+#define GOODIX_REG_ID 0x8140
#define RESOLUTION_LOC 1
#define MAX_CONTACTS_LOC 5
@@ -69,7 +69,7 @@ static const unsigned long goodix_irq_flags[] = {
* @len: length of the buffer to write
*/
static int goodix_i2c_read(struct i2c_client *client,
- u16 reg, u8 *buf, int len)
+ u16 reg, u8 *buf, int len)
{
struct i2c_msg msgs[2];
u16 wbuf = cpu_to_be16(reg);
@@ -78,7 +78,7 @@ static int goodix_i2c_read(struct i2c_client *client,
msgs[0].flags = 0;
msgs[0].addr = client->addr;
msgs[0].len = 2;
- msgs[0].buf = (u8 *) &wbuf;
+ msgs[0].buf = (u8 *)&wbuf;
msgs[1].flags = I2C_M_RD;
msgs[1].addr = client->addr;
@@ -101,6 +101,9 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
return error;
}
+ if (!(data[0] & 0x80))
+ return -EAGAIN;
+
touch_num = data[0] & 0x0f;
if (touch_num > ts->max_touch_num)
return -EPROTO;
@@ -144,7 +147,7 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
*/
static void goodix_process_events(struct goodix_ts_data *ts)
{
- u8 point_data[1 + GOODIX_CONTACT_SIZE * ts->max_touch_num];
+ u8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
int touch_num;
int i;
@@ -196,8 +199,8 @@ static void goodix_read_config(struct goodix_ts_data *ts)
int error;
error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA,
- config,
- GOODIX_CONFIG_MAX_LENGTH);
+ config,
+ GOODIX_CONFIG_MAX_LENGTH);
if (error) {
dev_warn(&ts->client->dev,
"Error reading config (%d), using defaults\n",
@@ -227,22 +230,28 @@ static void goodix_read_config(struct goodix_ts_data *ts)
*
* @client: the i2c client
* @version: output buffer containing the version on success
+ * @id: output buffer containing the id on success
*/
-static int goodix_read_version(struct i2c_client *client, u16 *version)
+static int goodix_read_version(struct i2c_client *client, u16 *version, u16 *id)
{
int error;
u8 buf[6];
+ char id_str[5];
- error = goodix_i2c_read(client, GOODIX_REG_VERSION, buf, sizeof(buf));
+ error = goodix_i2c_read(client, GOODIX_REG_ID, buf, sizeof(buf));
if (error) {
dev_err(&client->dev, "read version failed: %d\n", error);
return error;
}
- if (version)
- *version = get_unaligned_le16(&buf[4]);
+ memcpy(id_str, buf, 4);
+ id_str[4] = 0;
+ if (kstrtou16(id_str, 10, id))
+ *id = 0x1001;
+
+ *version = get_unaligned_le16(&buf[4]);
- dev_info(&client->dev, "IC VERSION: %6ph\n", buf);
+ dev_info(&client->dev, "ID %d, version: %04x\n", *id, *version);
return 0;
}
@@ -276,10 +285,13 @@ static int goodix_i2c_test(struct i2c_client *client)
* goodix_request_input_dev - Allocate, populate and register the input device
*
* @ts: our goodix_ts_data pointer
+ * @version: device firmware version
+ * @id: device ID
*
* Must be called during probe
*/
-static int goodix_request_input_dev(struct goodix_ts_data *ts)
+static int goodix_request_input_dev(struct goodix_ts_data *ts, u16 version,
+ u16 id)
{
int error;
@@ -289,14 +301,10 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts)
return -ENOMEM;
}
- ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) |
- BIT_MASK(EV_KEY) |
- BIT_MASK(EV_ABS);
-
- input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0,
- ts->abs_x_max, 0, 0);
- input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0,
- ts->abs_y_max, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
+ 0, ts->abs_x_max, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
+ 0, ts->abs_y_max, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
@@ -307,8 +315,8 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts)
ts->input_dev->phys = "input/ts";
ts->input_dev->id.bustype = BUS_I2C;
ts->input_dev->id.vendor = 0x0416;
- ts->input_dev->id.product = 0x1001;
- ts->input_dev->id.version = 10427;
+ ts->input_dev->id.product = id;
+ ts->input_dev->id.version = version;
error = input_register_device(ts->input_dev);
if (error) {
@@ -326,7 +334,7 @@ static int goodix_ts_probe(struct i2c_client *client,
struct goodix_ts_data *ts;
unsigned long irq_flags;
int error;
- u16 version_info;
+ u16 version_info, id_info;
dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr);
@@ -348,7 +356,7 @@ static int goodix_ts_probe(struct i2c_client *client,
return error;
}
- error = goodix_read_version(client, &version_info);
+ error = goodix_read_version(client, &version_info, &id_info);
if (error) {
dev_err(&client->dev, "Read version failed.\n");
return error;
@@ -356,7 +364,7 @@ static int goodix_ts_probe(struct i2c_client *client,
goodix_read_config(ts);
- error = goodix_request_input_dev(ts);
+ error = goodix_request_input_dev(ts, version_info, id_info);
if (error)
return error;
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 2c2107147319..8f3e243a62bf 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -78,7 +78,7 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
}
ret = i2c_master_recv(tsdata->client, rdbuf, readsize);
- if (ret != sizeof(rdbuf)) {
+ if (ret != readsize) {
dev_err(&tsdata->client->dev,
"%s: i2c_master_recv failed(), ret=%d\n",
__func__, ret);
diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c
index bdfa27dc097b..a4a103e1d11b 100644
--- a/drivers/input/touchscreen/s3c2410_ts.c
+++ b/drivers/input/touchscreen/s3c2410_ts.c
@@ -411,7 +411,7 @@ static const struct dev_pm_ops s3c_ts_pmops = {
};
#endif
-static struct platform_device_id s3cts_driver_ids[] = {
+static const struct platform_device_id s3cts_driver_ids[] = {
{ "s3c2410-ts", 0 },
{ "s3c2440-ts", 0 },
{ "s3c64xx-ts", FEAT_PEN_IRQ },
diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c
index e4c31256a74d..e414d43e5159 100644
--- a/drivers/input/touchscreen/stmpe-ts.c
+++ b/drivers/input/touchscreen/stmpe-ts.c
@@ -267,27 +267,10 @@ static void stmpe_ts_close(struct input_dev *dev)
static void stmpe_ts_get_platform_info(struct platform_device *pdev,
struct stmpe_touch *ts)
{
- struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
struct device_node *np = pdev->dev.of_node;
- struct stmpe_ts_platform_data *ts_pdata = NULL;
-
- ts->stmpe = stmpe;
-
- if (stmpe->pdata && stmpe->pdata->ts) {
- ts_pdata = stmpe->pdata->ts;
-
- ts->sample_time = ts_pdata->sample_time;
- ts->mod_12b = ts_pdata->mod_12b;
- ts->ref_sel = ts_pdata->ref_sel;
- ts->adc_freq = ts_pdata->adc_freq;
- ts->ave_ctrl = ts_pdata->ave_ctrl;
- ts->touch_det_delay = ts_pdata->touch_det_delay;
- ts->settling = ts_pdata->settling;
- ts->fraction_z = ts_pdata->fraction_z;
- ts->i_drive = ts_pdata->i_drive;
- } else if (np) {
- u32 val;
+ u32 val;
+ if (np) {
if (!of_property_read_u32(np, "st,sample-time", &val))
ts->sample_time = val;
if (!of_property_read_u32(np, "st,mod-12b", &val))
@@ -311,6 +294,7 @@ static void stmpe_ts_get_platform_info(struct platform_device *pdev,
static int stmpe_input_probe(struct platform_device *pdev)
{
+ struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
struct stmpe_touch *ts;
struct input_dev *idev;
int error;
@@ -329,6 +313,7 @@ static int stmpe_input_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, ts);
+ ts->stmpe = stmpe;
ts->idev = idev;
ts->dev = &pdev->dev;
@@ -351,14 +336,13 @@ static int stmpe_input_probe(struct platform_device *pdev)
idev->name = STMPE_TS_NAME;
idev->phys = STMPE_TS_NAME"/input0";
idev->id.bustype = BUS_I2C;
- idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
idev->open = stmpe_ts_open;
idev->close = stmpe_ts_close;
input_set_drvdata(idev, ts);
+ input_set_capability(idev, EV_KEY, BTN_TOUCH);
input_set_abs_params(idev, ABS_X, 0, XY_MASK, 0, 0);
input_set_abs_params(idev, ABS_Y, 0, XY_MASK, 0, 0);
input_set_abs_params(idev, ABS_PRESSURE, 0x0, 0xff, 0, 0);
@@ -383,14 +367,19 @@ static int stmpe_ts_remove(struct platform_device *pdev)
static struct platform_driver stmpe_ts_driver = {
.driver = {
- .name = STMPE_TS_NAME,
- },
+ .name = STMPE_TS_NAME,
+ },
.probe = stmpe_input_probe,
.remove = stmpe_ts_remove,
};
module_platform_driver(stmpe_ts_driver);
+static const struct of_device_id stmpe_ts_ids[] = {
+ { .compatible = "st,stmpe-ts", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, stmpe_ts_ids);
+
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
MODULE_DESCRIPTION("STMPEXXX touchscreen driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" STMPE_TS_NAME);
diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c
index 19880c7385e3..f58a196521a9 100644
--- a/drivers/input/touchscreen/zforce_ts.c
+++ b/drivers/input/touchscreen/zforce_ts.c
@@ -30,7 +30,6 @@
#include <linux/input/mt.h>
#include <linux/platform_data/zforce_ts.h>
#include <linux/regulator/consumer.h>
-#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index 1cc6ca8bfbda..85cfa4f8691f 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -2264,7 +2264,7 @@ static int capidrv_addcontr(u16 contr, struct capi_profile *profp)
return -1;
}
card->owner = THIS_MODULE;
- init_timer(&card->listentimer);
+ setup_timer(&card->listentimer, listentimerfunc, (unsigned long)card);
strcpy(card->name, id);
card->contrnr = contr;
card->nbchan = profp->nbchannel;
@@ -2331,8 +2331,6 @@ static int capidrv_addcontr(u16 contr, struct capi_profile *profp)
card->cipmask = 0x1FFF03FF; /* any */
card->cipmask2 = 0;
- card->listentimer.data = (unsigned long)card;
- card->listentimer.function = listentimerfunc;
send_listen(card);
mod_timer(&card->listentimer, jiffies + 60 * HZ);
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
index 97465ac5a2d5..eb83d94ab4fe 100644
--- a/drivers/isdn/hisax/Kconfig
+++ b/drivers/isdn/hisax/Kconfig
@@ -237,7 +237,7 @@ config HISAX_MIC
config HISAX_NETJET
bool "NETjet card"
- depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN)))
+ depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE))
depends on VIRT_TO_BUS
help
This enables HiSax support for the NetJet from Traverse
@@ -249,7 +249,7 @@ config HISAX_NETJET
config HISAX_NETJET_U
bool "NETspider U card"
- depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN)))
+ depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE))
depends on VIRT_TO_BUS
help
This enables HiSax support for the Netspider U interface ISDN card
diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c
index ead0a4fb7448..a0fdbc074b98 100644
--- a/drivers/isdn/hisax/st5481_usb.c
+++ b/drivers/isdn/hisax/st5481_usb.c
@@ -267,8 +267,8 @@ int st5481_setup_usb(struct st5481_adapter *adapter)
}
// The descriptor is wrong for some early samples of the ST5481 chip
- altsetting->endpoint[3].desc.wMaxPacketSize = __constant_cpu_to_le16(32);
- altsetting->endpoint[4].desc.wMaxPacketSize = __constant_cpu_to_le16(32);
+ altsetting->endpoint[3].desc.wMaxPacketSize = cpu_to_le16(32);
+ altsetting->endpoint[4].desc.wMaxPacketSize = cpu_to_le16(32);
// Use alternative setting 3 on interface 0 to have 2B+D
if ((status = usb_set_interface(dev, 0, 3)) < 0) {
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index 8dc7290089bb..0d29b5a6356d 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -601,14 +601,14 @@ static const struct proto_ops data_sock_ops = {
};
static int
-data_sock_create(struct net *net, struct socket *sock, int protocol)
+data_sock_create(struct net *net, struct socket *sock, int protocol, int kern)
{
struct sock *sk;
if (sock->type != SOCK_DGRAM)
return -ESOCKTNOSUPPORT;
- sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto);
+ sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern);
if (!sk)
return -ENOMEM;
@@ -756,14 +756,14 @@ static const struct proto_ops base_sock_ops = {
static int
-base_sock_create(struct net *net, struct socket *sock, int protocol)
+base_sock_create(struct net *net, struct socket *sock, int protocol, int kern)
{
struct sock *sk;
if (sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
- sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto);
+ sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern);
if (!sk)
return -ENOMEM;
@@ -785,7 +785,7 @@ mISDN_sock_create(struct net *net, struct socket *sock, int proto, int kern)
switch (proto) {
case ISDN_P_BASE:
- err = base_sock_create(net, sock, proto);
+ err = base_sock_create(net, sock, proto, kern);
break;
case ISDN_P_TE_S0:
case ISDN_P_NT_S0:
@@ -799,7 +799,7 @@ mISDN_sock_create(struct net *net, struct socket *sock, int proto, int kern)
case ISDN_P_B_L2DTMF:
case ISDN_P_B_L2DSP:
case ISDN_P_B_L2DSPHDLC:
- err = data_sock_create(net, sock, proto);
+ err = data_sock_create(net, sock, proto, kern);
break;
default:
return err;
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 966b9605f5f0..4191614c4651 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -11,9 +11,6 @@ menuconfig NEW_LEDS
Say Y to enable Linux LED support. This allows control of supported
LEDs from both userspace and optionally, by kernel events (triggers).
- This is not related to standard keyboard LEDs which are controlled
- via the input system.
-
if NEW_LEDS
config LEDS_CLASS
diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c
index 433f823037dd..ec1f46a6be3a 100644
--- a/drivers/mfd/janz-cmodio.c
+++ b/drivers/mfd/janz-cmodio.c
@@ -267,6 +267,10 @@ static void cmodio_pci_remove(struct pci_dev *dev)
static const struct pci_device_id cmodio_pci_ids[] = {
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0101 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0100 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0201 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0202 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0201 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0202 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, cmodio_pci_ids);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index df51d6025a90..019fceffc9e5 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -179,6 +179,20 @@ config VXLAN
To compile this driver as a module, choose M here: the module
will be called vxlan.
+config GENEVE
+ tristate "Generic Network Virtualization Encapsulation netdev"
+ depends on INET && GENEVE_CORE
+ select NET_IP_TUNNEL
+ ---help---
+ This allows one to create geneve virtual interfaces that provide
+ Layer 2 Networks over Layer 3 Networks. GENEVE is often used
+ to tunnel virtual network infrastructure in virtualized environments.
+ For more information see:
+ http://tools.ietf.org/html/draft-gross-geneve-02
+
+ To compile this driver as a module, choose M here: the module
+ will be called geneve.
+
config NETCONSOLE
tristate "Network console logging support"
---help---
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e25fdd7d905e..c12cb22478a7 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_TUN) += tun.o
obj-$(CONFIG_VETH) += veth.o
obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
obj-$(CONFIG_VXLAN) += vxlan.o
+obj-$(CONFIG_GENEVE) += geneve.o
obj-$(CONFIG_NLMON) += nlmon.o
#
diff --git a/drivers/net/arcnet/Kconfig b/drivers/net/arcnet/Kconfig
index 84fb6349a59a..2a9c3c3abe9b 100644
--- a/drivers/net/arcnet/Kconfig
+++ b/drivers/net/arcnet/Kconfig
@@ -15,10 +15,6 @@ menuconfig ARCNET
COM90xx type card, so say Y (or M) to "ARCnet COM90xx chipset
support" below.
- You might also want to have a look at the Ethernet-HOWTO, available
- from <http://www.tldp.org/docs.html#howto>(even though ARCnet
- is not really Ethernet).
-
To compile this driver as a module, choose M here. The module will
be called arcnet.
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index fbd54f0e32e8..7fde4d5c2b28 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -75,10 +75,10 @@
/* Port Key definitions
* key is determined according to the link speed, duplex and
* user key (which is yet not supported)
- * --------------------------------------------------------------
- * Port key : | User key | Speed | Duplex |
- * --------------------------------------------------------------
- * 16 6 1 0
+ * --------------------------------------------------------------
+ * Port key | User key (10 bits) | Speed (5 bits) | Duplex|
+ * --------------------------------------------------------------
+ * |15 6|5 1|0
*/
#define AD_DUPLEX_KEY_MASKS 0x1
#define AD_SPEED_KEY_MASKS 0x3E
@@ -1908,8 +1908,14 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution)
BOND_AD_INFO(bond).aggregator_identifier = 0;
- BOND_AD_INFO(bond).system.sys_priority = 0xFFFF;
- BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr);
+ BOND_AD_INFO(bond).system.sys_priority =
+ bond->params.ad_actor_sys_prio;
+ if (is_zero_ether_addr(bond->params.ad_actor_system))
+ BOND_AD_INFO(bond).system.sys_mac_addr =
+ *((struct mac_addr *)bond->dev->dev_addr);
+ else
+ BOND_AD_INFO(bond).system.sys_mac_addr =
+ *((struct mac_addr *)bond->params.ad_actor_system);
/* initialize how many times this module is called in one
* second (should be about every 100ms)
@@ -1945,10 +1951,10 @@ void bond_3ad_bind_slave(struct slave *slave)
port->slave = slave;
port->actor_port_number = SLAVE_AD_INFO(slave)->id;
- /* key is determined according to the link speed, duplex and user key(which
- * is yet not supported)
+ /* key is determined according to the link speed, duplex and
+ * user key
*/
- port->actor_admin_port_key = 0;
+ port->actor_admin_port_key = bond->params.ad_user_port_key << 6;
port->actor_admin_port_key |= __get_duplex(port);
port->actor_admin_port_key |= (__get_link_speed(port) << 1);
port->actor_oper_port_key = port->actor_admin_port_key;
@@ -1959,6 +1965,8 @@ void bond_3ad_bind_slave(struct slave *slave)
port->sm_vars &= ~AD_PORT_LACP_ENABLED;
/* actor system is the bond's system */
port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr;
+ port->actor_system_priority =
+ BOND_AD_INFO(bond).system.sys_priority;
/* tx timer(to verify that no more than MAX_TX_IN_SECOND
* lacpdu's are sent in one second)
*/
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index d5fe5d5f490f..19eb990d398c 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -76,7 +76,7 @@
#include <net/netns/generic.h>
#include <net/pkt_sched.h>
#include <linux/rculist.h>
-#include <net/flow_keys.h>
+#include <net/flow_dissector.h>
#include <net/switchdev.h>
#include <net/bonding.h>
#include <net/bond_3ad.h>
@@ -1015,10 +1015,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
netdev_features_t mask;
struct slave *slave;
- /* If any slave has the offload feature flag set,
- * set the offload flag on the bond.
- */
- mask = features | NETIF_F_HW_SWITCH_OFFLOAD;
+ mask = features;
features &= ~NETIF_F_ONE_FOR_ALL;
features |= NETIF_F_ALL_FOR_ALL;
@@ -3054,16 +3051,15 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb,
int noff, proto = -1;
if (bond->params.xmit_policy > BOND_XMIT_POLICY_LAYER23)
- return skb_flow_dissect(skb, fk);
+ return skb_flow_dissect_flow_keys(skb, fk);
- fk->ports = 0;
+ fk->ports.ports = 0;
noff = skb_network_offset(skb);
if (skb->protocol == htons(ETH_P_IP)) {
if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph))))
return false;
iph = ip_hdr(skb);
- fk->src = iph->saddr;
- fk->dst = iph->daddr;
+ iph_to_flow_copy_v4addrs(fk, iph);
noff += iph->ihl << 2;
if (!ip_is_fragment(iph))
proto = iph->protocol;
@@ -3071,15 +3067,14 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph6))))
return false;
iph6 = ipv6_hdr(skb);
- fk->src = (__force __be32)ipv6_addr_hash(&iph6->saddr);
- fk->dst = (__force __be32)ipv6_addr_hash(&iph6->daddr);
+ iph_to_flow_copy_v6addrs(fk, iph6);
noff += sizeof(*iph6);
proto = iph6->nexthdr;
} else {
return false;
}
if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34 && proto >= 0)
- fk->ports = skb_flow_get_ports(skb, noff, proto);
+ fk->ports.ports = skb_flow_get_ports(skb, noff, proto);
return true;
}
@@ -3105,8 +3100,9 @@ u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb)
bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP23)
hash = bond_eth_hash(skb);
else
- hash = (__force u32)flow.ports;
- hash ^= (__force u32)flow.dst ^ (__force u32)flow.src;
+ hash = (__force u32)flow.ports.ports;
+ hash ^= (__force u32)flow_get_u32_dst(&flow) ^
+ (__force u32)flow_get_u32_src(&flow);
hash ^= (hash >> 16);
hash ^= (hash >> 8);
@@ -4039,8 +4035,12 @@ static const struct net_device_ops bond_netdev_ops = {
.ndo_add_slave = bond_enslave,
.ndo_del_slave = bond_release,
.ndo_fix_features = bond_fix_features,
- .ndo_bridge_setlink = ndo_dflt_netdev_switch_port_bridge_setlink,
- .ndo_bridge_dellink = ndo_dflt_netdev_switch_port_bridge_dellink,
+ .ndo_bridge_setlink = switchdev_port_bridge_setlink,
+ .ndo_bridge_getlink = switchdev_port_bridge_getlink,
+ .ndo_bridge_dellink = switchdev_port_bridge_dellink,
+ .ndo_fdb_add = switchdev_port_fdb_add,
+ .ndo_fdb_del = switchdev_port_fdb_del,
+ .ndo_fdb_dump = switchdev_port_fdb_dump,
.ndo_features_check = passthru_features_check,
};
@@ -4140,6 +4140,8 @@ static int bond_check_params(struct bond_params *params)
struct bond_opt_value newval;
const struct bond_opt_value *valptr;
int arp_all_targets_value;
+ u16 ad_actor_sys_prio = 0;
+ u16 ad_user_port_key = 0;
/* Convert string parameters. */
if (mode) {
@@ -4434,6 +4436,24 @@ static int bond_check_params(struct bond_params *params)
fail_over_mac_value = BOND_FOM_NONE;
}
+ bond_opt_initstr(&newval, "default");
+ valptr = bond_opt_parse(
+ bond_opt_get(BOND_OPT_AD_ACTOR_SYS_PRIO),
+ &newval);
+ if (!valptr) {
+ pr_err("Error: No ad_actor_sys_prio default value");
+ return -EINVAL;
+ }
+ ad_actor_sys_prio = valptr->value;
+
+ valptr = bond_opt_parse(bond_opt_get(BOND_OPT_AD_USER_PORT_KEY),
+ &newval);
+ if (!valptr) {
+ pr_err("Error: No ad_user_port_key default value");
+ return -EINVAL;
+ }
+ ad_user_port_key = valptr->value;
+
if (lp_interval == 0) {
pr_warn("Warning: ip_interval must be between 1 and %d, so it was reset to %d\n",
INT_MAX, BOND_ALB_DEFAULT_LP_INTERVAL);
@@ -4462,6 +4482,9 @@ static int bond_check_params(struct bond_params *params)
params->lp_interval = lp_interval;
params->packets_per_slave = packets_per_slave;
params->tlb_dynamic_lb = 1; /* Default value */
+ params->ad_actor_sys_prio = ad_actor_sys_prio;
+ eth_zero_addr(params->ad_actor_system);
+ params->ad_user_port_key = ad_user_port_key;
if (packets_per_slave > 0) {
params->reciprocal_packets_per_slave =
reciprocal_value(packets_per_slave);
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index 7b1124366011..1bda29249d12 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -28,6 +28,8 @@ static size_t bond_get_slave_size(const struct net_device *bond_dev,
nla_total_size(MAX_ADDR_LEN) + /* IFLA_BOND_SLAVE_PERM_HWADDR */
nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_QUEUE_ID */
nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_AGGREGATOR_ID */
+ nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE */
+ nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */
0;
}
@@ -56,12 +58,23 @@ static int bond_fill_slave_info(struct sk_buff *skb,
if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
const struct aggregator *agg;
+ const struct port *ad_port;
+ ad_port = &SLAVE_AD_INFO(slave)->port;
agg = SLAVE_AD_INFO(slave)->port.aggregator;
- if (agg)
+ if (agg) {
if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID,
agg->aggregator_identifier))
goto nla_put_failure;
+ if (nla_put_u8(skb,
+ IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE,
+ ad_port->actor_oper_port_state))
+ goto nla_put_failure;
+ if (nla_put_u16(skb,
+ IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE,
+ ad_port->partner_oper.port_state))
+ goto nla_put_failure;
+ }
}
return 0;
@@ -94,6 +107,10 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
[IFLA_BOND_AD_LACP_RATE] = { .type = NLA_U8 },
[IFLA_BOND_AD_SELECT] = { .type = NLA_U8 },
[IFLA_BOND_AD_INFO] = { .type = NLA_NESTED },
+ [IFLA_BOND_AD_ACTOR_SYS_PRIO] = { .type = NLA_U16 },
+ [IFLA_BOND_AD_USER_PORT_KEY] = { .type = NLA_U16 },
+ [IFLA_BOND_AD_ACTOR_SYSTEM] = { .type = NLA_BINARY,
+ .len = ETH_ALEN },
};
static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = {
@@ -379,6 +396,36 @@ static int bond_changelink(struct net_device *bond_dev,
if (err)
return err;
}
+ if (data[IFLA_BOND_AD_ACTOR_SYS_PRIO]) {
+ int actor_sys_prio =
+ nla_get_u16(data[IFLA_BOND_AD_ACTOR_SYS_PRIO]);
+
+ bond_opt_initval(&newval, actor_sys_prio);
+ err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYS_PRIO, &newval);
+ if (err)
+ return err;
+ }
+
+ if (data[IFLA_BOND_AD_USER_PORT_KEY]) {
+ int port_key =
+ nla_get_u16(data[IFLA_BOND_AD_USER_PORT_KEY]);
+
+ bond_opt_initval(&newval, port_key);
+ err = __bond_opt_set(bond, BOND_OPT_AD_USER_PORT_KEY, &newval);
+ if (err)
+ return err;
+ }
+
+ if (data[IFLA_BOND_AD_ACTOR_SYSTEM]) {
+ if (nla_len(data[IFLA_BOND_AD_ACTOR_SYSTEM]) != ETH_ALEN)
+ return -EINVAL;
+
+ bond_opt_initval(&newval,
+ nla_get_be64(data[IFLA_BOND_AD_ACTOR_SYSTEM]));
+ err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYSTEM, &newval);
+ if (err)
+ return err;
+ }
return 0;
}
@@ -426,6 +473,9 @@ static size_t bond_get_size(const struct net_device *bond_dev)
nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_ACTOR_KEY */
nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_PARTNER_KEY*/
nla_total_size(ETH_ALEN) + /* IFLA_BOND_AD_INFO_PARTNER_MAC*/
+ nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_ACTOR_SYS_PRIO */
+ nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_USER_PORT_KEY */
+ nla_total_size(ETH_ALEN) + /* IFLA_BOND_AD_ACTOR_SYSTEM */
0;
}
@@ -551,6 +601,20 @@ static int bond_fill_info(struct sk_buff *skb,
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
struct ad_info info;
+ if (capable(CAP_NET_ADMIN)) {
+ if (nla_put_u16(skb, IFLA_BOND_AD_ACTOR_SYS_PRIO,
+ bond->params.ad_actor_sys_prio))
+ goto nla_put_failure;
+
+ if (nla_put_u16(skb, IFLA_BOND_AD_USER_PORT_KEY,
+ bond->params.ad_user_port_key))
+ goto nla_put_failure;
+
+ if (nla_put(skb, IFLA_BOND_AD_ACTOR_SYSTEM,
+ sizeof(bond->params.ad_actor_system),
+ &bond->params.ad_actor_system))
+ goto nla_put_failure;
+ }
if (!bond_3ad_get_active_agg_info(bond, &info)) {
struct nlattr *nest;
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index e8d3c1d35453..e9c624d54dd4 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -70,6 +70,12 @@ static int bond_option_slaves_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
const struct bond_opt_value *newval);
+static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_ad_actor_system_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
+static int bond_option_ad_user_port_key_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
static const struct bond_opt_value bond_mode_tbl[] = {
@@ -186,6 +192,18 @@ static const struct bond_opt_value bond_tlb_dynamic_lb_tbl[] = {
{ NULL, -1, 0}
};
+static const struct bond_opt_value bond_ad_actor_sys_prio_tbl[] = {
+ { "minval", 1, BOND_VALFLAG_MIN},
+ { "maxval", 65535, BOND_VALFLAG_MAX | BOND_VALFLAG_DEFAULT},
+ { NULL, -1, 0},
+};
+
+static const struct bond_opt_value bond_ad_user_port_key_tbl[] = {
+ { "minval", 0, BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT},
+ { "maxval", 1023, BOND_VALFLAG_MAX},
+ { NULL, -1, 0},
+};
+
static const struct bond_option bond_opts[BOND_OPT_LAST] = {
[BOND_OPT_MODE] = {
.id = BOND_OPT_MODE,
@@ -379,6 +397,29 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = {
.values = bond_tlb_dynamic_lb_tbl,
.flags = BOND_OPTFLAG_IFDOWN,
.set = bond_option_tlb_dynamic_lb_set,
+ },
+ [BOND_OPT_AD_ACTOR_SYS_PRIO] = {
+ .id = BOND_OPT_AD_ACTOR_SYS_PRIO,
+ .name = "ad_actor_sys_prio",
+ .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
+ .flags = BOND_OPTFLAG_IFDOWN,
+ .values = bond_ad_actor_sys_prio_tbl,
+ .set = bond_option_ad_actor_sys_prio_set,
+ },
+ [BOND_OPT_AD_ACTOR_SYSTEM] = {
+ .id = BOND_OPT_AD_ACTOR_SYSTEM,
+ .name = "ad_actor_system",
+ .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
+ .flags = BOND_OPTFLAG_RAWVAL | BOND_OPTFLAG_IFDOWN,
+ .set = bond_option_ad_actor_system_set,
+ },
+ [BOND_OPT_AD_USER_PORT_KEY] = {
+ .id = BOND_OPT_AD_USER_PORT_KEY,
+ .name = "ad_user_port_key",
+ .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
+ .flags = BOND_OPTFLAG_IFDOWN,
+ .values = bond_ad_user_port_key_tbl,
+ .set = bond_option_ad_user_port_key_set,
}
};
@@ -1349,3 +1390,53 @@ static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
return 0;
}
+
+static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
+{
+ netdev_info(bond->dev, "Setting ad_actor_sys_prio to %llu\n",
+ newval->value);
+
+ bond->params.ad_actor_sys_prio = newval->value;
+ return 0;
+}
+
+static int bond_option_ad_actor_system_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
+{
+ u8 macaddr[ETH_ALEN];
+ u8 *mac;
+ int i;
+
+ if (newval->string) {
+ i = sscanf(newval->string, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+ &macaddr[0], &macaddr[1], &macaddr[2],
+ &macaddr[3], &macaddr[4], &macaddr[5]);
+ if (i != ETH_ALEN)
+ goto err;
+ mac = macaddr;
+ } else {
+ mac = (u8 *)&newval->value;
+ }
+
+ if (!is_valid_ether_addr(mac))
+ goto err;
+
+ netdev_info(bond->dev, "Setting ad_actor_system to %pM\n", mac);
+ ether_addr_copy(bond->params.ad_actor_system, mac);
+ return 0;
+
+err:
+ netdev_err(bond->dev, "Invalid MAC address.\n");
+ return -EINVAL;
+}
+
+static int bond_option_ad_user_port_key_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
+{
+ netdev_info(bond->dev, "Setting ad_user_port_key to %llu\n",
+ newval->value);
+
+ bond->params.ad_user_port_key = newval->value;
+ return 0;
+}
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index b20b35acb47d..f514fe5e80a5 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -135,23 +135,30 @@ static void bond_info_show_master(struct seq_file *seq)
bond->params.ad_select);
seq_printf(seq, "Aggregator selection policy (ad_select): %s\n",
optval->string);
-
- if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
- seq_printf(seq, "bond %s has no active aggregator\n",
- bond->dev->name);
- } else {
- seq_printf(seq, "Active Aggregator Info:\n");
-
- seq_printf(seq, "\tAggregator ID: %d\n",
- ad_info.aggregator_id);
- seq_printf(seq, "\tNumber of ports: %d\n",
- ad_info.ports);
- seq_printf(seq, "\tActor Key: %d\n",
- ad_info.actor_key);
- seq_printf(seq, "\tPartner Key: %d\n",
- ad_info.partner_key);
- seq_printf(seq, "\tPartner Mac Address: %pM\n",
- ad_info.partner_system);
+ if (capable(CAP_NET_ADMIN)) {
+ seq_printf(seq, "System priority: %d\n",
+ BOND_AD_INFO(bond).system.sys_priority);
+ seq_printf(seq, "System MAC address: %pM\n",
+ &BOND_AD_INFO(bond).system.sys_mac_addr);
+
+ if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
+ seq_printf(seq,
+ "bond %s has no active aggregator\n",
+ bond->dev->name);
+ } else {
+ seq_printf(seq, "Active Aggregator Info:\n");
+
+ seq_printf(seq, "\tAggregator ID: %d\n",
+ ad_info.aggregator_id);
+ seq_printf(seq, "\tNumber of ports: %d\n",
+ ad_info.ports);
+ seq_printf(seq, "\tActor Key: %d\n",
+ ad_info.actor_key);
+ seq_printf(seq, "\tPartner Key: %d\n",
+ ad_info.partner_key);
+ seq_printf(seq, "\tPartner Mac Address: %pM\n",
+ ad_info.partner_system);
+ }
}
}
}
@@ -195,29 +202,35 @@ static void bond_info_show_slave(struct seq_file *seq,
seq_printf(seq, "Partner Churned Count: %d\n",
port->churn_partner_count);
- seq_puts(seq, "details actor lacp pdu:\n");
- seq_printf(seq, " system priority: %d\n",
- port->actor_system_priority);
- seq_printf(seq, " port key: %d\n",
- port->actor_oper_port_key);
- seq_printf(seq, " port priority: %d\n",
- port->actor_port_priority);
- seq_printf(seq, " port number: %d\n",
- port->actor_port_number);
- seq_printf(seq, " port state: %d\n",
- port->actor_oper_port_state);
-
- seq_puts(seq, "details partner lacp pdu:\n");
- seq_printf(seq, " system priority: %d\n",
- port->partner_oper.system_priority);
- seq_printf(seq, " oper key: %d\n",
- port->partner_oper.key);
- seq_printf(seq, " port priority: %d\n",
- port->partner_oper.port_priority);
- seq_printf(seq, " port number: %d\n",
- port->partner_oper.port_number);
- seq_printf(seq, " port state: %d\n",
- port->partner_oper.port_state);
+ if (capable(CAP_NET_ADMIN)) {
+ seq_puts(seq, "details actor lacp pdu:\n");
+ seq_printf(seq, " system priority: %d\n",
+ port->actor_system_priority);
+ seq_printf(seq, " system mac address: %pM\n",
+ &port->actor_system);
+ seq_printf(seq, " port key: %d\n",
+ port->actor_oper_port_key);
+ seq_printf(seq, " port priority: %d\n",
+ port->actor_port_priority);
+ seq_printf(seq, " port number: %d\n",
+ port->actor_port_number);
+ seq_printf(seq, " port state: %d\n",
+ port->actor_oper_port_state);
+
+ seq_puts(seq, "details partner lacp pdu:\n");
+ seq_printf(seq, " system priority: %d\n",
+ port->partner_oper.system_priority);
+ seq_printf(seq, " system mac address: %pM\n",
+ &port->partner_oper.system);
+ seq_printf(seq, " oper key: %d\n",
+ port->partner_oper.key);
+ seq_printf(seq, " port priority: %d\n",
+ port->partner_oper.port_priority);
+ seq_printf(seq, " port number: %d\n",
+ port->partner_oper.port_number);
+ seq_printf(seq, " port state: %d\n",
+ port->partner_oper.port_state);
+ }
} else {
seq_puts(seq, "Aggregator ID: N/A\n");
}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 7e9e151d4d61..31835a4dab57 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -549,7 +549,7 @@ static ssize_t bonding_show_ad_actor_key(struct device *d,
int count = 0;
struct bonding *bond = to_bond(d);
- if (BOND_MODE(bond) == BOND_MODE_8023AD) {
+ if (BOND_MODE(bond) == BOND_MODE_8023AD && capable(CAP_NET_ADMIN)) {
struct ad_info ad_info;
count = sprintf(buf, "%d\n",
bond_3ad_get_active_agg_info(bond, &ad_info)
@@ -569,7 +569,7 @@ static ssize_t bonding_show_ad_partner_key(struct device *d,
int count = 0;
struct bonding *bond = to_bond(d);
- if (BOND_MODE(bond) == BOND_MODE_8023AD) {
+ if (BOND_MODE(bond) == BOND_MODE_8023AD && capable(CAP_NET_ADMIN)) {
struct ad_info ad_info;
count = sprintf(buf, "%d\n",
bond_3ad_get_active_agg_info(bond, &ad_info)
@@ -589,7 +589,7 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d,
int count = 0;
struct bonding *bond = to_bond(d);
- if (BOND_MODE(bond) == BOND_MODE_8023AD) {
+ if (BOND_MODE(bond) == BOND_MODE_8023AD && capable(CAP_NET_ADMIN)) {
struct ad_info ad_info;
if (!bond_3ad_get_active_agg_info(bond, &ad_info))
count = sprintf(buf, "%pM\n", ad_info.partner_system);
@@ -692,6 +692,49 @@ static ssize_t bonding_show_packets_per_slave(struct device *d,
static DEVICE_ATTR(packets_per_slave, S_IRUGO | S_IWUSR,
bonding_show_packets_per_slave, bonding_sysfs_store_option);
+static ssize_t bonding_show_ad_actor_sys_prio(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bonding *bond = to_bond(d);
+
+ if (BOND_MODE(bond) == BOND_MODE_8023AD && capable(CAP_NET_ADMIN))
+ return sprintf(buf, "%hu\n", bond->params.ad_actor_sys_prio);
+
+ return 0;
+}
+static DEVICE_ATTR(ad_actor_sys_prio, S_IRUGO | S_IWUSR,
+ bonding_show_ad_actor_sys_prio, bonding_sysfs_store_option);
+
+static ssize_t bonding_show_ad_actor_system(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bonding *bond = to_bond(d);
+
+ if (BOND_MODE(bond) == BOND_MODE_8023AD && capable(CAP_NET_ADMIN))
+ return sprintf(buf, "%pM\n", bond->params.ad_actor_system);
+
+ return 0;
+}
+
+static DEVICE_ATTR(ad_actor_system, S_IRUGO | S_IWUSR,
+ bonding_show_ad_actor_system, bonding_sysfs_store_option);
+
+static ssize_t bonding_show_ad_user_port_key(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bonding *bond = to_bond(d);
+
+ if (BOND_MODE(bond) == BOND_MODE_8023AD && capable(CAP_NET_ADMIN))
+ return sprintf(buf, "%hu\n", bond->params.ad_user_port_key);
+
+ return 0;
+}
+static DEVICE_ATTR(ad_user_port_key, S_IRUGO | S_IWUSR,
+ bonding_show_ad_user_port_key, bonding_sysfs_store_option);
+
static struct attribute *per_bond_attrs[] = {
&dev_attr_slaves.attr,
&dev_attr_mode.attr,
@@ -725,6 +768,9 @@ static struct attribute *per_bond_attrs[] = {
&dev_attr_lp_interval.attr,
&dev_attr_packets_per_slave.attr,
&dev_attr_tlb_dynamic_lb.attr,
+ &dev_attr_ad_actor_sys_prio.attr,
+ &dev_attr_ad_actor_system.attr,
+ &dev_attr_ad_user_port_key.attr,
NULL,
};
diff --git a/drivers/net/bonding/bond_sysfs_slave.c b/drivers/net/bonding/bond_sysfs_slave.c
index 23618a831612..7d16c51e6913 100644
--- a/drivers/net/bonding/bond_sysfs_slave.c
+++ b/drivers/net/bonding/bond_sysfs_slave.c
@@ -80,6 +80,36 @@ static ssize_t ad_aggregator_id_show(struct slave *slave, char *buf)
}
static SLAVE_ATTR_RO(ad_aggregator_id);
+static ssize_t ad_actor_oper_port_state_show(struct slave *slave, char *buf)
+{
+ const struct port *ad_port;
+
+ if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
+ ad_port = &SLAVE_AD_INFO(slave)->port;
+ if (ad_port->aggregator)
+ return sprintf(buf, "%u\n",
+ ad_port->actor_oper_port_state);
+ }
+
+ return sprintf(buf, "N/A\n");
+}
+static SLAVE_ATTR_RO(ad_actor_oper_port_state);
+
+static ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf)
+{
+ const struct port *ad_port;
+
+ if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
+ ad_port = &SLAVE_AD_INFO(slave)->port;
+ if (ad_port->aggregator)
+ return sprintf(buf, "%u\n",
+ ad_port->partner_oper.port_state);
+ }
+
+ return sprintf(buf, "N/A\n");
+}
+static SLAVE_ATTR_RO(ad_partner_oper_port_state);
+
static const struct slave_attribute *slave_attrs[] = {
&slave_attr_state,
&slave_attr_mii_status,
@@ -87,6 +117,8 @@ static const struct slave_attribute *slave_attrs[] = {
&slave_attr_perm_hwaddr,
&slave_attr_queue_id,
&slave_attr_ad_aggregator_id,
+ &slave_attr_ad_actor_oper_port_state,
+ &slave_attr_ad_partner_oper_port_state,
NULL
};
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index b0f69248cb71..e9b1810d319f 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -440,6 +440,9 @@ unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx)
struct can_frame *cf = (struct can_frame *)skb->data;
u8 dlc = cf->can_dlc;
+ if (!(skb->tstamp.tv64))
+ __net_timestamp(skb);
+
netif_rx(priv->echo_skb[idx]);
priv->echo_skb[idx] = NULL;
@@ -575,6 +578,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
if (unlikely(!skb))
return NULL;
+ __net_timestamp(skb);
skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -603,6 +607,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
if (unlikely(!skb))
return NULL;
+ __net_timestamp(skb);
skb->protocol = htons(ETH_P_CANFD);
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index ad0a7e8c2c2b..6201c5a1a884 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -93,13 +93,13 @@
(FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE)
/* FLEXCAN control register 2 (CTRL2) bits */
-#define FLEXCAN_CRL2_ECRWRE BIT(29)
-#define FLEXCAN_CRL2_WRMFRZ BIT(28)
-#define FLEXCAN_CRL2_RFFN(x) (((x) & 0x0f) << 24)
-#define FLEXCAN_CRL2_TASD(x) (((x) & 0x1f) << 19)
-#define FLEXCAN_CRL2_MRP BIT(18)
-#define FLEXCAN_CRL2_RRS BIT(17)
-#define FLEXCAN_CRL2_EACEN BIT(16)
+#define FLEXCAN_CTRL2_ECRWRE BIT(29)
+#define FLEXCAN_CTRL2_WRMFRZ BIT(28)
+#define FLEXCAN_CTRL2_RFFN(x) (((x) & 0x0f) << 24)
+#define FLEXCAN_CTRL2_TASD(x) (((x) & 0x1f) << 19)
+#define FLEXCAN_CTRL2_MRP BIT(18)
+#define FLEXCAN_CTRL2_RRS BIT(17)
+#define FLEXCAN_CTRL2_EACEN BIT(16)
/* FLEXCAN memory error control register (MECR) bits */
#define FLEXCAN_MECR_ECRWRDIS BIT(31)
@@ -158,7 +158,6 @@
FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID))
/* FLEXCAN message buffers */
-#define FLEXCAN_MB_CNT_CODE(x) (((x) & 0xf) << 24)
#define FLEXCAN_MB_CODE_RX_INACTIVE (0x0 << 24)
#define FLEXCAN_MB_CODE_RX_EMPTY (0x4 << 24)
#define FLEXCAN_MB_CODE_RX_FULL (0x2 << 24)
@@ -184,14 +183,14 @@
* FLEXCAN hardware feature flags
*
* Below is some version info we got:
- * SOC Version IP-Version Glitch- [TR]WRN_INT Memory err
- * Filter? connected? detection
- * MX25 FlexCAN2 03.00.00.00 no no no
- * MX28 FlexCAN2 03.00.04.00 yes yes no
- * MX35 FlexCAN2 03.00.00.00 no no no
- * MX53 FlexCAN2 03.00.00.00 yes no no
- * MX6s FlexCAN3 10.00.12.00 yes yes no
- * VF610 FlexCAN3 ? no yes yes
+ * SOC Version IP-Version Glitch- [TR]WRN_INT Memory err RTR re-
+ * Filter? connected? detection ception in MB
+ * MX25 FlexCAN2 03.00.00.00 no no no no
+ * MX28 FlexCAN2 03.00.04.00 yes yes no no
+ * MX35 FlexCAN2 03.00.00.00 no no no no
+ * MX53 FlexCAN2 03.00.00.00 yes no no no
+ * MX6s FlexCAN3 10.00.12.00 yes yes no yes
+ * VF610 FlexCAN3 ? no yes yes yes?
*
* Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected.
*/
@@ -221,7 +220,7 @@ struct flexcan_regs {
u32 imask1; /* 0x28 */
u32 iflag2; /* 0x2c */
u32 iflag1; /* 0x30 */
- u32 crl2; /* 0x34 */
+ u32 ctrl2; /* 0x34 */
u32 esr2; /* 0x38 */
u32 imeur; /* 0x3c */
u32 lrfr; /* 0x40 */
@@ -230,6 +229,16 @@ struct flexcan_regs {
u32 rxfir; /* 0x4c */
u32 _reserved3[12]; /* 0x50 */
struct flexcan_mb cantxfg[64]; /* 0x80 */
+ /* FIFO-mode:
+ * MB
+ * 0x080...0x08f 0 RX message buffer
+ * 0x090...0x0df 1-5 reserverd
+ * 0x0e0...0x0ff 6-7 8 entry ID table
+ * (mx25, mx28, mx35, mx53)
+ * 0x0e0...0x2df 6-7..37 8..128 entry ID table
+ * size conf'ed via ctrl2::RFFN
+ * (mx6, vf610)
+ */
u32 _reserved4[408];
u32 mecr; /* 0xae0 */
u32 erriar; /* 0xae4 */
@@ -468,7 +477,7 @@ static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct flexcan_regs __iomem *regs = priv->base;
struct can_frame *cf = (struct can_frame *)skb->data;
u32 can_id;
- u32 ctrl = FLEXCAN_MB_CNT_CODE(0xc) | (cf->can_dlc << 16);
+ u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16);
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
@@ -815,7 +824,7 @@ static int flexcan_chip_start(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
- u32 reg_mcr, reg_ctrl, reg_crl2, reg_mecr;
+ u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr;
int err, i;
/* enable module */
@@ -918,9 +927,9 @@ static int flexcan_chip_start(struct net_device *dev)
* and Correction of Memory Errors" to write to
* MECR register
*/
- reg_crl2 = flexcan_read(&regs->crl2);
- reg_crl2 |= FLEXCAN_CRL2_ECRWRE;
- flexcan_write(reg_crl2, &regs->crl2);
+ reg_ctrl2 = flexcan_read(&regs->ctrl2);
+ reg_ctrl2 |= FLEXCAN_CTRL2_ECRWRE;
+ flexcan_write(reg_ctrl2, &regs->ctrl2);
reg_mecr = flexcan_read(&regs->mecr);
reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS;
diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c
index 4dd183a3643a..c1e85368a198 100644
--- a/drivers/net/can/janz-ican3.c
+++ b/drivers/net/can/janz-ican3.c
@@ -40,6 +40,7 @@
#define MSYNC_PEER 0x00 /* ICAN only */
#define MSYNC_LOCL 0x01 /* host only */
#define TARGET_RUNNING 0x02
+#define FIRMWARE_STAMP 0x60 /* big endian firmware stamp */
#define MSYNC_RB0 0x01
#define MSYNC_RB1 0x02
@@ -83,6 +84,7 @@
#define MSG_COFFREQ 0x42
#define MSG_CONREQ 0x43
#define MSG_CCONFREQ 0x47
+#define MSG_LMTS 0xb4
/*
* Janz ICAN3 CAN Inquiry Message Types
@@ -165,6 +167,12 @@
/* SJA1000 Clock Input */
#define ICAN3_CAN_CLOCK 8000000
+/* Janz ICAN3 firmware types */
+enum ican3_fwtype {
+ ICAN3_FWTYPE_ICANOS,
+ ICAN3_FWTYPE_CAL_CANOPEN,
+};
+
/* Driver Name */
#define DRV_NAME "janz-ican3"
@@ -215,6 +223,10 @@ struct ican3_dev {
struct completion buserror_comp;
struct can_berr_counter bec;
+ /* firmware type */
+ enum ican3_fwtype fwtype;
+ char fwinfo[32];
+
/* old and new style host interface */
unsigned int iftype;
@@ -750,13 +762,61 @@ static int ican3_set_id_filter(struct ican3_dev *mod, bool accept)
*/
static int ican3_set_bus_state(struct ican3_dev *mod, bool on)
{
+ struct can_bittiming *bt = &mod->can.bittiming;
struct ican3_msg msg;
+ u8 btr0, btr1;
+ int res;
- memset(&msg, 0, sizeof(msg));
- msg.spec = on ? MSG_CONREQ : MSG_COFFREQ;
- msg.len = cpu_to_le16(0);
+ /* This algorithm was stolen from drivers/net/can/sja1000/sja1000.c */
+ /* The bittiming register command for the ICAN3 just sets the bit timing */
+ /* registers on the SJA1000 chip directly */
+ btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
+ btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
+ (((bt->phase_seg2 - 1) & 0x7) << 4);
+ if (mod->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+ btr1 |= 0x80;
- return ican3_send_msg(mod, &msg);
+ if (mod->fwtype == ICAN3_FWTYPE_ICANOS) {
+ if (on) {
+ /* set bittiming */
+ memset(&msg, 0, sizeof(msg));
+ msg.spec = MSG_CBTRREQ;
+ msg.len = cpu_to_le16(4);
+ msg.data[0] = 0x00;
+ msg.data[1] = 0x00;
+ msg.data[2] = btr0;
+ msg.data[3] = btr1;
+
+ res = ican3_send_msg(mod, &msg);
+ if (res)
+ return res;
+ }
+
+ /* can-on/off request */
+ memset(&msg, 0, sizeof(msg));
+ msg.spec = on ? MSG_CONREQ : MSG_COFFREQ;
+ msg.len = cpu_to_le16(0);
+
+ return ican3_send_msg(mod, &msg);
+
+ } else if (mod->fwtype == ICAN3_FWTYPE_CAL_CANOPEN) {
+ memset(&msg, 0, sizeof(msg));
+ msg.spec = MSG_LMTS;
+ if (on) {
+ msg.len = cpu_to_le16(4);
+ msg.data[0] = 0;
+ msg.data[1] = 0;
+ msg.data[2] = btr0;
+ msg.data[3] = btr1;
+ } else {
+ msg.len = cpu_to_le16(2);
+ msg.data[0] = 1;
+ msg.data[1] = 0;
+ }
+
+ return ican3_send_msg(mod, &msg);
+ }
+ return -ENOTSUPP;
}
static int ican3_set_termination(struct ican3_dev *mod, bool on)
@@ -1402,7 +1462,7 @@ static int ican3_reset_module(struct ican3_dev *mod)
return 0;
msleep(10);
- } while (time_before(jiffies, start + HZ / 4));
+ } while (time_before(jiffies, start + HZ / 2));
netdev_err(mod->ndev, "failed to reset CAN module\n");
return -ETIMEDOUT;
@@ -1427,6 +1487,17 @@ static int ican3_startup_module(struct ican3_dev *mod)
return ret;
}
+ /* detect firmware */
+ memcpy_fromio(mod->fwinfo, mod->dpm + FIRMWARE_STAMP, sizeof(mod->fwinfo) - 1);
+ if (strncmp(mod->fwinfo, "JANZ-ICAN3", 10)) {
+ netdev_err(mod->ndev, "ICAN3 not detected (found %s)\n", mod->fwinfo);
+ return -ENODEV;
+ }
+ if (strstr(mod->fwinfo, "CAL/CANopen"))
+ mod->fwtype = ICAN3_FWTYPE_CAL_CANOPEN;
+ else
+ mod->fwtype = ICAN3_FWTYPE_ICANOS;
+
/* re-enable interrupts so we can send messages */
iowrite8(1 << mod->num, &mod->ctrl->int_enable);
@@ -1615,36 +1686,6 @@ static const struct can_bittiming_const ican3_bittiming_const = {
.brp_inc = 1,
};
-/*
- * This routine was stolen from drivers/net/can/sja1000/sja1000.c
- *
- * The bittiming register command for the ICAN3 just sets the bit timing
- * registers on the SJA1000 chip directly
- */
-static int ican3_set_bittiming(struct net_device *ndev)
-{
- struct ican3_dev *mod = netdev_priv(ndev);
- struct can_bittiming *bt = &mod->can.bittiming;
- struct ican3_msg msg;
- u8 btr0, btr1;
-
- btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
- btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
- (((bt->phase_seg2 - 1) & 0x7) << 4);
- if (mod->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
- btr1 |= 0x80;
-
- memset(&msg, 0, sizeof(msg));
- msg.spec = MSG_CBTRREQ;
- msg.len = cpu_to_le16(4);
- msg.data[0] = 0x00;
- msg.data[1] = 0x00;
- msg.data[2] = btr0;
- msg.data[3] = btr1;
-
- return ican3_send_msg(mod, &msg);
-}
-
static int ican3_set_mode(struct net_device *ndev, enum can_mode mode)
{
struct ican3_dev *mod = netdev_priv(ndev);
@@ -1730,11 +1771,22 @@ static ssize_t ican3_sysfs_set_term(struct device *dev,
return count;
}
+static ssize_t ican3_sysfs_show_fwinfo(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ican3_dev *mod = netdev_priv(to_net_dev(dev));
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n", mod->fwinfo);
+}
+
static DEVICE_ATTR(termination, S_IWUSR | S_IRUGO, ican3_sysfs_show_term,
ican3_sysfs_set_term);
+static DEVICE_ATTR(fwinfo, S_IRUSR | S_IRUGO, ican3_sysfs_show_fwinfo, NULL);
static struct attribute *ican3_sysfs_attrs[] = {
&dev_attr_termination.attr,
+ &dev_attr_fwinfo.attr,
NULL,
};
@@ -1794,7 +1846,6 @@ static int ican3_probe(struct platform_device *pdev)
mod->can.clock.freq = ICAN3_CAN_CLOCK;
mod->can.bittiming_const = &ican3_bittiming_const;
- mod->can.do_set_bittiming = ican3_set_bittiming;
mod->can.do_set_mode = ican3_set_mode;
mod->can.do_get_berr_counter = ican3_get_berr_counter;
mod->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES
@@ -1866,7 +1917,7 @@ static int ican3_probe(struct platform_device *pdev)
goto out_free_irq;
}
- dev_info(dev, "module %d: registered CAN device\n", pdata->modno);
+ netdev_info(mod->ndev, "module %d: registered CAN device\n", pdata->modno);
return 0;
out_free_irq:
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index c837eb91d43e..f64f5290d6f8 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -207,6 +207,7 @@ static void slc_bump(struct slcan *sl)
if (!skb)
return;
+ __net_timestamp(skb);
skb->dev = sl->dev;
skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index bf63fee4e743..c1a95a34d62e 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -190,10 +190,11 @@
#define RXBEID0_OFF 4
#define RXBDLC_OFF 5
#define RXBDAT_OFF 6
-#define RXFSIDH(n) ((n) * 4)
-#define RXFSIDL(n) ((n) * 4 + 1)
-#define RXFEID8(n) ((n) * 4 + 2)
-#define RXFEID0(n) ((n) * 4 + 3)
+#define RXFSID(n) ((n < 3) ? 0 : 4)
+#define RXFSIDH(n) ((n) * 4 + RXFSID(n))
+#define RXFSIDL(n) ((n) * 4 + 1 + RXFSID(n))
+#define RXFEID8(n) ((n) * 4 + 2 + RXFSID(n))
+#define RXFEID0(n) ((n) * 4 + 3 + RXFSID(n))
#define RXMSIDH(n) ((n) * 4 + 0x20)
#define RXMSIDL(n) ((n) * 4 + 0x21)
#define RXMEID8(n) ((n) * 4 + 0x22)
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
index 674f367087c5..0ce868de855d 100644
--- a/drivers/net/can/vcan.c
+++ b/drivers/net/can/vcan.c
@@ -78,6 +78,9 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
skb->dev = dev;
skb->ip_summed = CHECKSUM_UNNECESSARY;
+ if (!(skb->tstamp.tv64))
+ __net_timestamp(skb);
+
netif_rx_ni(skb);
}
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index 18550c7ebe6f..7ad0a4d8e475 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -37,22 +37,22 @@ config NET_DSA_MV88E6123_61_65
ethernet switch chips.
config NET_DSA_MV88E6171
- tristate "Marvell 88E6171/6172 ethernet switch chip support"
+ tristate "Marvell 88E6171/6175/6350/6351 ethernet switch chip support"
depends on NET_DSA
select NET_DSA_MV88E6XXX
select NET_DSA_TAG_EDSA
---help---
- This enables support for the Marvell 88E6171/6172 ethernet switch
- chips.
+ This enables support for the Marvell 88E6171/6175/6350/6351
+ ethernet switches chips.
config NET_DSA_MV88E6352
- tristate "Marvell 88E6176/88E6352 ethernet switch chip support"
+ tristate "Marvell 88E6172/88E6176/88E6352 ethernet switch chip support"
depends on NET_DSA
select NET_DSA_MV88E6XXX
select NET_DSA_TAG_EDSA
---help---
- This enables support for the Marvell 88E6176 and 88E6352 ethernet
- switch chips.
+ This enables support for the Marvell 88E6172, 88E6176 and 88E6352
+ ethernet switch chips.
config NET_DSA_BCM_SF2
tristate "Broadcom Starfighter 2 Ethernet switch support"
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index cedb572bf25a..972982f8bea7 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -24,6 +24,7 @@
#include <net/dsa.h>
#include <linux/ethtool.h>
#include <linux/if_bridge.h>
+#include <linux/brcmphy.h>
#include "bcm_sf2.h"
#include "bcm_sf2_regs.h"
@@ -697,7 +698,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
/* Include the pseudo-PHY address and the broadcast PHY address to
* divert reads towards our workaround
*/
- ds->phys_mii_mask |= ((1 << 30) | (1 << 0));
+ ds->phys_mii_mask |= ((1 << BRCM_PSEUDO_PHY_ADDR) | (1 << 0));
rev = reg_readl(priv, REG_SWITCH_REVISION);
priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) &
@@ -782,7 +783,7 @@ static int bcm_sf2_sw_phy_read(struct dsa_switch *ds, int addr, int regnum)
*/
switch (addr) {
case 0:
- case 30:
+ case BRCM_PSEUDO_PHY_ADDR:
return bcm_sf2_sw_indir_rw(ds, 1, addr, regnum, 0);
default:
return 0xffff;
@@ -797,7 +798,7 @@ static int bcm_sf2_sw_phy_write(struct dsa_switch *ds, int addr, int regnum,
*/
switch (addr) {
case 0:
- case 30:
+ case BRCM_PSEUDO_PHY_ADDR:
bcm_sf2_sw_indir_rw(ds, 0, addr, regnum, val);
break;
}
@@ -911,6 +912,13 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
*/
if (port == 7) {
status->link = priv->port_sts[port].link;
+ /* For MoCA interfaces, also force a link down notification
+ * since some version of the user-space daemon (mocad) use
+ * cmd->autoneg to force the link, which messes up the PHY
+ * state machine and make it go in PHY_FORCING state instead.
+ */
+ if (!status->link)
+ netif_carrier_off(ds->ports[port]);
status->duplex = 1;
} else {
status->link = 1;
diff --git a/drivers/net/dsa/mv88e6123_61_65.c b/drivers/net/dsa/mv88e6123_61_65.c
index b4af6d5aff7c..71a29a7ce538 100644
--- a/drivers/net/dsa/mv88e6123_61_65.c
+++ b/drivers/net/dsa/mv88e6123_61_65.c
@@ -54,192 +54,40 @@ static char *mv88e6123_61_65_probe(struct device *host_dev, int sw_addr)
static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
{
+ u32 upstream_port = dsa_upstream_port(ds);
int ret;
- int i;
+ u32 reg;
+
+ ret = mv88e6xxx_setup_global(ds);
+ if (ret)
+ return ret;
/* Disable the PHY polling unit (since there won't be any
* external PHYs to poll), don't discard packets with
* excessive collisions, and mask all interrupt sources.
*/
- REG_WRITE(REG_GLOBAL, 0x04, 0x0000);
-
- /* Set the default address aging time to 5 minutes, and
- * enable address learn messages to be sent to all message
- * ports.
- */
- REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
-
- /* Configure the priority mapping registers. */
- ret = mv88e6xxx_config_prio(ds);
- if (ret < 0)
- return ret;
+ REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, 0x0000);
/* Configure the upstream port, and configure the upstream
* port as the port to which ingress and egress monitor frames
* are to be sent.
*/
- REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110));
+ reg = upstream_port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
+ upstream_port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT |
+ upstream_port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT;
+ REG_WRITE(REG_GLOBAL, GLOBAL_MONITOR_CONTROL, reg);
/* Disable remote management for now, and set the switch's
* DSA device number.
*/
- REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
-
- /* Send all frames with destination addresses matching
- * 01:80:c2:00:00:2x to the CPU port.
- */
- REG_WRITE(REG_GLOBAL2, 0x02, 0xffff);
-
- /* Send all frames with destination addresses matching
- * 01:80:c2:00:00:0x to the CPU port.
- */
- REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
-
- /* Disable the loopback filter, disable flow control
- * messages, disable flood broadcast override, disable
- * removing of provider tags, disable ATU age violation
- * interrupts, disable tag flow control, force flow
- * control priority to the highest, and send all special
- * multicast frames to the CPU at the highest priority.
- */
- REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
-
- /* Program the DSA routing table. */
- for (i = 0; i < 32; i++) {
- int nexthop;
-
- nexthop = 0x1f;
- if (i != ds->index && i < ds->dst->pd->nr_chips)
- nexthop = ds->pd->rtable[i] & 0x1f;
-
- REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
- }
-
- /* Clear all trunk masks. */
- for (i = 0; i < 8; i++)
- REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff);
-
- /* Clear all trunk mappings. */
- for (i = 0; i < 16; i++)
- REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
-
- /* Disable ingress rate limiting by resetting all ingress
- * rate limit registers to their initial state.
- */
- for (i = 0; i < 6; i++)
- REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8));
-
- /* Initialise cross-chip port VLAN table to reset defaults. */
- REG_WRITE(REG_GLOBAL2, 0x0b, 0x9000);
-
- /* Clear the priority override table. */
- for (i = 0; i < 16; i++)
- REG_WRITE(REG_GLOBAL2, 0x0f, 0x8000 | (i << 8));
-
- /* @@@ initialise AVB (22/23) watchdog (27) sdet (29) registers */
+ REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL_2, ds->index & 0x1f);
return 0;
}
-static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
-{
- int addr = REG_PORT(p);
- u16 val;
-
- /* MAC Forcing register: don't force link, speed, duplex
- * or flow control state to any particular values on physical
- * ports, but force the CPU port and all DSA ports to 1000 Mb/s
- * full duplex.
- */
- if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
- REG_WRITE(addr, 0x01, 0x003e);
- else
- REG_WRITE(addr, 0x01, 0x0003);
-
- /* Do not limit the period of time that this port can be
- * paused for by the remote end or the period of time that
- * this port can pause the remote end.
- */
- REG_WRITE(addr, 0x02, 0x0000);
-
- /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
- * disable Header mode, enable IGMP/MLD snooping, disable VLAN
- * tunneling, determine priority by looking at 802.1p and IP
- * priority fields (IP prio has precedence), and set STP state
- * to Forwarding.
- *
- * If this is the CPU link, use DSA or EDSA tagging depending
- * on which tagging mode was configured.
- *
- * If this is a link to another switch, use DSA tagging mode.
- *
- * If this is the upstream port for this switch, enable
- * forwarding of unknown unicasts and multicasts.
- */
- val = 0x0433;
- if (dsa_is_cpu_port(ds, p)) {
- if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
- val |= 0x3300;
- else
- val |= 0x0100;
- }
- if (ds->dsa_port_mask & (1 << p))
- val |= 0x0100;
- if (p == dsa_upstream_port(ds))
- val |= 0x000c;
- REG_WRITE(addr, 0x04, val);
-
- /* Port Control 2: don't force a good FCS, set the maximum
- * frame size to 10240 bytes, don't let the switch add or
- * strip 802.1q tags, don't discard tagged or untagged frames
- * on this port, do a destination address lookup on all
- * received packets as usual, disable ARP mirroring and don't
- * send a copy of all transmitted/received frames on this port
- * to the CPU.
- */
- REG_WRITE(addr, 0x08, 0x2080);
-
- /* Egress rate control: disable egress rate control. */
- REG_WRITE(addr, 0x09, 0x0001);
-
- /* Egress rate control 2: disable egress rate control. */
- REG_WRITE(addr, 0x0a, 0x0000);
-
- /* Port Association Vector: when learning source addresses
- * of packets, add the address to the address database using
- * a port bitmap that has only the bit for this port set and
- * the other bits clear.
- */
- REG_WRITE(addr, 0x0b, 1 << p);
-
- /* Port ATU control: disable limiting the number of address
- * database entries that this port is allowed to use.
- */
- REG_WRITE(addr, 0x0c, 0x0000);
-
- /* Priority Override: disable DA, SA and VTU priority override. */
- REG_WRITE(addr, 0x0d, 0x0000);
-
- /* Port Ethertype: use the Ethertype DSA Ethertype value. */
- REG_WRITE(addr, 0x0f, ETH_P_EDSA);
-
- /* Tag Remap: use an identity 802.1p prio -> switch prio
- * mapping.
- */
- REG_WRITE(addr, 0x18, 0x3210);
-
- /* Tag Remap 2: use an identity 802.1p prio -> switch prio
- * mapping.
- */
- REG_WRITE(addr, 0x19, 0x7654);
-
- return mv88e6xxx_setup_port_common(ds, p);
-}
-
static int mv88e6123_61_65_setup(struct dsa_switch *ds)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
- int i;
int ret;
ret = mv88e6xxx_setup_common(ds);
@@ -262,19 +110,11 @@ static int mv88e6123_61_65_setup(struct dsa_switch *ds)
if (ret < 0)
return ret;
- /* @@@ initialise vtu and atu */
-
ret = mv88e6123_61_65_setup_global(ds);
if (ret < 0)
return ret;
- for (i = 0; i < ps->num_ports; i++) {
- ret = mv88e6123_61_65_setup_port(ds, i);
- if (ret < 0)
- return ret;
- }
-
- return 0;
+ return mv88e6xxx_setup_ports(ds);
}
struct dsa_switch_driver mv88e6123_61_65_switch_driver = {
diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c
index e54824fa0d95..32f4a08e9bc9 100644
--- a/drivers/net/dsa/mv88e6131.c
+++ b/drivers/net/dsa/mv88e6131.c
@@ -37,6 +37,8 @@ static char *mv88e6131_probe(struct device *host_dev, int sw_addr)
return "Marvell 88E6131 (B2)";
if (ret_masked == PORT_SWITCH_ID_6131)
return "Marvell 88E6131";
+ if (ret_masked == PORT_SWITCH_ID_6185)
+ return "Marvell 88E6185";
}
return NULL;
@@ -44,186 +46,62 @@ static char *mv88e6131_probe(struct device *host_dev, int sw_addr)
static int mv88e6131_setup_global(struct dsa_switch *ds)
{
+ u32 upstream_port = dsa_upstream_port(ds);
int ret;
- int i;
+ u32 reg;
+
+ ret = mv88e6xxx_setup_global(ds);
+ if (ret)
+ return ret;
/* Enable the PHY polling unit, don't discard packets with
* excessive collisions, use a weighted fair queueing scheme
* to arbitrate between packet queues, set the maximum frame
* size to 1632, and mask all interrupt sources.
*/
- REG_WRITE(REG_GLOBAL, 0x04, 0x4400);
-
- /* Set the default address aging time to 5 minutes, and
- * enable address learn messages to be sent to all message
- * ports.
- */
- REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
-
- /* Configure the priority mapping registers. */
- ret = mv88e6xxx_config_prio(ds);
- if (ret < 0)
- return ret;
+ REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL,
+ GLOBAL_CONTROL_PPU_ENABLE | GLOBAL_CONTROL_MAX_FRAME_1632);
/* Set the VLAN ethertype to 0x8100. */
- REG_WRITE(REG_GLOBAL, 0x19, 0x8100);
+ REG_WRITE(REG_GLOBAL, GLOBAL_CORE_TAG_TYPE, 0x8100);
/* Disable ARP mirroring, and configure the upstream port as
* the port to which ingress and egress monitor frames are to
* be sent.
*/
- REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1100) | 0x00f0);
+ reg = upstream_port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
+ upstream_port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT |
+ GLOBAL_MONITOR_CONTROL_ARP_DISABLED;
+ REG_WRITE(REG_GLOBAL, GLOBAL_MONITOR_CONTROL, reg);
/* Disable cascade port functionality unless this device
* is used in a cascade configuration, and set the switch's
* DSA device number.
*/
if (ds->dst->pd->nr_chips > 1)
- REG_WRITE(REG_GLOBAL, 0x1c, 0xf000 | (ds->index & 0x1f));
+ REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL_2,
+ GLOBAL_CONTROL_2_MULTIPLE_CASCADE |
+ (ds->index & 0x1f));
else
- REG_WRITE(REG_GLOBAL, 0x1c, 0xe000 | (ds->index & 0x1f));
-
- /* Send all frames with destination addresses matching
- * 01:80:c2:00:00:0x to the CPU port.
- */
- REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
-
- /* Ignore removed tag data on doubly tagged packets, disable
- * flow control messages, force flow control priority to the
- * highest, and send all special multicast frames to the CPU
- * port at the highest priority.
- */
- REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
-
- /* Program the DSA routing table. */
- for (i = 0; i < 32; i++) {
- int nexthop;
-
- nexthop = 0x1f;
- if (ds->pd->rtable &&
- i != ds->index && i < ds->dst->pd->nr_chips)
- nexthop = ds->pd->rtable[i] & 0x1f;
-
- REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
- }
-
- /* Clear all trunk masks. */
- for (i = 0; i < 8; i++)
- REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0x7ff);
-
- /* Clear all trunk mappings. */
- for (i = 0; i < 16; i++)
- REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
+ REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL_2,
+ GLOBAL_CONTROL_2_NO_CASCADE |
+ (ds->index & 0x1f));
/* Force the priority of IGMP/MLD snoop frames and ARP frames
* to the highest setting.
*/
- REG_WRITE(REG_GLOBAL2, 0x0f, 0x00ff);
+ REG_WRITE(REG_GLOBAL2, GLOBAL2_PRIO_OVERRIDE,
+ GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP |
+ 7 << GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT |
+ GLOBAL2_PRIO_OVERRIDE_FORCE_ARP |
+ 7 << GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT);
return 0;
}
-static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
-{
- struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
- int addr = REG_PORT(p);
- u16 val;
-
- /* MAC Forcing register: don't force link, speed, duplex
- * or flow control state to any particular values on physical
- * ports, but force the CPU port and all DSA ports to 1000 Mb/s
- * (100 Mb/s on 6085) full duplex.
- */
- if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
- if (ps->id == PORT_SWITCH_ID_6085)
- REG_WRITE(addr, 0x01, 0x003d); /* 100 Mb/s */
- else
- REG_WRITE(addr, 0x01, 0x003e); /* 1000 Mb/s */
- else
- REG_WRITE(addr, 0x01, 0x0003);
-
- /* Port Control: disable Core Tag, disable Drop-on-Lock,
- * transmit frames unmodified, disable Header mode,
- * enable IGMP/MLD snoop, disable DoubleTag, disable VLAN
- * tunneling, determine priority by looking at 802.1p and
- * IP priority fields (IP prio has precedence), and set STP
- * state to Forwarding.
- *
- * If this is the upstream port for this switch, enable
- * forwarding of unknown unicasts, and enable DSA tagging
- * mode.
- *
- * If this is the link to another switch, use DSA tagging
- * mode, but do not enable forwarding of unknown unicasts.
- */
- val = 0x0433;
- if (p == dsa_upstream_port(ds)) {
- val |= 0x0104;
- /* On 6085, unknown multicast forward is controlled
- * here rather than in Port Control 2 register.
- */
- if (ps->id == PORT_SWITCH_ID_6085)
- val |= 0x0008;
- }
- if (ds->dsa_port_mask & (1 << p))
- val |= 0x0100;
- REG_WRITE(addr, 0x04, val);
-
- /* Port Control 2: don't force a good FCS, don't use
- * VLAN-based, source address-based or destination
- * address-based priority overrides, don't let the switch
- * add or strip 802.1q tags, don't discard tagged or
- * untagged frames on this port, do a destination address
- * lookup on received packets as usual, don't send a copy
- * of all transmitted/received frames on this port to the
- * CPU, and configure the upstream port number.
- *
- * If this is the upstream port for this switch, enable
- * forwarding of unknown multicast addresses.
- */
- if (ps->id == PORT_SWITCH_ID_6085)
- /* on 6085, bits 3:0 are reserved, bit 6 control ARP
- * mirroring, and multicast forward is handled in
- * Port Control register.
- */
- REG_WRITE(addr, 0x08, 0x0080);
- else {
- val = 0x0080 | dsa_upstream_port(ds);
- if (p == dsa_upstream_port(ds))
- val |= 0x0040;
- REG_WRITE(addr, 0x08, val);
- }
-
- /* Rate Control: disable ingress rate limiting. */
- REG_WRITE(addr, 0x09, 0x0000);
-
- /* Rate Control 2: disable egress rate limiting. */
- REG_WRITE(addr, 0x0a, 0x0000);
-
- /* Port Association Vector: when learning source addresses
- * of packets, add the address to the address database using
- * a port bitmap that has only the bit for this port set and
- * the other bits clear.
- */
- REG_WRITE(addr, 0x0b, 1 << p);
-
- /* Tag Remap: use an identity 802.1p prio -> switch prio
- * mapping.
- */
- REG_WRITE(addr, 0x18, 0x3210);
-
- /* Tag Remap 2: use an identity 802.1p prio -> switch prio
- * mapping.
- */
- REG_WRITE(addr, 0x19, 0x7654);
-
- return mv88e6xxx_setup_port_common(ds, p);
-}
-
static int mv88e6131_setup(struct dsa_switch *ds)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
- int i;
int ret;
ret = mv88e6xxx_setup_common(ds);
@@ -234,6 +112,7 @@ static int mv88e6131_setup(struct dsa_switch *ds)
switch (ps->id) {
case PORT_SWITCH_ID_6085:
+ case PORT_SWITCH_ID_6185:
ps->num_ports = 10;
break;
case PORT_SWITCH_ID_6095:
@@ -251,19 +130,11 @@ static int mv88e6131_setup(struct dsa_switch *ds)
if (ret < 0)
return ret;
- /* @@@ initialise vtu and atu */
-
ret = mv88e6131_setup_global(ds);
if (ret < 0)
return ret;
- for (i = 0; i < ps->num_ports; i++) {
- ret = mv88e6131_setup_port(ds, i);
- if (ret < 0)
- return ret;
- }
-
- return 0;
+ return mv88e6xxx_setup_ports(ds);
}
static int mv88e6131_port_to_phy_addr(struct dsa_switch *ds, int port)
diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c
index 9104efea0e3e..1c7808495a9d 100644
--- a/drivers/net/dsa/mv88e6171.c
+++ b/drivers/net/dsa/mv88e6171.c
@@ -1,4 +1,4 @@
-/* net/dsa/mv88e6171.c - Marvell 88e6171/8826172 switch chip support
+/* net/dsa/mv88e6171.c - Marvell 88e6171 switch chip support
* Copyright (c) 2008-2009 Marvell Semiconductor
* Copyright (c) 2014 Claudio Leite <leitec@staticky.com>
*
@@ -29,8 +29,12 @@ static char *mv88e6171_probe(struct device *host_dev, int sw_addr)
if (ret >= 0) {
if ((ret & 0xfff0) == PORT_SWITCH_ID_6171)
return "Marvell 88E6171";
- if ((ret & 0xfff0) == PORT_SWITCH_ID_6172)
- return "Marvell 88E6172";
+ if ((ret & 0xfff0) == PORT_SWITCH_ID_6175)
+ return "Marvell 88E6175";
+ if ((ret & 0xfff0) == PORT_SWITCH_ID_6350)
+ return "Marvell 88E6350";
+ if ((ret & 0xfff0) == PORT_SWITCH_ID_6351)
+ return "Marvell 88E6351";
}
return NULL;
@@ -38,196 +42,41 @@ static char *mv88e6171_probe(struct device *host_dev, int sw_addr)
static int mv88e6171_setup_global(struct dsa_switch *ds)
{
- struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ u32 upstream_port = dsa_upstream_port(ds);
int ret;
- int i;
+ u32 reg;
+
+ ret = mv88e6xxx_setup_global(ds);
+ if (ret)
+ return ret;
/* Discard packets with excessive collisions, mask all
* interrupt sources, enable PPU.
*/
- REG_WRITE(REG_GLOBAL, 0x04, 0x6000);
-
- /* Set the default address aging time to 5 minutes, and
- * enable address learn messages to be sent to all message
- * ports.
- */
- REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
-
- /* Configure the priority mapping registers. */
- ret = mv88e6xxx_config_prio(ds);
- if (ret < 0)
- return ret;
+ REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL,
+ GLOBAL_CONTROL_PPU_ENABLE | GLOBAL_CONTROL_DISCARD_EXCESS);
/* Configure the upstream port, and configure the upstream
* port as the port to which ingress and egress monitor frames
* are to be sent.
*/
- if (REG_READ(REG_PORT(0), 0x03) == 0x1710)
- REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1111));
- else
- REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110));
+ reg = upstream_port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
+ upstream_port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT |
+ upstream_port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT |
+ upstream_port << GLOBAL_MONITOR_CONTROL_MIRROR_SHIFT;
+ REG_WRITE(REG_GLOBAL, GLOBAL_MONITOR_CONTROL, reg);
/* Disable remote management for now, and set the switch's
* DSA device number.
*/
- REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
-
- /* Send all frames with destination addresses matching
- * 01:80:c2:00:00:2x to the CPU port.
- */
- REG_WRITE(REG_GLOBAL2, 0x02, 0xffff);
-
- /* Send all frames with destination addresses matching
- * 01:80:c2:00:00:0x to the CPU port.
- */
- REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
-
- /* Disable the loopback filter, disable flow control
- * messages, disable flood broadcast override, disable
- * removing of provider tags, disable ATU age violation
- * interrupts, disable tag flow control, force flow
- * control priority to the highest, and send all special
- * multicast frames to the CPU at the highest priority.
- */
- REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
-
- /* Program the DSA routing table. */
- for (i = 0; i < 32; i++) {
- int nexthop;
-
- nexthop = 0x1f;
- if (i != ds->index && i < ds->dst->pd->nr_chips)
- nexthop = ds->pd->rtable[i] & 0x1f;
-
- REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
- }
-
- /* Clear all trunk masks. */
- for (i = 0; i < ps->num_ports; i++)
- REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff);
-
- /* Clear all trunk mappings. */
- for (i = 0; i < 16; i++)
- REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
-
- /* Disable ingress rate limiting by resetting all ingress
- * rate limit registers to their initial state.
- */
- for (i = 0; i < 6; i++)
- REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8));
-
- /* Initialise cross-chip port VLAN table to reset defaults. */
- REG_WRITE(REG_GLOBAL2, 0x0b, 0x9000);
-
- /* Clear the priority override table. */
- for (i = 0; i < 16; i++)
- REG_WRITE(REG_GLOBAL2, 0x0f, 0x8000 | (i << 8));
-
- /* @@@ initialise AVB (22/23) watchdog (27) sdet (29) registers */
+ REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL_2, ds->index & 0x1f);
return 0;
}
-static int mv88e6171_setup_port(struct dsa_switch *ds, int p)
-{
- int addr = REG_PORT(p);
- u16 val;
-
- /* MAC Forcing register: don't force link, speed, duplex
- * or flow control state to any particular values on physical
- * ports, but force the CPU port and all DSA ports to 1000 Mb/s
- * full duplex.
- */
- val = REG_READ(addr, 0x01);
- if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
- REG_WRITE(addr, 0x01, val | 0x003e);
- else
- REG_WRITE(addr, 0x01, val | 0x0003);
-
- /* Do not limit the period of time that this port can be
- * paused for by the remote end or the period of time that
- * this port can pause the remote end.
- */
- REG_WRITE(addr, 0x02, 0x0000);
-
- /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
- * disable Header mode, enable IGMP/MLD snooping, disable VLAN
- * tunneling, determine priority by looking at 802.1p and IP
- * priority fields (IP prio has precedence), and set STP state
- * to Forwarding.
- *
- * If this is the CPU link, use DSA or EDSA tagging depending
- * on which tagging mode was configured.
- *
- * If this is a link to another switch, use DSA tagging mode.
- *
- * If this is the upstream port for this switch, enable
- * forwarding of unknown unicasts and multicasts.
- */
- val = 0x0433;
- if (dsa_is_cpu_port(ds, p)) {
- if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
- val |= 0x3300;
- else
- val |= 0x0100;
- }
- if (ds->dsa_port_mask & (1 << p))
- val |= 0x0100;
- if (p == dsa_upstream_port(ds))
- val |= 0x000c;
- REG_WRITE(addr, 0x04, val);
-
- /* Port Control 2: don't force a good FCS, set the maximum
- * frame size to 10240 bytes, don't let the switch add or
- * strip 802.1q tags, don't discard tagged or untagged frames
- * on this port, do a destination address lookup on all
- * received packets as usual, disable ARP mirroring and don't
- * send a copy of all transmitted/received frames on this port
- * to the CPU.
- */
- REG_WRITE(addr, 0x08, 0x2080);
-
- /* Egress rate control: disable egress rate control. */
- REG_WRITE(addr, 0x09, 0x0001);
-
- /* Egress rate control 2: disable egress rate control. */
- REG_WRITE(addr, 0x0a, 0x0000);
-
- /* Port Association Vector: when learning source addresses
- * of packets, add the address to the address database using
- * a port bitmap that has only the bit for this port set and
- * the other bits clear.
- */
- REG_WRITE(addr, 0x0b, 1 << p);
-
- /* Port ATU control: disable limiting the number of address
- * database entries that this port is allowed to use.
- */
- REG_WRITE(addr, 0x0c, 0x0000);
-
- /* Priority Override: disable DA, SA and VTU priority override. */
- REG_WRITE(addr, 0x0d, 0x0000);
-
- /* Port Ethertype: use the Ethertype DSA Ethertype value. */
- REG_WRITE(addr, 0x0f, ETH_P_EDSA);
-
- /* Tag Remap: use an identity 802.1p prio -> switch prio
- * mapping.
- */
- REG_WRITE(addr, 0x18, 0x3210);
-
- /* Tag Remap 2: use an identity 802.1p prio -> switch prio
- * mapping.
- */
- REG_WRITE(addr, 0x19, 0x7654);
-
- return mv88e6xxx_setup_port_common(ds, p);
-}
-
static int mv88e6171_setup(struct dsa_switch *ds)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
- int i;
int ret;
ret = mv88e6xxx_setup_common(ds);
@@ -240,44 +89,11 @@ static int mv88e6171_setup(struct dsa_switch *ds)
if (ret < 0)
return ret;
- /* @@@ initialise vtu and atu */
-
ret = mv88e6171_setup_global(ds);
if (ret < 0)
return ret;
- for (i = 0; i < ps->num_ports; i++) {
- if (!(dsa_is_cpu_port(ds, i) || ds->phys_port_mask & (1 << i)))
- continue;
-
- ret = mv88e6171_setup_port(ds, i);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-static int mv88e6171_get_eee(struct dsa_switch *ds, int port,
- struct ethtool_eee *e)
-{
- struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
-
- if (ps->id == PORT_SWITCH_ID_6172)
- return mv88e6xxx_get_eee(ds, port, e);
-
- return -EOPNOTSUPP;
-}
-
-static int mv88e6171_set_eee(struct dsa_switch *ds, int port,
- struct phy_device *phydev, struct ethtool_eee *e)
-{
- struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
-
- if (ps->id == PORT_SWITCH_ID_6172)
- return mv88e6xxx_set_eee(ds, port, phydev, e);
-
- return -EOPNOTSUPP;
+ return mv88e6xxx_setup_ports(ds);
}
struct dsa_switch_driver mv88e6171_switch_driver = {
@@ -292,8 +108,6 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
.get_strings = mv88e6xxx_get_strings,
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
.get_sset_count = mv88e6xxx_get_sset_count,
- .set_eee = mv88e6171_set_eee,
- .get_eee = mv88e6171_get_eee,
#ifdef CONFIG_NET_DSA_HWMON
.get_temp = mv88e6xxx_get_temp,
#endif
@@ -308,4 +122,6 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
};
MODULE_ALIAS("platform:mv88e6171");
-MODULE_ALIAS("platform:mv88e6172");
+MODULE_ALIAS("platform:mv88e6175");
+MODULE_ALIAS("platform:mv88e6350");
+MODULE_ALIAS("platform:mv88e6351");
diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c
index 126c11b81e75..632815c10a40 100644
--- a/drivers/net/dsa/mv88e6352.c
+++ b/drivers/net/dsa/mv88e6352.c
@@ -32,6 +32,8 @@ static char *mv88e6352_probe(struct device *host_dev, int sw_addr)
ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), PORT_SWITCH_ID);
if (ret >= 0) {
+ if ((ret & 0xfff0) == PORT_SWITCH_ID_6172)
+ return "Marvell 88E6172";
if ((ret & 0xfff0) == PORT_SWITCH_ID_6176)
return "Marvell 88E6176";
if (ret == PORT_SWITCH_ID_6352_A0)
@@ -47,187 +49,37 @@ static char *mv88e6352_probe(struct device *host_dev, int sw_addr)
static int mv88e6352_setup_global(struct dsa_switch *ds)
{
- struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ u32 upstream_port = dsa_upstream_port(ds);
int ret;
- int i;
+ u32 reg;
+
+ ret = mv88e6xxx_setup_global(ds);
+ if (ret)
+ return ret;
/* Discard packets with excessive collisions,
* mask all interrupt sources, enable PPU (bit 14, undocumented).
*/
- REG_WRITE(REG_GLOBAL, 0x04, 0x6000);
-
- /* Set the default address aging time to 5 minutes, and
- * enable address learn messages to be sent to all message
- * ports.
- */
- REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
-
- /* Configure the priority mapping registers. */
- ret = mv88e6xxx_config_prio(ds);
- if (ret < 0)
- return ret;
+ REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL,
+ GLOBAL_CONTROL_PPU_ENABLE | GLOBAL_CONTROL_DISCARD_EXCESS);
/* Configure the upstream port, and configure the upstream
* port as the port to which ingress and egress monitor frames
* are to be sent.
*/
- REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110));
+ reg = upstream_port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
+ upstream_port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT |
+ upstream_port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT;
+ REG_WRITE(REG_GLOBAL, GLOBAL_MONITOR_CONTROL, reg);
/* Disable remote management for now, and set the switch's
* DSA device number.
*/
REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
- /* Send all frames with destination addresses matching
- * 01:80:c2:00:00:2x to the CPU port.
- */
- REG_WRITE(REG_GLOBAL2, 0x02, 0xffff);
-
- /* Send all frames with destination addresses matching
- * 01:80:c2:00:00:0x to the CPU port.
- */
- REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
-
- /* Disable the loopback filter, disable flow control
- * messages, disable flood broadcast override, disable
- * removing of provider tags, disable ATU age violation
- * interrupts, disable tag flow control, force flow
- * control priority to the highest, and send all special
- * multicast frames to the CPU at the highest priority.
- */
- REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
-
- /* Program the DSA routing table. */
- for (i = 0; i < 32; i++) {
- int nexthop = 0x1f;
-
- if (i != ds->index && i < ds->dst->pd->nr_chips)
- nexthop = ds->pd->rtable[i] & 0x1f;
-
- REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
- }
-
- /* Clear all trunk masks. */
- for (i = 0; i < 8; i++)
- REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0x7f);
-
- /* Clear all trunk mappings. */
- for (i = 0; i < 16; i++)
- REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
-
- /* Disable ingress rate limiting by resetting all ingress
- * rate limit registers to their initial state.
- */
- for (i = 0; i < ps->num_ports; i++)
- REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8));
-
- /* Initialise cross-chip port VLAN table to reset defaults. */
- REG_WRITE(REG_GLOBAL2, 0x0b, 0x9000);
-
- /* Clear the priority override table. */
- for (i = 0; i < 16; i++)
- REG_WRITE(REG_GLOBAL2, 0x0f, 0x8000 | (i << 8));
-
- /* @@@ initialise AVB (22/23) watchdog (27) sdet (29) registers */
-
return 0;
}
-static int mv88e6352_setup_port(struct dsa_switch *ds, int p)
-{
- int addr = REG_PORT(p);
- u16 val;
-
- /* MAC Forcing register: don't force link, speed, duplex
- * or flow control state to any particular values on physical
- * ports, but force the CPU port and all DSA ports to 1000 Mb/s
- * full duplex.
- */
- if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
- REG_WRITE(addr, 0x01, 0x003e);
- else
- REG_WRITE(addr, 0x01, 0x0003);
-
- /* Do not limit the period of time that this port can be
- * paused for by the remote end or the period of time that
- * this port can pause the remote end.
- */
- REG_WRITE(addr, 0x02, 0x0000);
-
- /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
- * disable Header mode, enable IGMP/MLD snooping, disable VLAN
- * tunneling, determine priority by looking at 802.1p and IP
- * priority fields (IP prio has precedence), and set STP state
- * to Forwarding.
- *
- * If this is the CPU link, use DSA or EDSA tagging depending
- * on which tagging mode was configured.
- *
- * If this is a link to another switch, use DSA tagging mode.
- *
- * If this is the upstream port for this switch, enable
- * forwarding of unknown unicasts and multicasts.
- */
- val = 0x0433;
- if (dsa_is_cpu_port(ds, p)) {
- if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
- val |= 0x3300;
- else
- val |= 0x0100;
- }
- if (ds->dsa_port_mask & (1 << p))
- val |= 0x0100;
- if (p == dsa_upstream_port(ds))
- val |= 0x000c;
- REG_WRITE(addr, 0x04, val);
-
- /* Port Control 2: don't force a good FCS, set the maximum
- * frame size to 10240 bytes, don't let the switch add or
- * strip 802.1q tags, don't discard tagged or untagged frames
- * on this port, do a destination address lookup on all
- * received packets as usual, disable ARP mirroring and don't
- * send a copy of all transmitted/received frames on this port
- * to the CPU.
- */
- REG_WRITE(addr, 0x08, 0x2080);
-
- /* Egress rate control: disable egress rate control. */
- REG_WRITE(addr, 0x09, 0x0001);
-
- /* Egress rate control 2: disable egress rate control. */
- REG_WRITE(addr, 0x0a, 0x0000);
-
- /* Port Association Vector: when learning source addresses
- * of packets, add the address to the address database using
- * a port bitmap that has only the bit for this port set and
- * the other bits clear.
- */
- REG_WRITE(addr, 0x0b, 1 << p);
-
- /* Port ATU control: disable limiting the number of address
- * database entries that this port is allowed to use.
- */
- REG_WRITE(addr, 0x0c, 0x0000);
-
- /* Priority Override: disable DA, SA and VTU priority override. */
- REG_WRITE(addr, 0x0d, 0x0000);
-
- /* Port Ethertype: use the Ethertype DSA Ethertype value. */
- REG_WRITE(addr, 0x0f, ETH_P_EDSA);
-
- /* Tag Remap: use an identity 802.1p prio -> switch prio
- * mapping.
- */
- REG_WRITE(addr, 0x18, 0x3210);
-
- /* Tag Remap 2: use an identity 802.1p prio -> switch prio
- * mapping.
- */
- REG_WRITE(addr, 0x19, 0x7654);
-
- return mv88e6xxx_setup_port_common(ds, p);
-}
-
#ifdef CONFIG_NET_DSA_HWMON
static int mv88e6352_get_temp(struct dsa_switch *ds, int *temp)
@@ -292,7 +144,6 @@ static int mv88e6352_setup(struct dsa_switch *ds)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int ret;
- int i;
ret = mv88e6xxx_setup_common(ds);
if (ret < 0)
@@ -306,19 +157,11 @@ static int mv88e6352_setup(struct dsa_switch *ds)
if (ret < 0)
return ret;
- /* @@@ initialise vtu and atu */
-
ret = mv88e6352_setup_global(ds);
if (ret < 0)
return ret;
- for (i = 0; i < ps->num_ports; i++) {
- ret = mv88e6352_setup_port(ds, i);
- if (ret < 0)
- return ret;
- }
-
- return 0;
+ return mv88e6xxx_setup_ports(ds);
}
static int mv88e6352_read_eeprom_word(struct dsa_switch *ds, int addr)
@@ -552,3 +395,4 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
};
MODULE_ALIAS("platform:mv88e6352");
+MODULE_ALIAS("platform:mv88e6172");
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index cf309aa92802..fd8547c2b79d 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -8,6 +8,7 @@
* (at your option) any later version.
*/
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/if_bridge.h>
@@ -16,9 +17,38 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/phy.h>
+#include <linux/seq_file.h>
#include <net/dsa.h>
#include "mv88e6xxx.h"
+/* MDIO bus access can be nested in the case of PHYs connected to the
+ * internal MDIO bus of the switch, which is accessed via MDIO bus of
+ * the Ethernet interface. Avoid lockdep false positives by using
+ * mutex_lock_nested().
+ */
+static int mv88e6xxx_mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
+{
+ int ret;
+
+ mutex_lock_nested(&bus->mdio_lock, SINGLE_DEPTH_NESTING);
+ ret = bus->read(bus, addr, regnum);
+ mutex_unlock(&bus->mdio_lock);
+
+ return ret;
+}
+
+static int mv88e6xxx_mdiobus_write(struct mii_bus *bus, int addr, u32 regnum,
+ u16 val)
+{
+ int ret;
+
+ mutex_lock_nested(&bus->mdio_lock, SINGLE_DEPTH_NESTING);
+ ret = bus->write(bus, addr, regnum, val);
+ mutex_unlock(&bus->mdio_lock);
+
+ return ret;
+}
+
/* If the switch's ADDR[4:0] strap pins are strapped to zero, it will
* use all 32 SMI bus addresses on its SMI bus, and all switch registers
* will be directly accessible on some {device address,register address}
@@ -33,7 +63,7 @@ static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr)
int i;
for (i = 0; i < 16; i++) {
- ret = mdiobus_read(bus, sw_addr, SMI_CMD);
+ ret = mv88e6xxx_mdiobus_read(bus, sw_addr, SMI_CMD);
if (ret < 0)
return ret;
@@ -49,7 +79,7 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
int ret;
if (sw_addr == 0)
- return mdiobus_read(bus, addr, reg);
+ return mv88e6xxx_mdiobus_read(bus, addr, reg);
/* Wait for the bus to become free. */
ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
@@ -57,8 +87,8 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
return ret;
/* Transmit the read command. */
- ret = mdiobus_write(bus, sw_addr, SMI_CMD,
- SMI_CMD_OP_22_READ | (addr << 5) | reg);
+ ret = mv88e6xxx_mdiobus_write(bus, sw_addr, SMI_CMD,
+ SMI_CMD_OP_22_READ | (addr << 5) | reg);
if (ret < 0)
return ret;
@@ -68,7 +98,7 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
return ret;
/* Read the data. */
- ret = mdiobus_read(bus, sw_addr, SMI_DATA);
+ ret = mv88e6xxx_mdiobus_read(bus, sw_addr, SMI_DATA);
if (ret < 0)
return ret;
@@ -112,7 +142,7 @@ int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
int ret;
if (sw_addr == 0)
- return mdiobus_write(bus, addr, reg, val);
+ return mv88e6xxx_mdiobus_write(bus, addr, reg, val);
/* Wait for the bus to become free. */
ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
@@ -120,13 +150,13 @@ int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
return ret;
/* Transmit the data to write. */
- ret = mdiobus_write(bus, sw_addr, SMI_DATA, val);
+ ret = mv88e6xxx_mdiobus_write(bus, sw_addr, SMI_DATA, val);
if (ret < 0)
return ret;
/* Transmit the write command. */
- ret = mdiobus_write(bus, sw_addr, SMI_CMD,
- SMI_CMD_OP_22_WRITE | (addr << 5) | reg);
+ ret = mv88e6xxx_mdiobus_write(bus, sw_addr, SMI_CMD,
+ SMI_CMD_OP_22_WRITE | (addr << 5) | reg);
if (ret < 0)
return ret;
@@ -165,24 +195,6 @@ int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
return ret;
}
-int mv88e6xxx_config_prio(struct dsa_switch *ds)
-{
- /* Configure the IP ToS mapping registers. */
- REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_0, 0x0000);
- REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_1, 0x0000);
- REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_2, 0x5555);
- REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_3, 0x5555);
- REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_4, 0xaaaa);
- REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_5, 0xaaaa);
- REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_6, 0xffff);
- REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_7, 0xffff);
-
- /* Configure the IEEE 802.1p priority mapping register. */
- REG_WRITE(REG_GLOBAL, GLOBAL_IEEE_PRI, 0xfa41);
-
- return 0;
-}
-
int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr)
{
REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, (addr[0] << 8) | addr[1]);
@@ -217,20 +229,20 @@ int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr)
return 0;
}
-/* Must be called with phy mutex held */
+/* Must be called with SMI mutex held */
static int _mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum)
{
if (addr >= 0)
- return mv88e6xxx_reg_read(ds, addr, regnum);
+ return _mv88e6xxx_reg_read(ds, addr, regnum);
return 0xffff;
}
-/* Must be called with phy mutex held */
+/* Must be called with SMI mutex held */
static int _mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum,
u16 val)
{
if (addr >= 0)
- return mv88e6xxx_reg_write(ds, addr, regnum, val);
+ return _mv88e6xxx_reg_write(ds, addr, regnum, val);
return 0;
}
@@ -434,26 +446,113 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds)
}
}
+static bool mv88e6xxx_6065_family(struct dsa_switch *ds)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+
+ switch (ps->id) {
+ case PORT_SWITCH_ID_6031:
+ case PORT_SWITCH_ID_6061:
+ case PORT_SWITCH_ID_6035:
+ case PORT_SWITCH_ID_6065:
+ return true;
+ }
+ return false;
+}
+
+static bool mv88e6xxx_6095_family(struct dsa_switch *ds)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+
+ switch (ps->id) {
+ case PORT_SWITCH_ID_6092:
+ case PORT_SWITCH_ID_6095:
+ return true;
+ }
+ return false;
+}
+
+static bool mv88e6xxx_6097_family(struct dsa_switch *ds)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+
+ switch (ps->id) {
+ case PORT_SWITCH_ID_6046:
+ case PORT_SWITCH_ID_6085:
+ case PORT_SWITCH_ID_6096:
+ case PORT_SWITCH_ID_6097:
+ return true;
+ }
+ return false;
+}
+
+static bool mv88e6xxx_6165_family(struct dsa_switch *ds)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+
+ switch (ps->id) {
+ case PORT_SWITCH_ID_6123:
+ case PORT_SWITCH_ID_6161:
+ case PORT_SWITCH_ID_6165:
+ return true;
+ }
+ return false;
+}
+
+static bool mv88e6xxx_6185_family(struct dsa_switch *ds)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+
+ switch (ps->id) {
+ case PORT_SWITCH_ID_6121:
+ case PORT_SWITCH_ID_6122:
+ case PORT_SWITCH_ID_6152:
+ case PORT_SWITCH_ID_6155:
+ case PORT_SWITCH_ID_6182:
+ case PORT_SWITCH_ID_6185:
+ case PORT_SWITCH_ID_6108:
+ case PORT_SWITCH_ID_6131:
+ return true;
+ }
+ return false;
+}
+
+static bool mv88e6xxx_6351_family(struct dsa_switch *ds)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+
+ switch (ps->id) {
+ case PORT_SWITCH_ID_6171:
+ case PORT_SWITCH_ID_6175:
+ case PORT_SWITCH_ID_6350:
+ case PORT_SWITCH_ID_6351:
+ return true;
+ }
+ return false;
+}
+
static bool mv88e6xxx_6352_family(struct dsa_switch *ds)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
switch (ps->id) {
- case PORT_SWITCH_ID_6352:
case PORT_SWITCH_ID_6172:
case PORT_SWITCH_ID_6176:
+ case PORT_SWITCH_ID_6240:
+ case PORT_SWITCH_ID_6352:
return true;
}
return false;
}
-static int mv88e6xxx_stats_wait(struct dsa_switch *ds)
+/* Must be called with SMI mutex held */
+static int _mv88e6xxx_stats_wait(struct dsa_switch *ds)
{
int ret;
int i;
for (i = 0; i < 10; i++) {
- ret = REG_READ(REG_GLOBAL, GLOBAL_STATS_OP);
+ ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_OP);
if ((ret & GLOBAL_STATS_OP_BUSY) == 0)
return 0;
}
@@ -461,7 +560,8 @@ static int mv88e6xxx_stats_wait(struct dsa_switch *ds)
return -ETIMEDOUT;
}
-static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
+/* Must be called with SMI mutex held */
+static int _mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
{
int ret;
@@ -469,42 +569,45 @@ static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
port = (port + 1) << 5;
/* Snapshot the hardware statistics counters for this port. */
- REG_WRITE(REG_GLOBAL, GLOBAL_STATS_OP,
- GLOBAL_STATS_OP_CAPTURE_PORT |
- GLOBAL_STATS_OP_HIST_RX_TX | port);
+ ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP,
+ GLOBAL_STATS_OP_CAPTURE_PORT |
+ GLOBAL_STATS_OP_HIST_RX_TX | port);
+ if (ret < 0)
+ return ret;
/* Wait for the snapshotting to complete. */
- ret = mv88e6xxx_stats_wait(ds);
+ ret = _mv88e6xxx_stats_wait(ds);
if (ret < 0)
return ret;
return 0;
}
-static void mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val)
+/* Must be called with SMI mutex held */
+static void _mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val)
{
u32 _val;
int ret;
*val = 0;
- ret = mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP,
- GLOBAL_STATS_OP_READ_CAPTURED |
- GLOBAL_STATS_OP_HIST_RX_TX | stat);
+ ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP,
+ GLOBAL_STATS_OP_READ_CAPTURED |
+ GLOBAL_STATS_OP_HIST_RX_TX | stat);
if (ret < 0)
return;
- ret = mv88e6xxx_stats_wait(ds);
+ ret = _mv88e6xxx_stats_wait(ds);
if (ret < 0)
return;
- ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_32);
+ ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_32);
if (ret < 0)
return;
_val = ret << 16;
- ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_01);
+ ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_01);
if (ret < 0)
return;
@@ -578,6 +681,40 @@ static void _mv88e6xxx_get_strings(struct dsa_switch *ds,
}
}
+static uint64_t _mv88e6xxx_get_ethtool_stat(struct dsa_switch *ds,
+ int stat,
+ struct mv88e6xxx_hw_stat *stats,
+ int port)
+{
+ struct mv88e6xxx_hw_stat *s = stats + stat;
+ u32 low;
+ u32 high = 0;
+ int ret;
+ u64 value;
+
+ if (s->reg >= 0x100) {
+ ret = _mv88e6xxx_reg_read(ds, REG_PORT(port),
+ s->reg - 0x100);
+ if (ret < 0)
+ return UINT64_MAX;
+
+ low = ret;
+ if (s->sizeof_stat == 4) {
+ ret = _mv88e6xxx_reg_read(ds, REG_PORT(port),
+ s->reg - 0x100 + 1);
+ if (ret < 0)
+ return UINT64_MAX;
+ high = ret;
+ }
+ } else {
+ _mv88e6xxx_stats_read(ds, s->reg, &low);
+ if (s->sizeof_stat == 8)
+ _mv88e6xxx_stats_read(ds, s->reg + 1, &high);
+ }
+ value = (((u64)high) << 16) | low;
+ return value;
+}
+
static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
int nr_stats,
struct mv88e6xxx_hw_stat *stats,
@@ -587,44 +724,19 @@ static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
int ret;
int i;
- mutex_lock(&ps->stats_mutex);
+ mutex_lock(&ps->smi_mutex);
- ret = mv88e6xxx_stats_snapshot(ds, port);
+ ret = _mv88e6xxx_stats_snapshot(ds, port);
if (ret < 0) {
- mutex_unlock(&ps->stats_mutex);
+ mutex_unlock(&ps->smi_mutex);
return;
}
/* Read each of the counters. */
- for (i = 0; i < nr_stats; i++) {
- struct mv88e6xxx_hw_stat *s = stats + i;
- u32 low;
- u32 high = 0;
+ for (i = 0; i < nr_stats; i++)
+ data[i] = _mv88e6xxx_get_ethtool_stat(ds, i, stats, port);
- if (s->reg >= 0x100) {
- ret = mv88e6xxx_reg_read(ds, REG_PORT(port),
- s->reg - 0x100);
- if (ret < 0)
- goto error;
- low = ret;
- if (s->sizeof_stat == 4) {
- ret = mv88e6xxx_reg_read(ds, REG_PORT(port),
- s->reg - 0x100 + 1);
- if (ret < 0)
- goto error;
- high = ret;
- }
- data[i] = (((u64)high) << 16) | low;
- continue;
- }
- mv88e6xxx_stats_read(ds, s->reg, &low);
- if (s->sizeof_stat == 8)
- mv88e6xxx_stats_read(ds, s->reg + 1, &high);
-
- data[i] = (((u64)high) << 32) | low;
- }
-error:
- mutex_unlock(&ps->stats_mutex);
+ mutex_unlock(&ps->smi_mutex);
}
/* All the statistics in the table */
@@ -694,7 +806,7 @@ int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp)
*temp = 0;
- mutex_lock(&ps->phy_mutex);
+ mutex_lock(&ps->smi_mutex);
ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6);
if (ret < 0)
@@ -727,19 +839,23 @@ int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp)
error:
_mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0);
- mutex_unlock(&ps->phy_mutex);
+ mutex_unlock(&ps->smi_mutex);
return ret;
}
#endif /* CONFIG_NET_DSA_HWMON */
-static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
+/* Must be called with SMI lock held */
+static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset,
+ u16 mask)
{
unsigned long timeout = jiffies + HZ / 10;
while (time_before(jiffies, timeout)) {
int ret;
- ret = REG_READ(reg, offset);
+ ret = _mv88e6xxx_reg_read(ds, reg, offset);
+ if (ret < 0)
+ return ret;
if (!(ret & mask))
return 0;
@@ -748,10 +864,22 @@ static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
return -ETIMEDOUT;
}
-int mv88e6xxx_phy_wait(struct dsa_switch *ds)
+static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
{
- return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
- GLOBAL2_SMI_OP_BUSY);
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ int ret;
+
+ mutex_lock(&ps->smi_mutex);
+ ret = _mv88e6xxx_wait(ds, reg, offset, mask);
+ mutex_unlock(&ps->smi_mutex);
+
+ return ret;
+}
+
+static int _mv88e6xxx_phy_wait(struct dsa_switch *ds)
+{
+ return _mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
+ GLOBAL2_SMI_OP_BUSY);
}
int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds)
@@ -767,56 +895,53 @@ int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds)
}
/* Must be called with SMI lock held */
-static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
+static int _mv88e6xxx_atu_wait(struct dsa_switch *ds)
{
- unsigned long timeout = jiffies + HZ / 10;
-
- while (time_before(jiffies, timeout)) {
- int ret;
-
- ret = _mv88e6xxx_reg_read(ds, reg, offset);
- if (ret < 0)
- return ret;
- if (!(ret & mask))
- return 0;
-
- usleep_range(1000, 2000);
- }
- return -ETIMEDOUT;
+ return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_ATU_OP,
+ GLOBAL_ATU_OP_BUSY);
}
/* Must be called with SMI lock held */
-static int _mv88e6xxx_atu_wait(struct dsa_switch *ds)
+static int _mv88e6xxx_scratch_wait(struct dsa_switch *ds)
{
- return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_ATU_OP,
- GLOBAL_ATU_OP_BUSY);
+ return _mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SCRATCH_MISC,
+ GLOBAL2_SCRATCH_BUSY);
}
-/* Must be called with phy mutex held */
+/* Must be called with SMI mutex held */
static int _mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr,
int regnum)
{
int ret;
- REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP,
- GLOBAL2_SMI_OP_22_READ | (addr << 5) | regnum);
+ ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
+ GLOBAL2_SMI_OP_22_READ | (addr << 5) |
+ regnum);
+ if (ret < 0)
+ return ret;
- ret = mv88e6xxx_phy_wait(ds);
+ ret = _mv88e6xxx_phy_wait(ds);
if (ret < 0)
return ret;
- return REG_READ(REG_GLOBAL2, GLOBAL2_SMI_DATA);
+ return _mv88e6xxx_reg_read(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA);
}
-/* Must be called with phy mutex held */
+/* Must be called with SMI mutex held */
static int _mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr,
int regnum, u16 val)
{
- REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_DATA, val);
- REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP,
- GLOBAL2_SMI_OP_22_WRITE | (addr << 5) | regnum);
+ int ret;
- return mv88e6xxx_phy_wait(ds);
+ ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA, val);
+ if (ret < 0)
+ return ret;
+
+ ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
+ GLOBAL2_SMI_OP_22_WRITE | (addr << 5) |
+ regnum);
+
+ return _mv88e6xxx_phy_wait(ds);
}
int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
@@ -824,7 +949,7 @@ int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int reg;
- mutex_lock(&ps->phy_mutex);
+ mutex_lock(&ps->smi_mutex);
reg = _mv88e6xxx_phy_read_indirect(ds, port, 16);
if (reg < 0)
@@ -833,7 +958,7 @@ int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
e->eee_enabled = !!(reg & 0x0200);
e->tx_lpi_enabled = !!(reg & 0x0100);
- reg = mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS);
+ reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS);
if (reg < 0)
goto out;
@@ -841,7 +966,7 @@ int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
reg = 0;
out:
- mutex_unlock(&ps->phy_mutex);
+ mutex_unlock(&ps->smi_mutex);
return reg;
}
@@ -852,7 +977,7 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
int reg;
int ret;
- mutex_lock(&ps->phy_mutex);
+ mutex_lock(&ps->smi_mutex);
ret = _mv88e6xxx_phy_read_indirect(ds, port, 16);
if (ret < 0)
@@ -866,7 +991,7 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
ret = _mv88e6xxx_phy_write_indirect(ds, port, 16, reg);
out:
- mutex_unlock(&ps->phy_mutex);
+ mutex_unlock(&ps->smi_mutex);
return ret;
}
@@ -1241,13 +1366,212 @@ static void mv88e6xxx_bridge_work(struct work_struct *work)
}
}
-int mv88e6xxx_setup_port_common(struct dsa_switch *ds, int port)
+static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int ret, fid;
+ u16 reg;
mutex_lock(&ps->smi_mutex);
+ if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
+ mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
+ mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) ||
+ mv88e6xxx_6065_family(ds)) {
+ /* MAC Forcing register: don't force link, speed,
+ * duplex or flow control state to any particular
+ * values on physical ports, but force the CPU port
+ * and all DSA ports to their maximum bandwidth and
+ * full duplex.
+ */
+ reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_PCS_CTRL);
+ if (dsa_is_cpu_port(ds, port) ||
+ ds->dsa_port_mask & (1 << port)) {
+ reg |= PORT_PCS_CTRL_FORCE_LINK |
+ PORT_PCS_CTRL_LINK_UP |
+ PORT_PCS_CTRL_DUPLEX_FULL |
+ PORT_PCS_CTRL_FORCE_DUPLEX;
+ if (mv88e6xxx_6065_family(ds))
+ reg |= PORT_PCS_CTRL_100;
+ else
+ reg |= PORT_PCS_CTRL_1000;
+ } else {
+ reg |= PORT_PCS_CTRL_UNFORCED;
+ }
+
+ ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+ PORT_PCS_CTRL, reg);
+ if (ret)
+ goto abort;
+ }
+
+ /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
+ * disable Header mode, enable IGMP/MLD snooping, disable VLAN
+ * tunneling, determine priority by looking at 802.1p and IP
+ * priority fields (IP prio has precedence), and set STP state
+ * to Forwarding.
+ *
+ * If this is the CPU link, use DSA or EDSA tagging depending
+ * on which tagging mode was configured.
+ *
+ * If this is a link to another switch, use DSA tagging mode.
+ *
+ * If this is the upstream port for this switch, enable
+ * forwarding of unknown unicasts and multicasts.
+ */
+ reg = 0;
+ if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
+ mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
+ mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) ||
+ mv88e6xxx_6185_family(ds))
+ reg = PORT_CONTROL_IGMP_MLD_SNOOP |
+ PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP |
+ PORT_CONTROL_STATE_FORWARDING;
+ if (dsa_is_cpu_port(ds, port)) {
+ if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds))
+ reg |= PORT_CONTROL_DSA_TAG;
+ if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
+ mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) {
+ if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
+ reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA;
+ else
+ reg |= PORT_CONTROL_FRAME_MODE_DSA;
+ }
+
+ if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
+ mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
+ mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) ||
+ mv88e6xxx_6185_family(ds)) {
+ if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
+ reg |= PORT_CONTROL_EGRESS_ADD_TAG;
+ }
+ }
+ if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
+ mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
+ mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds)) {
+ if (ds->dsa_port_mask & (1 << port))
+ reg |= PORT_CONTROL_FRAME_MODE_DSA;
+ if (port == dsa_upstream_port(ds))
+ reg |= PORT_CONTROL_FORWARD_UNKNOWN |
+ PORT_CONTROL_FORWARD_UNKNOWN_MC;
+ }
+ if (reg) {
+ ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+ PORT_CONTROL, reg);
+ if (ret)
+ goto abort;
+ }
+
+ /* Port Control 2: don't force a good FCS, set the maximum
+ * frame size to 10240 bytes, don't let the switch add or
+ * strip 802.1q tags, don't discard tagged or untagged frames
+ * on this port, do a destination address lookup on all
+ * received packets as usual, disable ARP mirroring and don't
+ * send a copy of all transmitted/received frames on this port
+ * to the CPU.
+ */
+ reg = 0;
+ if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
+ mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
+ mv88e6xxx_6095_family(ds))
+ reg = PORT_CONTROL_2_MAP_DA;
+
+ if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
+ mv88e6xxx_6165_family(ds))
+ reg |= PORT_CONTROL_2_JUMBO_10240;
+
+ if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) {
+ /* Set the upstream port this port should use */
+ reg |= dsa_upstream_port(ds);
+ /* enable forwarding of unknown multicast addresses to
+ * the upstream port
+ */
+ if (port == dsa_upstream_port(ds))
+ reg |= PORT_CONTROL_2_FORWARD_UNKNOWN;
+ }
+
+ if (reg) {
+ ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+ PORT_CONTROL_2, reg);
+ if (ret)
+ goto abort;
+ }
+
+ /* Port Association Vector: when learning source addresses
+ * of packets, add the address to the address database using
+ * a port bitmap that has only the bit for this port set and
+ * the other bits clear.
+ */
+ ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_ASSOC_VECTOR,
+ 1 << port);
+ if (ret)
+ goto abort;
+
+ /* Egress rate control 2: disable egress rate control. */
+ ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_RATE_CONTROL_2,
+ 0x0000);
+ if (ret)
+ goto abort;
+
+ if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
+ mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) {
+ /* Do not limit the period of time that this port can
+ * be paused for by the remote end or the period of
+ * time that this port can pause the remote end.
+ */
+ ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+ PORT_PAUSE_CTRL, 0x0000);
+ if (ret)
+ goto abort;
+
+ /* Port ATU control: disable limiting the number of
+ * address database entries that this port is allowed
+ * to use.
+ */
+ ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+ PORT_ATU_CONTROL, 0x0000);
+ /* Priority Override: disable DA, SA and VTU priority
+ * override.
+ */
+ ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+ PORT_PRI_OVERRIDE, 0x0000);
+ if (ret)
+ goto abort;
+
+ /* Port Ethertype: use the Ethertype DSA Ethertype
+ * value.
+ */
+ ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+ PORT_ETH_TYPE, ETH_P_EDSA);
+ if (ret)
+ goto abort;
+ /* Tag Remap: use an identity 802.1p prio -> switch
+ * prio mapping.
+ */
+ ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+ PORT_TAG_REGMAP_0123, 0x3210);
+ if (ret)
+ goto abort;
+
+ /* Tag Remap 2: use an identity 802.1p prio -> switch
+ * prio mapping.
+ */
+ ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+ PORT_TAG_REGMAP_4567, 0x7654);
+ if (ret)
+ goto abort;
+ }
+
+ if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
+ mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
+ mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) {
+ /* Rate Control: disable ingress rate limiting. */
+ ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+ PORT_RATE_CONTROL, 0x0001);
+ if (ret)
+ goto abort;
+ }
+
/* Port Control 1: disable trunking, disable sending
* learning messages to this port.
*/
@@ -1281,13 +1605,283 @@ abort:
return ret;
}
+int mv88e6xxx_setup_ports(struct dsa_switch *ds)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ int ret;
+ int i;
+
+ for (i = 0; i < ps->num_ports; i++) {
+ ret = mv88e6xxx_setup_port(ds, i);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static int mv88e6xxx_regs_show(struct seq_file *s, void *p)
+{
+ struct dsa_switch *ds = s->private;
+
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ int reg, port;
+
+ seq_puts(s, " GLOBAL GLOBAL2 ");
+ for (port = 0 ; port < ps->num_ports; port++)
+ seq_printf(s, " %2d ", port);
+ seq_puts(s, "\n");
+
+ for (reg = 0; reg < 32; reg++) {
+ seq_printf(s, "%2x: ", reg);
+ seq_printf(s, " %4x %4x ",
+ mv88e6xxx_reg_read(ds, REG_GLOBAL, reg),
+ mv88e6xxx_reg_read(ds, REG_GLOBAL2, reg));
+
+ for (port = 0 ; port < ps->num_ports; port++)
+ seq_printf(s, "%4x ",
+ mv88e6xxx_reg_read(ds, REG_PORT(port), reg));
+ seq_puts(s, "\n");
+ }
+
+ return 0;
+}
+
+static int mv88e6xxx_regs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mv88e6xxx_regs_show, inode->i_private);
+}
+
+static const struct file_operations mv88e6xxx_regs_fops = {
+ .open = mv88e6xxx_regs_open,
+ .read = seq_read,
+ .llseek = no_llseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static void mv88e6xxx_atu_show_header(struct seq_file *s)
+{
+ seq_puts(s, "DB T/P Vec State Addr\n");
+}
+
+static void mv88e6xxx_atu_show_entry(struct seq_file *s, int dbnum,
+ unsigned char *addr, int data)
+{
+ bool trunk = !!(data & GLOBAL_ATU_DATA_TRUNK);
+ int portvec = ((data & GLOBAL_ATU_DATA_PORT_VECTOR_MASK) >>
+ GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT);
+ int state = data & GLOBAL_ATU_DATA_STATE_MASK;
+
+ seq_printf(s, "%03x %5s %10pb %x %pM\n",
+ dbnum, (trunk ? "Trunk" : "Port"), &portvec, state, addr);
+}
+
+static int mv88e6xxx_atu_show_db(struct seq_file *s, struct dsa_switch *ds,
+ int dbnum)
+{
+ unsigned char bcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ unsigned char addr[6];
+ int ret, data, state;
+
+ ret = __mv88e6xxx_write_addr(ds, bcast);
+ if (ret < 0)
+ return ret;
+
+ do {
+ ret = _mv88e6xxx_atu_cmd(ds, dbnum, GLOBAL_ATU_OP_GET_NEXT_DB);
+ if (ret < 0)
+ return ret;
+ data = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA);
+ if (data < 0)
+ return data;
+
+ state = data & GLOBAL_ATU_DATA_STATE_MASK;
+ if (state == GLOBAL_ATU_DATA_STATE_UNUSED)
+ break;
+ ret = __mv88e6xxx_read_addr(ds, addr);
+ if (ret < 0)
+ return ret;
+ mv88e6xxx_atu_show_entry(s, dbnum, addr, data);
+ } while (state != GLOBAL_ATU_DATA_STATE_UNUSED);
+
+ return 0;
+}
+
+static int mv88e6xxx_atu_show(struct seq_file *s, void *p)
+{
+ struct dsa_switch *ds = s->private;
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ int dbnum;
+
+ mv88e6xxx_atu_show_header(s);
+
+ for (dbnum = 0; dbnum < 255; dbnum++) {
+ mutex_lock(&ps->smi_mutex);
+ mv88e6xxx_atu_show_db(s, ds, dbnum);
+ mutex_unlock(&ps->smi_mutex);
+ }
+
+ return 0;
+}
+
+static int mv88e6xxx_atu_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mv88e6xxx_atu_show, inode->i_private);
+}
+
+static const struct file_operations mv88e6xxx_atu_fops = {
+ .open = mv88e6xxx_atu_open,
+ .read = seq_read,
+ .llseek = no_llseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static void mv88e6xxx_stats_show_header(struct seq_file *s,
+ struct mv88e6xxx_priv_state *ps)
+{
+ int port;
+
+ seq_puts(s, " Statistic ");
+ for (port = 0 ; port < ps->num_ports; port++)
+ seq_printf(s, "Port %2d ", port);
+ seq_puts(s, "\n");
+}
+
+static int mv88e6xxx_stats_show(struct seq_file *s, void *p)
+{
+ struct dsa_switch *ds = s->private;
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ struct mv88e6xxx_hw_stat *stats = mv88e6xxx_hw_stats;
+ int port, stat, max_stats;
+ uint64_t value;
+
+ if (have_sw_in_discards(ds))
+ max_stats = ARRAY_SIZE(mv88e6xxx_hw_stats);
+ else
+ max_stats = ARRAY_SIZE(mv88e6xxx_hw_stats) - 3;
+
+ mv88e6xxx_stats_show_header(s, ps);
+
+ mutex_lock(&ps->smi_mutex);
+
+ for (stat = 0; stat < max_stats; stat++) {
+ seq_printf(s, "%19s: ", stats[stat].string);
+ for (port = 0 ; port < ps->num_ports; port++) {
+ _mv88e6xxx_stats_snapshot(ds, port);
+ value = _mv88e6xxx_get_ethtool_stat(ds, stat, stats,
+ port);
+ seq_printf(s, "%8llu ", value);
+ }
+ seq_puts(s, "\n");
+ }
+ mutex_unlock(&ps->smi_mutex);
+
+ return 0;
+}
+
+static int mv88e6xxx_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mv88e6xxx_stats_show, inode->i_private);
+}
+
+static const struct file_operations mv88e6xxx_stats_fops = {
+ .open = mv88e6xxx_stats_open,
+ .read = seq_read,
+ .llseek = no_llseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int mv88e6xxx_device_map_show(struct seq_file *s, void *p)
+{
+ struct dsa_switch *ds = s->private;
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ int target, ret;
+
+ seq_puts(s, "Target Port\n");
+
+ mutex_lock(&ps->smi_mutex);
+ for (target = 0; target < 32; target++) {
+ ret = _mv88e6xxx_reg_write(
+ ds, REG_GLOBAL2, GLOBAL2_DEVICE_MAPPING,
+ target << GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT);
+ if (ret < 0)
+ goto out;
+ ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL2,
+ GLOBAL2_DEVICE_MAPPING);
+ seq_printf(s, " %2d %2d\n", target,
+ ret & GLOBAL2_DEVICE_MAPPING_PORT_MASK);
+ }
+out:
+ mutex_unlock(&ps->smi_mutex);
+
+ return 0;
+}
+
+static int mv88e6xxx_device_map_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mv88e6xxx_device_map_show, inode->i_private);
+}
+
+static const struct file_operations mv88e6xxx_device_map_fops = {
+ .open = mv88e6xxx_device_map_open,
+ .read = seq_read,
+ .llseek = no_llseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int mv88e6xxx_scratch_show(struct seq_file *s, void *p)
+{
+ struct dsa_switch *ds = s->private;
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ int reg, ret;
+
+ seq_puts(s, "Register Value\n");
+
+ mutex_lock(&ps->smi_mutex);
+ for (reg = 0; reg < 0x80; reg++) {
+ ret = _mv88e6xxx_reg_write(
+ ds, REG_GLOBAL2, GLOBAL2_SCRATCH_MISC,
+ reg << GLOBAL2_SCRATCH_REGISTER_SHIFT);
+ if (ret < 0)
+ goto out;
+
+ ret = _mv88e6xxx_scratch_wait(ds);
+ if (ret < 0)
+ goto out;
+
+ ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL2,
+ GLOBAL2_SCRATCH_MISC);
+ seq_printf(s, " %2x %2x\n", reg,
+ ret & GLOBAL2_SCRATCH_VALUE_MASK);
+ }
+out:
+ mutex_unlock(&ps->smi_mutex);
+
+ return 0;
+}
+
+static int mv88e6xxx_scratch_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mv88e6xxx_scratch_show, inode->i_private);
+}
+
+static const struct file_operations mv88e6xxx_scratch_fops = {
+ .open = mv88e6xxx_scratch_open,
+ .read = seq_read,
+ .llseek = no_llseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
int mv88e6xxx_setup_common(struct dsa_switch *ds)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ char *name;
mutex_init(&ps->smi_mutex);
- mutex_init(&ps->stats_mutex);
- mutex_init(&ps->phy_mutex);
ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0;
@@ -1295,6 +1889,128 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds)
INIT_WORK(&ps->bridge_work, mv88e6xxx_bridge_work);
+ name = kasprintf(GFP_KERNEL, "dsa%d", ds->index);
+ ps->dbgfs = debugfs_create_dir(name, NULL);
+ kfree(name);
+
+ debugfs_create_file("regs", S_IRUGO, ps->dbgfs, ds,
+ &mv88e6xxx_regs_fops);
+
+ debugfs_create_file("atu", S_IRUGO, ps->dbgfs, ds,
+ &mv88e6xxx_atu_fops);
+
+ debugfs_create_file("stats", S_IRUGO, ps->dbgfs, ds,
+ &mv88e6xxx_stats_fops);
+
+ debugfs_create_file("device_map", S_IRUGO, ps->dbgfs, ds,
+ &mv88e6xxx_device_map_fops);
+
+ debugfs_create_file("scratch", S_IRUGO, ps->dbgfs, ds,
+ &mv88e6xxx_scratch_fops);
+ return 0;
+}
+
+int mv88e6xxx_setup_global(struct dsa_switch *ds)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ int i;
+
+ /* Set the default address aging time to 5 minutes, and
+ * enable address learn messages to be sent to all message
+ * ports.
+ */
+ REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
+ 0x0140 | GLOBAL_ATU_CONTROL_LEARN2ALL);
+
+ /* Configure the IP ToS mapping registers. */
+ REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_0, 0x0000);
+ REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_1, 0x0000);
+ REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_2, 0x5555);
+ REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_3, 0x5555);
+ REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_4, 0xaaaa);
+ REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_5, 0xaaaa);
+ REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_6, 0xffff);
+ REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_7, 0xffff);
+
+ /* Configure the IEEE 802.1p priority mapping register. */
+ REG_WRITE(REG_GLOBAL, GLOBAL_IEEE_PRI, 0xfa41);
+
+ /* Send all frames with destination addresses matching
+ * 01:80:c2:00:00:0x to the CPU port.
+ */
+ REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_0X, 0xffff);
+
+ /* Ignore removed tag data on doubly tagged packets, disable
+ * flow control messages, force flow control priority to the
+ * highest, and send all special multicast frames to the CPU
+ * port at the highest priority.
+ */
+ REG_WRITE(REG_GLOBAL2, GLOBAL2_SWITCH_MGMT,
+ 0x7 | GLOBAL2_SWITCH_MGMT_RSVD2CPU | 0x70 |
+ GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI);
+
+ /* Program the DSA routing table. */
+ for (i = 0; i < 32; i++) {
+ int nexthop = 0x1f;
+
+ if (ds->pd->rtable &&
+ i != ds->index && i < ds->dst->pd->nr_chips)
+ nexthop = ds->pd->rtable[i] & 0x1f;
+
+ REG_WRITE(REG_GLOBAL2, GLOBAL2_DEVICE_MAPPING,
+ GLOBAL2_DEVICE_MAPPING_UPDATE |
+ (i << GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT) |
+ nexthop);
+ }
+
+ /* Clear all trunk masks. */
+ for (i = 0; i < 8; i++)
+ REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MASK,
+ 0x8000 | (i << GLOBAL2_TRUNK_MASK_NUM_SHIFT) |
+ ((1 << ps->num_ports) - 1));
+
+ /* Clear all trunk mappings. */
+ for (i = 0; i < 16; i++)
+ REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MAPPING,
+ GLOBAL2_TRUNK_MAPPING_UPDATE |
+ (i << GLOBAL2_TRUNK_MAPPING_ID_SHIFT));
+
+ if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
+ mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) {
+ /* Send all frames with destination addresses matching
+ * 01:80:c2:00:00:2x to the CPU port.
+ */
+ REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_2X, 0xffff);
+
+ /* Initialise cross-chip port VLAN table to reset
+ * defaults.
+ */
+ REG_WRITE(REG_GLOBAL2, GLOBAL2_PVT_ADDR, 0x9000);
+
+ /* Clear the priority override table. */
+ for (i = 0; i < 16; i++)
+ REG_WRITE(REG_GLOBAL2, GLOBAL2_PRIO_OVERRIDE,
+ 0x8000 | (i << 8));
+ }
+
+ if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
+ mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
+ mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) {
+ /* Disable ingress rate limiting by resetting all
+ * ingress rate limit registers to their initial
+ * state.
+ */
+ for (i = 0; i < ps->num_ports; i++)
+ REG_WRITE(REG_GLOBAL2, GLOBAL2_INGRESS_OP,
+ 0x9000 | (i << 8));
+ }
+
+ /* Clear the statistics counters for all ports */
+ REG_WRITE(REG_GLOBAL, GLOBAL_STATS_OP, GLOBAL_STATS_OP_FLUSH_ALL);
+
+ /* Wait for the flush to complete. */
+ _mv88e6xxx_stats_wait(ds);
+
return 0;
}
@@ -1343,14 +2059,14 @@ int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg)
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int ret;
- mutex_lock(&ps->phy_mutex);
+ mutex_lock(&ps->smi_mutex);
ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
if (ret < 0)
goto error;
ret = _mv88e6xxx_phy_read_indirect(ds, port, reg);
error:
_mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
- mutex_unlock(&ps->phy_mutex);
+ mutex_unlock(&ps->smi_mutex);
return ret;
}
@@ -1360,7 +2076,7 @@ int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page,
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int ret;
- mutex_lock(&ps->phy_mutex);
+ mutex_lock(&ps->smi_mutex);
ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
if (ret < 0)
goto error;
@@ -1368,7 +2084,7 @@ int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page,
ret = _mv88e6xxx_phy_write_indirect(ds, port, reg, val);
error:
_mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
- mutex_unlock(&ps->phy_mutex);
+ mutex_unlock(&ps->smi_mutex);
return ret;
}
@@ -1391,9 +2107,9 @@ mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum)
if (addr < 0)
return addr;
- mutex_lock(&ps->phy_mutex);
+ mutex_lock(&ps->smi_mutex);
ret = _mv88e6xxx_phy_read(ds, addr, regnum);
- mutex_unlock(&ps->phy_mutex);
+ mutex_unlock(&ps->smi_mutex);
return ret;
}
@@ -1407,9 +2123,9 @@ mv88e6xxx_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
if (addr < 0)
return addr;
- mutex_lock(&ps->phy_mutex);
+ mutex_lock(&ps->smi_mutex);
ret = _mv88e6xxx_phy_write(ds, addr, regnum, val);
- mutex_unlock(&ps->phy_mutex);
+ mutex_unlock(&ps->smi_mutex);
return ret;
}
@@ -1423,9 +2139,9 @@ mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int port, int regnum)
if (addr < 0)
return addr;
- mutex_lock(&ps->phy_mutex);
+ mutex_lock(&ps->smi_mutex);
ret = _mv88e6xxx_phy_read_indirect(ds, addr, regnum);
- mutex_unlock(&ps->phy_mutex);
+ mutex_unlock(&ps->smi_mutex);
return ret;
}
@@ -1440,9 +2156,9 @@ mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum,
if (addr < 0)
return addr;
- mutex_lock(&ps->phy_mutex);
+ mutex_lock(&ps->smi_mutex);
ret = _mv88e6xxx_phy_write_indirect(ds, addr, regnum, val);
- mutex_unlock(&ps->phy_mutex);
+ mutex_unlock(&ps->smi_mutex);
return ret;
}
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index e045154f3364..a650b2656de9 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -11,6 +11,10 @@
#ifndef __MV88E6XXX_H
#define __MV88E6XXX_H
+#ifndef UINT64_MAX
+#define UINT64_MAX (u64)(~((u64)0))
+#endif
+
#define SMI_CMD 0x00
#define SMI_CMD_BUSY BIT(15)
#define SMI_CMD_CLAUSE_22 BIT(12)
@@ -40,9 +44,31 @@
#define PORT_STATUS_TX_PAUSED BIT(5)
#define PORT_STATUS_FLOW_CTRL BIT(4)
#define PORT_PCS_CTRL 0x01
+#define PORT_PCS_CTRL_FC BIT(7)
+#define PORT_PCS_CTRL_FORCE_FC BIT(6)
+#define PORT_PCS_CTRL_LINK_UP BIT(5)
+#define PORT_PCS_CTRL_FORCE_LINK BIT(4)
+#define PORT_PCS_CTRL_DUPLEX_FULL BIT(3)
+#define PORT_PCS_CTRL_FORCE_DUPLEX BIT(2)
+#define PORT_PCS_CTRL_10 0x00
+#define PORT_PCS_CTRL_100 0x01
+#define PORT_PCS_CTRL_1000 0x02
+#define PORT_PCS_CTRL_UNFORCED 0x03
+#define PORT_PAUSE_CTRL 0x02
#define PORT_SWITCH_ID 0x03
+#define PORT_SWITCH_ID_6031 0x0310
+#define PORT_SWITCH_ID_6035 0x0350
+#define PORT_SWITCH_ID_6046 0x0480
+#define PORT_SWITCH_ID_6061 0x0610
+#define PORT_SWITCH_ID_6065 0x0650
#define PORT_SWITCH_ID_6085 0x04a0
+#define PORT_SWITCH_ID_6092 0x0970
#define PORT_SWITCH_ID_6095 0x0950
+#define PORT_SWITCH_ID_6096 0x0980
+#define PORT_SWITCH_ID_6097 0x0990
+#define PORT_SWITCH_ID_6108 0x1070
+#define PORT_SWITCH_ID_6121 0x1040
+#define PORT_SWITCH_ID_6122 0x1050
#define PORT_SWITCH_ID_6123 0x1210
#define PORT_SWITCH_ID_6123_A1 0x1212
#define PORT_SWITCH_ID_6123_A2 0x1213
@@ -58,13 +84,38 @@
#define PORT_SWITCH_ID_6165_A2 0x1653
#define PORT_SWITCH_ID_6171 0x1710
#define PORT_SWITCH_ID_6172 0x1720
+#define PORT_SWITCH_ID_6175 0x1750
#define PORT_SWITCH_ID_6176 0x1760
#define PORT_SWITCH_ID_6182 0x1a60
#define PORT_SWITCH_ID_6185 0x1a70
+#define PORT_SWITCH_ID_6240 0x2400
+#define PORT_SWITCH_ID_6320 0x1250
+#define PORT_SWITCH_ID_6350 0x3710
+#define PORT_SWITCH_ID_6351 0x3750
#define PORT_SWITCH_ID_6352 0x3520
#define PORT_SWITCH_ID_6352_A0 0x3521
#define PORT_SWITCH_ID_6352_A1 0x3522
#define PORT_CONTROL 0x04
+#define PORT_CONTROL_USE_CORE_TAG BIT(15)
+#define PORT_CONTROL_DROP_ON_LOCK BIT(14)
+#define PORT_CONTROL_EGRESS_UNMODIFIED (0x0 << 12)
+#define PORT_CONTROL_EGRESS_UNTAGGED (0x1 << 12)
+#define PORT_CONTROL_EGRESS_TAGGED (0x2 << 12)
+#define PORT_CONTROL_EGRESS_ADD_TAG (0x3 << 12)
+#define PORT_CONTROL_HEADER BIT(11)
+#define PORT_CONTROL_IGMP_MLD_SNOOP BIT(10)
+#define PORT_CONTROL_DOUBLE_TAG BIT(9)
+#define PORT_CONTROL_FRAME_MODE_NORMAL (0x0 << 8)
+#define PORT_CONTROL_FRAME_MODE_DSA (0x1 << 8)
+#define PORT_CONTROL_FRAME_MODE_PROVIDER (0x2 << 8)
+#define PORT_CONTROL_FRAME_ETHER_TYPE_DSA (0x3 << 8)
+#define PORT_CONTROL_DSA_TAG BIT(8)
+#define PORT_CONTROL_VLAN_TUNNEL BIT(7)
+#define PORT_CONTROL_TAG_IF_BOTH BIT(6)
+#define PORT_CONTROL_USE_IP BIT(5)
+#define PORT_CONTROL_USE_TAG BIT(4)
+#define PORT_CONTROL_FORWARD_UNKNOWN_MC BIT(3)
+#define PORT_CONTROL_FORWARD_UNKNOWN BIT(2)
#define PORT_CONTROL_STATE_MASK 0x03
#define PORT_CONTROL_STATE_DISABLED 0x00
#define PORT_CONTROL_STATE_BLOCKING 0x01
@@ -74,15 +125,32 @@
#define PORT_BASE_VLAN 0x06
#define PORT_DEFAULT_VLAN 0x07
#define PORT_CONTROL_2 0x08
+#define PORT_CONTROL_2_IGNORE_FCS BIT(15)
+#define PORT_CONTROL_2_VTU_PRI_OVERRIDE BIT(14)
+#define PORT_CONTROL_2_SA_PRIO_OVERRIDE BIT(13)
+#define PORT_CONTROL_2_DA_PRIO_OVERRIDE BIT(12)
+#define PORT_CONTROL_2_JUMBO_1522 (0x00 << 12)
+#define PORT_CONTROL_2_JUMBO_2048 (0x01 << 12)
+#define PORT_CONTROL_2_JUMBO_10240 (0x02 << 12)
+#define PORT_CONTROL_2_DISCARD_TAGGED BIT(9)
+#define PORT_CONTROL_2_DISCARD_UNTAGGED BIT(8)
+#define PORT_CONTROL_2_MAP_DA BIT(7)
+#define PORT_CONTROL_2_DEFAULT_FORWARD BIT(6)
+#define PORT_CONTROL_2_FORWARD_UNKNOWN BIT(6)
+#define PORT_CONTROL_2_EGRESS_MONITOR BIT(5)
+#define PORT_CONTROL_2_INGRESS_MONITOR BIT(4)
#define PORT_RATE_CONTROL 0x09
#define PORT_RATE_CONTROL_2 0x0a
#define PORT_ASSOC_VECTOR 0x0b
+#define PORT_ATU_CONTROL 0x0c
+#define PORT_PRI_OVERRIDE 0x0d
+#define PORT_ETH_TYPE 0x0f
#define PORT_IN_DISCARD_LO 0x10
#define PORT_IN_DISCARD_HI 0x11
#define PORT_IN_FILTERED 0x12
#define PORT_OUT_FILTERED 0x13
-#define PORT_TAG_REGMAP_0123 0x19
-#define PORT_TAG_REGMAP_4567 0x1a
+#define PORT_TAG_REGMAP_0123 0x18
+#define PORT_TAG_REGMAP_4567 0x19
#define REG_GLOBAL 0x1b
#define GLOBAL_STATUS 0x00
@@ -102,7 +170,7 @@
#define GLOBAL_CONTROL_DISCARD_EXCESS BIT(13) /* 6352 */
#define GLOBAL_CONTROL_SCHED_PRIO BIT(11) /* 6152 */
#define GLOBAL_CONTROL_MAX_FRAME_1632 BIT(10) /* 6152 */
-#define GLOBAL_CONTROL_RELOAD_EEPROM BIT(9) /* 6152 */
+#define GLOBAL_CONTROL_RELOAD_EEPROM BIT(9) /* 6152 */
#define GLOBAL_CONTROL_DEVICE_EN BIT(7)
#define GLOBAL_CONTROL_STATS_DONE_EN BIT(6)
#define GLOBAL_CONTROL_VTU_PROBLEM_EN BIT(5)
@@ -117,6 +185,7 @@
#define GLOBAL_VTU_DATA_4_7 0x08
#define GLOBAL_VTU_DATA_8_11 0x09
#define GLOBAL_ATU_CONTROL 0x0a
+#define GLOBAL_ATU_CONTROL_LEARN2ALL BIT(3)
#define GLOBAL_ATU_OP 0x0b
#define GLOBAL_ATU_OP_BUSY BIT(15)
#define GLOBAL_ATU_OP_NOP (0 << 12)
@@ -128,6 +197,9 @@
#define GLOBAL_ATU_OP_FLUSH_NON_STATIC_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY)
#define GLOBAL_ATU_OP_GET_CLR_VIOLATION ((7 << 12) | GLOBAL_ATU_OP_BUSY)
#define GLOBAL_ATU_DATA 0x0c
+#define GLOBAL_ATU_DATA_TRUNK BIT(15)
+#define GLOBAL_ATU_DATA_PORT_VECTOR_MASK 0x3ff0
+#define GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT 4
#define GLOBAL_ATU_DATA_STATE_MASK 0x0f
#define GLOBAL_ATU_DATA_STATE_UNUSED 0x00
#define GLOBAL_ATU_DATA_STATE_UC_MGMT 0x0d
@@ -151,7 +223,15 @@
#define GLOBAL_IEEE_PRI 0x18
#define GLOBAL_CORE_TAG_TYPE 0x19
#define GLOBAL_MONITOR_CONTROL 0x1a
+#define GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT 12
+#define GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT 8
+#define GLOBAL_MONITOR_CONTROL_ARP_SHIFT 4
+#define GLOBAL_MONITOR_CONTROL_MIRROR_SHIFT 0
+#define GLOBAL_MONITOR_CONTROL_ARP_DISABLED (0xf0)
#define GLOBAL_CONTROL_2 0x1c
+#define GLOBAL_CONTROL_2_NO_CASCADE 0xe000
+#define GLOBAL_CONTROL_2_MULTIPLE_CASCADE 0xf000
+
#define GLOBAL_STATS_OP 0x1d
#define GLOBAL_STATS_OP_BUSY BIT(15)
#define GLOBAL_STATS_OP_NOP (0 << 12)
@@ -172,9 +252,21 @@
#define GLOBAL2_MGMT_EN_0X 0x03
#define GLOBAL2_FLOW_CONTROL 0x04
#define GLOBAL2_SWITCH_MGMT 0x05
+#define GLOBAL2_SWITCH_MGMT_USE_DOUBLE_TAG_DATA BIT(15)
+#define GLOBAL2_SWITCH_MGMT_PREVENT_LOOPS BIT(14)
+#define GLOBAL2_SWITCH_MGMT_FLOW_CONTROL_MSG BIT(13)
+#define GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI BIT(7)
+#define GLOBAL2_SWITCH_MGMT_RSVD2CPU BIT(3)
#define GLOBAL2_DEVICE_MAPPING 0x06
+#define GLOBAL2_DEVICE_MAPPING_UPDATE BIT(15)
+#define GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT 8
+#define GLOBAL2_DEVICE_MAPPING_PORT_MASK 0x0f
#define GLOBAL2_TRUNK_MASK 0x07
+#define GLOBAL2_TRUNK_MASK_UPDATE BIT(15)
+#define GLOBAL2_TRUNK_MASK_NUM_SHIFT 12
#define GLOBAL2_TRUNK_MAPPING 0x08
+#define GLOBAL2_TRUNK_MAPPING_UPDATE BIT(15)
+#define GLOBAL2_TRUNK_MAPPING_ID_SHIFT 11
#define GLOBAL2_INGRESS_OP 0x09
#define GLOBAL2_INGRESS_DATA 0x0a
#define GLOBAL2_PVT_ADDR 0x0b
@@ -183,6 +275,10 @@
#define GLOBAL2_SWITCH_MAC_BUSY BIT(15)
#define GLOBAL2_ATU_STATS 0x0e
#define GLOBAL2_PRIO_OVERRIDE 0x0f
+#define GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP BIT(7)
+#define GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT 4
+#define GLOBAL2_PRIO_OVERRIDE_FORCE_ARP BIT(3)
+#define GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT 0
#define GLOBAL2_EEPROM_OP 0x14
#define GLOBAL2_EEPROM_OP_BUSY BIT(15)
#define GLOBAL2_EEPROM_OP_LOAD BIT(11)
@@ -201,6 +297,9 @@
#define GLOBAL2_SMI_OP_45_READ_DATA ((2 << 10) | GLOBAL2_SMI_OP_BUSY)
#define GLOBAL2_SMI_DATA 0x19
#define GLOBAL2_SCRATCH_MISC 0x1a
+#define GLOBAL2_SCRATCH_BUSY BIT(15)
+#define GLOBAL2_SCRATCH_REGISTER_SHIFT 8
+#define GLOBAL2_SCRATCH_VALUE_MASK 0xff
#define GLOBAL2_WDOG_CONTROL 0x1b
#define GLOBAL2_QOS_WEIGHT 0x1c
#define GLOBAL2_MISC 0x1d
@@ -251,6 +350,8 @@ struct mv88e6xxx_priv_state {
u8 port_state[DSA_MAX_PORTS];
struct work_struct bridge_work;
+
+ struct dentry *dbgfs;
};
struct mv88e6xxx_hw_stat {
@@ -260,14 +361,14 @@ struct mv88e6xxx_hw_stat {
};
int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active);
-int mv88e6xxx_setup_port_common(struct dsa_switch *ds, int port);
+int mv88e6xxx_setup_ports(struct dsa_switch *ds);
int mv88e6xxx_setup_common(struct dsa_switch *ds);
+int mv88e6xxx_setup_global(struct dsa_switch *ds);
int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg);
int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg);
int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
int reg, u16 val);
int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val);
-int mv88e6xxx_config_prio(struct dsa_switch *ds);
int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr);
int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr);
int mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum);
@@ -289,7 +390,6 @@ int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port);
void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
struct ethtool_regs *regs, void *_p);
int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp);
-int mv88e6xxx_phy_wait(struct dsa_switch *ds);
int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds);
int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds);
int mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, int regnum);
diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/Kconfig
index afaab4b2333f..5b7658bcf020 100644
--- a/drivers/net/ethernet/3com/Kconfig
+++ b/drivers/net/ethernet/3com/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_3COM
default y
depends on ISA || EISA || PCI || PCMCIA
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
@@ -23,8 +21,7 @@ config EL3
depends on (ISA || EISA)
---help---
If you have a network (Ethernet) card belonging to the 3Com
- EtherLinkIII series, say Y and read the Ethernet-HOWTO, available
- from <http://www.tldp.org/docs.html#howto>.
+ EtherLinkIII series, say Y here.
If your card is not working you may need to use the DOS
setup disk to disable Plug & Play mode, and to select the default
@@ -38,8 +35,7 @@ config 3C515
depends on ISA && ISA_DMA_API
---help---
If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet
- network card, say Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ network card, say Y here.
To compile this driver as a module, choose M here. The module
will be called 3c515.
@@ -78,9 +74,7 @@ config VORTEX
"Tornado" (3c905) PCI
"Hurricane" (3c555/3cSOHO) PCI
- If you have such a card, say Y and read the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>. More
- specific information is in
+ If you have such a card, say Y here. More specific information is in
<file:Documentation/networking/vortex.txt> and in the comments at
the beginning of <file:drivers/net/ethernet/3com/3c59x.c>.
@@ -97,9 +91,7 @@ config TYPHOON
3CR990SVR, 3CR990SVR95, 3CR990SVR97, 3CR990-FX-95 Server,
3CR990-FX-97 Server, 3C990B-TX-M, 3C990BSVR
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card of this type, say Y here.
To compile this driver as a module, choose M here. The module
will be called typhoon.
diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
index 2d89bd00de61..edf72258ab1d 100644
--- a/drivers/net/ethernet/8390/Kconfig
+++ b/drivers/net/ethernet/8390/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_8390
default y
depends on NET_VENDOR_NATSEMI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
@@ -71,9 +69,7 @@ config MAC8390
select CRC32
---help---
If you want to include a driver to support Nubus or LC-PDS
- Ethernet cards using an NS8390 chipset or its equivalent, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ Ethernet cards using an NS8390 chipset or its equivalent, say Y.
config MCF8390
tristate "ColdFire NS8390 based Ethernet support"
@@ -95,10 +91,9 @@ config NE2000
ATARI_ETHERNEC)
select CRC32
---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Many Ethernet cards
- without a specific driver are compatible with NE2000.
+ If you have a network (Ethernet) card of this type, say Y here.
+ Many Ethernet cards without a specific driver are compatible with
+ the NE2000.
If you have a PCI NE2000 card however, say N here and Y to "PCI
NE2000 and clone support" below.
@@ -114,8 +109,7 @@ config NE2K_PCI
This driver is for NE2000 compatible PCI cards. It will not work
with ISA NE2000 cards (they have their own driver, "NE2000/NE1000
support" below). If you have a PCI NE2000 network (Ethernet) card,
- say Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ say Y here.
This driver also works for the following NE2000 clone cards:
RealTek RTL-8029 Winbond 89C940 Compex RL2000 KTI ET32P2
@@ -164,9 +158,7 @@ config ULTRA
depends on ISA
select CRC32
---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card of this type, say Y here.
Important: There have been many reports that, with some motherboards
mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible,
@@ -183,9 +175,7 @@ config WD80x3
depends on ISA
select CRC32
---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card of this type, say Y here.
To compile this driver as a module, choose M here. The module
will be called wd.
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index eadcb053807e..f3bb1784066b 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -34,6 +34,7 @@ source "drivers/net/ethernet/adi/Kconfig"
source "drivers/net/ethernet/broadcom/Kconfig"
source "drivers/net/ethernet/brocade/Kconfig"
source "drivers/net/ethernet/calxeda/Kconfig"
+source "drivers/net/ethernet/cavium/Kconfig"
source "drivers/net/ethernet/chelsio/Kconfig"
source "drivers/net/ethernet/cirrus/Kconfig"
source "drivers/net/ethernet/cisco/Kconfig"
@@ -66,6 +67,7 @@ config DNET
source "drivers/net/ethernet/dec/Kconfig"
source "drivers/net/ethernet/dlink/Kconfig"
source "drivers/net/ethernet/emulex/Kconfig"
+source "drivers/net/ethernet/ezchip/Kconfig"
source "drivers/net/ethernet/neterion/Kconfig"
source "drivers/net/ethernet/faraday/Kconfig"
source "drivers/net/ethernet/freescale/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 1367afcd0a8b..c51014b0464f 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_NET_BFIN) += adi/
obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/
obj-$(CONFIG_NET_VENDOR_BROCADE) += brocade/
obj-$(CONFIG_NET_CALXEDA_XGMAC) += calxeda/
+obj-$(CONFIG_NET_VENDOR_CAVIUM) += cavium/
obj-$(CONFIG_NET_VENDOR_CHELSIO) += chelsio/
obj-$(CONFIG_NET_VENDOR_CIRRUS) += cirrus/
obj-$(CONFIG_NET_VENDOR_CISCO) += cisco/
@@ -29,6 +30,7 @@ obj-$(CONFIG_DNET) += dnet.o
obj-$(CONFIG_NET_VENDOR_DEC) += dec/
obj-$(CONFIG_NET_VENDOR_DLINK) += dlink/
obj-$(CONFIG_NET_VENDOR_EMULEX) += emulex/
+obj-$(CONFIG_NET_VENDOR_EZCHIP) += ezchip/
obj-$(CONFIG_NET_VENDOR_EXAR) += neterion/
obj-$(CONFIG_NET_VENDOR_FARADAY) += faraday/
obj-$(CONFIG_NET_VENDOR_FREESCALE) += freescale/
diff --git a/drivers/net/ethernet/adaptec/Kconfig b/drivers/net/ethernet/adaptec/Kconfig
index 5c804bbe3dab..822cffb4174c 100644
--- a/drivers/net/ethernet/adaptec/Kconfig
+++ b/drivers/net/ethernet/adaptec/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_ADAPTEC
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig
index c9cd3592ab73..6b94ba610399 100644
--- a/drivers/net/ethernet/adi/Kconfig
+++ b/drivers/net/ethernet/adi/Kconfig
@@ -7,8 +7,6 @@ config NET_BFIN
depends on BF516 || BF518 || BF526 || BF527 || BF536 || BF537
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
- Make sure you know the name of your card. Read the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
If unsure, say Y.
diff --git a/drivers/net/ethernet/agere/Kconfig b/drivers/net/ethernet/agere/Kconfig
index 63e805de619e..b6fe9200355a 100644
--- a/drivers/net/ethernet/agere/Kconfig
+++ b/drivers/net/ethernet/agere/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_AGERE
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/allwinner/Kconfig b/drivers/net/ethernet/allwinner/Kconfig
index d8d95d4cd45a..47da7e7a5b6a 100644
--- a/drivers/net/ethernet/allwinner/Kconfig
+++ b/drivers/net/ethernet/allwinner/Kconfig
@@ -9,8 +9,7 @@ config NET_VENDOR_ALLWINNER
depends on ARCH_SUNXI
---help---
If you have a network (Ethernet) card belonging to this
- class, say Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ class, say Y here.
Note that the answer to this question doesn't directly
affect the kernel: saying N will just cause the configurator
diff --git a/drivers/net/ethernet/alteon/Kconfig b/drivers/net/ethernet/alteon/Kconfig
index 799a85282070..e06ccab354b5 100644
--- a/drivers/net/ethernet/alteon/Kconfig
+++ b/drivers/net/ethernet/alteon/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_ALTEON
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig
index 426916036151..afc62ea804fc 100644
--- a/drivers/net/ethernet/amd/Kconfig
+++ b/drivers/net/ethernet/amd/Kconfig
@@ -37,8 +37,7 @@ config AMD8111_ETH
select MII
---help---
If you have an AMD 8111-based PCI LANCE ethernet card,
- answer Y here and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ answer Y here.
To compile this driver as a module, choose M here. The module
will be called amd8111e.
@@ -47,10 +46,8 @@ config LANCE
tristate "AMD LANCE and PCnet (AT1500 and NE2100) support"
depends on ISA && ISA_DMA_API && !ARM
---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Some LinkSys cards are
- of this type.
+ If you have a network (Ethernet) card of this type, say Y here.
+ Some LinkSys cards are of this type.
To compile this driver as a module, choose M here: the module
will be called lance. This is recommended.
@@ -62,8 +59,7 @@ config PCNET32
select MII
---help---
If you have a PCnet32 or PCnetPCI based network (Ethernet) card,
- answer Y here and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ answer Y here.
To compile this driver as a module, choose M here. The module
will be called pcnet32.
@@ -144,9 +140,7 @@ config NI65
tristate "NI6510 support"
depends on ISA && ISA_DMA_API && !ARM
---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card of this type, say Y here.
To compile this driver as a module, choose M here. The module
will be called ni65.
@@ -179,10 +173,8 @@ config SUNLANCE
config AMD_XGBE
tristate "AMD 10GbE Ethernet driver"
- depends on (OF_NET || ACPI) && HAS_IOMEM && HAS_DMA
+ depends on ((OF_NET && OF_ADDRESS) || ACPI) && HAS_IOMEM && HAS_DMA
depends on ARM64 || COMPILE_TEST
- select PHYLIB
- select AMD_XGBE_PHY
select BITREVERSE
select CRC32
select PTP_1588_CLOCK
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
index 34c28aac767f..b6fa89102526 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
@@ -857,6 +857,48 @@
*/
#define PCS_MMD_SELECT 0xff
+/* SerDes integration register offsets */
+#define SIR0_KR_RT_1 0x002c
+#define SIR0_STATUS 0x0040
+#define SIR1_SPEED 0x0000
+
+/* SerDes integration register entry bit positions and sizes */
+#define SIR0_KR_RT_1_RESET_INDEX 11
+#define SIR0_KR_RT_1_RESET_WIDTH 1
+#define SIR0_STATUS_RX_READY_INDEX 0
+#define SIR0_STATUS_RX_READY_WIDTH 1
+#define SIR0_STATUS_TX_READY_INDEX 8
+#define SIR0_STATUS_TX_READY_WIDTH 1
+#define SIR1_SPEED_CDR_RATE_INDEX 12
+#define SIR1_SPEED_CDR_RATE_WIDTH 4
+#define SIR1_SPEED_DATARATE_INDEX 4
+#define SIR1_SPEED_DATARATE_WIDTH 2
+#define SIR1_SPEED_PLLSEL_INDEX 3
+#define SIR1_SPEED_PLLSEL_WIDTH 1
+#define SIR1_SPEED_RATECHANGE_INDEX 6
+#define SIR1_SPEED_RATECHANGE_WIDTH 1
+#define SIR1_SPEED_TXAMP_INDEX 8
+#define SIR1_SPEED_TXAMP_WIDTH 4
+#define SIR1_SPEED_WORDMODE_INDEX 0
+#define SIR1_SPEED_WORDMODE_WIDTH 3
+
+/* SerDes RxTx register offsets */
+#define RXTX_REG6 0x0018
+#define RXTX_REG20 0x0050
+#define RXTX_REG22 0x0058
+#define RXTX_REG114 0x01c8
+#define RXTX_REG129 0x0204
+
+/* SerDes RxTx register entry bit positions and sizes */
+#define RXTX_REG6_RESETB_RXD_INDEX 8
+#define RXTX_REG6_RESETB_RXD_WIDTH 1
+#define RXTX_REG20_BLWC_ENA_INDEX 2
+#define RXTX_REG20_BLWC_ENA_WIDTH 1
+#define RXTX_REG114_PQ_REG_INDEX 9
+#define RXTX_REG114_PQ_REG_WIDTH 7
+#define RXTX_REG129_RXDFE_CONFIG_INDEX 14
+#define RXTX_REG129_RXDFE_CONFIG_WIDTH 2
+
/* Descriptor/Packet entry bit positions and sizes */
#define RX_PACKET_ERRORS_CRC_INDEX 2
#define RX_PACKET_ERRORS_CRC_WIDTH 1
@@ -973,10 +1015,47 @@
#define TX_NORMAL_DESC2_VLAN_INSERT 0x2
/* MDIO undefined or vendor specific registers */
+#ifndef MDIO_PMA_10GBR_PMD_CTRL
+#define MDIO_PMA_10GBR_PMD_CTRL 0x0096
+#endif
+
+#ifndef MDIO_PMA_10GBR_FECCTRL
+#define MDIO_PMA_10GBR_FECCTRL 0x00ab
+#endif
+
+#ifndef MDIO_AN_XNP
+#define MDIO_AN_XNP 0x0016
+#endif
+
+#ifndef MDIO_AN_LPX
+#define MDIO_AN_LPX 0x0019
+#endif
+
#ifndef MDIO_AN_COMP_STAT
#define MDIO_AN_COMP_STAT 0x0030
#endif
+#ifndef MDIO_AN_INTMASK
+#define MDIO_AN_INTMASK 0x8001
+#endif
+
+#ifndef MDIO_AN_INT
+#define MDIO_AN_INT 0x8002
+#endif
+
+#ifndef MDIO_CTRL1_SPEED1G
+#define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
+#endif
+
+/* MDIO mask values */
+#define XGBE_XNP_MCF_NULL_MESSAGE 0x001
+#define XGBE_XNP_ACK_PROCESSED BIT(12)
+#define XGBE_XNP_MP_FORMATTED BIT(13)
+#define XGBE_XNP_NP_EXCHANGE BIT(15)
+
+#define XGBE_KR_TRAINING_START BIT(0)
+#define XGBE_KR_TRAINING_ENABLE BIT(1)
+
/* Bit setting and getting macros
* The get macro will extract the current bit field value from within
* the variable
@@ -1119,6 +1198,82 @@ do { \
ioread32((_pdata)->xpcs_regs + (_off))
/* Macros for building, reading or writing register values or bits
+ * within the register values of SerDes integration registers.
+ */
+#define XSIR_GET_BITS(_var, _prefix, _field) \
+ GET_BITS((_var), \
+ _prefix##_##_field##_INDEX, \
+ _prefix##_##_field##_WIDTH)
+
+#define XSIR_SET_BITS(_var, _prefix, _field, _val) \
+ SET_BITS((_var), \
+ _prefix##_##_field##_INDEX, \
+ _prefix##_##_field##_WIDTH, (_val))
+
+#define XSIR0_IOREAD(_pdata, _reg) \
+ ioread16((_pdata)->sir0_regs + _reg)
+
+#define XSIR0_IOREAD_BITS(_pdata, _reg, _field) \
+ GET_BITS(XSIR0_IOREAD((_pdata), _reg), \
+ _reg##_##_field##_INDEX, \
+ _reg##_##_field##_WIDTH)
+
+#define XSIR0_IOWRITE(_pdata, _reg, _val) \
+ iowrite16((_val), (_pdata)->sir0_regs + _reg)
+
+#define XSIR0_IOWRITE_BITS(_pdata, _reg, _field, _val) \
+do { \
+ u16 reg_val = XSIR0_IOREAD((_pdata), _reg); \
+ SET_BITS(reg_val, \
+ _reg##_##_field##_INDEX, \
+ _reg##_##_field##_WIDTH, (_val)); \
+ XSIR0_IOWRITE((_pdata), _reg, reg_val); \
+} while (0)
+
+#define XSIR1_IOREAD(_pdata, _reg) \
+ ioread16((_pdata)->sir1_regs + _reg)
+
+#define XSIR1_IOREAD_BITS(_pdata, _reg, _field) \
+ GET_BITS(XSIR1_IOREAD((_pdata), _reg), \
+ _reg##_##_field##_INDEX, \
+ _reg##_##_field##_WIDTH)
+
+#define XSIR1_IOWRITE(_pdata, _reg, _val) \
+ iowrite16((_val), (_pdata)->sir1_regs + _reg)
+
+#define XSIR1_IOWRITE_BITS(_pdata, _reg, _field, _val) \
+do { \
+ u16 reg_val = XSIR1_IOREAD((_pdata), _reg); \
+ SET_BITS(reg_val, \
+ _reg##_##_field##_INDEX, \
+ _reg##_##_field##_WIDTH, (_val)); \
+ XSIR1_IOWRITE((_pdata), _reg, reg_val); \
+} while (0)
+
+/* Macros for building, reading or writing register values or bits
+ * within the register values of SerDes RxTx registers.
+ */
+#define XRXTX_IOREAD(_pdata, _reg) \
+ ioread16((_pdata)->rxtx_regs + _reg)
+
+#define XRXTX_IOREAD_BITS(_pdata, _reg, _field) \
+ GET_BITS(XRXTX_IOREAD((_pdata), _reg), \
+ _reg##_##_field##_INDEX, \
+ _reg##_##_field##_WIDTH)
+
+#define XRXTX_IOWRITE(_pdata, _reg, _val) \
+ iowrite16((_val), (_pdata)->rxtx_regs + _reg)
+
+#define XRXTX_IOWRITE_BITS(_pdata, _reg, _field, _val) \
+do { \
+ u16 reg_val = XRXTX_IOREAD((_pdata), _reg); \
+ SET_BITS(reg_val, \
+ _reg##_##_field##_INDEX, \
+ _reg##_##_field##_WIDTH, (_val)); \
+ XRXTX_IOWRITE((_pdata), _reg, reg_val); \
+} while (0)
+
+/* Macros for building, reading or writing register values or bits
* using MDIO. Different from above because of the use of standardized
* Linux include values. No shifting is performed with the bit
* operations, everything works on mask values.
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dcb.c b/drivers/net/ethernet/amd/xgbe/xgbe-dcb.c
index 8a50b01c2686..a6b9899e285f 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dcb.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dcb.c
@@ -150,9 +150,12 @@ static int xgbe_dcb_ieee_setets(struct net_device *netdev,
tc_ets = 0;
tc_ets_weight = 0;
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
- DBGPR(" TC%u: tx_bw=%hhu, rx_bw=%hhu, tsa=%hhu\n", i,
- ets->tc_tx_bw[i], ets->tc_rx_bw[i], ets->tc_tsa[i]);
- DBGPR(" PRIO%u: TC=%hhu\n", i, ets->prio_tc[i]);
+ netif_dbg(pdata, drv, netdev,
+ "TC%u: tx_bw=%hhu, rx_bw=%hhu, tsa=%hhu\n", i,
+ ets->tc_tx_bw[i], ets->tc_rx_bw[i],
+ ets->tc_tsa[i]);
+ netif_dbg(pdata, drv, netdev, "PRIO%u: TC=%hhu\n", i,
+ ets->prio_tc[i]);
if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]) &&
(i >= pdata->hw_feat.tc_cnt))
@@ -214,8 +217,9 @@ static int xgbe_dcb_ieee_setpfc(struct net_device *netdev,
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
- DBGPR(" cap=%hhu, en=%hhx, mbc=%hhu, delay=%hhu\n",
- pfc->pfc_cap, pfc->pfc_en, pfc->mbc, pfc->delay);
+ netif_dbg(pdata, drv, netdev,
+ "cap=%hhu, en=%#hhx, mbc=%hhu, delay=%hhu\n",
+ pfc->pfc_cap, pfc->pfc_en, pfc->mbc, pfc->delay);
if (!pdata->pfc) {
pdata->pfc = devm_kzalloc(pdata->dev, sizeof(*pdata->pfc),
@@ -238,9 +242,10 @@ static u8 xgbe_dcb_getdcbx(struct net_device *netdev)
static u8 xgbe_dcb_setdcbx(struct net_device *netdev, u8 dcbx)
{
+ struct xgbe_prv_data *pdata = netdev_priv(netdev);
u8 support = xgbe_dcb_getdcbx(netdev);
- DBGPR(" DCBX=%#hhx\n", dcbx);
+ netif_dbg(pdata, drv, netdev, "DCBX=%#hhx\n", dcbx);
if (dcbx & ~support)
return 1;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
index d81fc6bd4759..dd03ad865caf 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
@@ -208,8 +208,9 @@ static int xgbe_init_ring(struct xgbe_prv_data *pdata,
if (!ring->rdata)
return -ENOMEM;
- DBGPR(" rdesc=0x%p, rdesc_dma=0x%llx, rdata=0x%p\n",
- ring->rdesc, ring->rdesc_dma, ring->rdata);
+ netif_dbg(pdata, drv, pdata->netdev,
+ "rdesc=%p, rdesc_dma=%pad, rdata=%p\n",
+ ring->rdesc, &ring->rdesc_dma, ring->rdata);
DBGPR("<--xgbe_init_ring\n");
@@ -226,7 +227,9 @@ static int xgbe_alloc_ring_resources(struct xgbe_prv_data *pdata)
channel = pdata->channel;
for (i = 0; i < pdata->channel_count; i++, channel++) {
- DBGPR(" %s - tx_ring:\n", channel->name);
+ netif_dbg(pdata, drv, pdata->netdev, "%s - Tx ring:\n",
+ channel->name);
+
ret = xgbe_init_ring(pdata, channel->tx_ring,
pdata->tx_desc_count);
if (ret) {
@@ -235,12 +238,14 @@ static int xgbe_alloc_ring_resources(struct xgbe_prv_data *pdata)
goto err_ring;
}
- DBGPR(" %s - rx_ring:\n", channel->name);
+ netif_dbg(pdata, drv, pdata->netdev, "%s - Rx ring:\n",
+ channel->name);
+
ret = xgbe_init_ring(pdata, channel->rx_ring,
pdata->rx_desc_count);
if (ret) {
netdev_alert(pdata->netdev,
- "error initializing Tx ring\n");
+ "error initializing Rx ring\n");
goto err_ring;
}
}
@@ -476,8 +481,6 @@ static void xgbe_unmap_rdata(struct xgbe_prv_data *pdata,
if (rdata->state_saved) {
rdata->state_saved = 0;
- rdata->state.incomplete = 0;
- rdata->state.context_next = 0;
rdata->state.skb = NULL;
rdata->state.len = 0;
rdata->state.error = 0;
@@ -518,8 +521,6 @@ static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb)
rdata = XGBE_GET_DESC_DATA(ring, cur_index);
if (tso) {
- DBGPR(" TSO packet\n");
-
/* Map the TSO header */
skb_dma = dma_map_single(pdata->dev, skb->data,
packet->header_len, DMA_TO_DEVICE);
@@ -529,6 +530,9 @@ static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb)
}
rdata->skb_dma = skb_dma;
rdata->skb_dma_len = packet->header_len;
+ netif_dbg(pdata, tx_queued, pdata->netdev,
+ "skb header: index=%u, dma=%pad, len=%u\n",
+ cur_index, &skb_dma, packet->header_len);
offset = packet->header_len;
@@ -550,8 +554,9 @@ static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb)
}
rdata->skb_dma = skb_dma;
rdata->skb_dma_len = len;
- DBGPR(" skb data: index=%u, dma=0x%llx, len=%u\n",
- cur_index, skb_dma, len);
+ netif_dbg(pdata, tx_queued, pdata->netdev,
+ "skb data: index=%u, dma=%pad, len=%u\n",
+ cur_index, &skb_dma, len);
datalen -= len;
offset += len;
@@ -563,7 +568,8 @@ static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb)
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- DBGPR(" mapping frag %u\n", i);
+ netif_dbg(pdata, tx_queued, pdata->netdev,
+ "mapping frag %u\n", i);
frag = &skb_shinfo(skb)->frags[i];
offset = 0;
@@ -582,8 +588,9 @@ static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb)
rdata->skb_dma = skb_dma;
rdata->skb_dma_len = len;
rdata->mapped_as_page = 1;
- DBGPR(" skb data: index=%u, dma=0x%llx, len=%u\n",
- cur_index, skb_dma, len);
+ netif_dbg(pdata, tx_queued, pdata->netdev,
+ "skb frag: index=%u, dma=%pad, len=%u\n",
+ cur_index, &skb_dma, len);
datalen -= len;
offset += len;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
index 21d9497518fd..506e832c9e9a 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -710,7 +710,8 @@ static int xgbe_set_promiscuous_mode(struct xgbe_prv_data *pdata,
if (XGMAC_IOREAD_BITS(pdata, MAC_PFR, PR) == val)
return 0;
- DBGPR(" %s promiscuous mode\n", enable ? "entering" : "leaving");
+ netif_dbg(pdata, drv, pdata->netdev, "%s promiscuous mode\n",
+ enable ? "entering" : "leaving");
XGMAC_IOWRITE_BITS(pdata, MAC_PFR, PR, val);
return 0;
@@ -724,7 +725,8 @@ static int xgbe_set_all_multicast_mode(struct xgbe_prv_data *pdata,
if (XGMAC_IOREAD_BITS(pdata, MAC_PFR, PM) == val)
return 0;
- DBGPR(" %s allmulti mode\n", enable ? "entering" : "leaving");
+ netif_dbg(pdata, drv, pdata->netdev, "%s allmulti mode\n",
+ enable ? "entering" : "leaving");
XGMAC_IOWRITE_BITS(pdata, MAC_PFR, PM, val);
return 0;
@@ -749,8 +751,9 @@ static void xgbe_set_mac_reg(struct xgbe_prv_data *pdata,
mac_addr[0] = ha->addr[4];
mac_addr[1] = ha->addr[5];
- DBGPR(" adding mac address %pM at 0x%04x\n", ha->addr,
- *mac_reg);
+ netif_dbg(pdata, drv, pdata->netdev,
+ "adding mac address %pM at %#x\n",
+ ha->addr, *mac_reg);
XGMAC_SET_BITS(mac_addr_hi, MAC_MACA1HR, AE, 1);
}
@@ -907,23 +910,6 @@ static void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad,
else
mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff);
- /* If the PCS is changing modes, match the MAC speed to it */
- if (((mmd_address >> 16) == MDIO_MMD_PCS) &&
- ((mmd_address & 0xffff) == MDIO_CTRL2)) {
- struct phy_device *phydev = pdata->phydev;
-
- if (mmd_data & MDIO_PCS_CTRL2_TYPE) {
- /* KX mode */
- if (phydev->supported & SUPPORTED_1000baseKX_Full)
- xgbe_set_gmii_speed(pdata);
- else
- xgbe_set_gmii_2500_speed(pdata);
- } else {
- /* KR mode */
- xgbe_set_xgmii_speed(pdata);
- }
- }
-
/* The PCS registers are accessed using mmio. The underlying APB3
* management interface uses indirect addressing to access the MMD
* register sets. This requires accessing of the PCS register in two
@@ -1322,7 +1308,8 @@ static void xgbe_config_dcb_tc(struct xgbe_prv_data *pdata)
for (i = 0; i < pdata->hw_feat.tc_cnt; i++) {
switch (ets->tc_tsa[i]) {
case IEEE_8021QAZ_TSA_STRICT:
- DBGPR(" TC%u using SP\n", i);
+ netif_dbg(pdata, drv, pdata->netdev,
+ "TC%u using SP\n", i);
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA,
MTL_TSA_SP);
break;
@@ -1330,7 +1317,8 @@ static void xgbe_config_dcb_tc(struct xgbe_prv_data *pdata)
weight = total_weight * ets->tc_tx_bw[i] / 100;
weight = clamp(weight, min_weight, total_weight);
- DBGPR(" TC%u using DWRR (weight %u)\n", i, weight);
+ netif_dbg(pdata, drv, pdata->netdev,
+ "TC%u using DWRR (weight %u)\n", i, weight);
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA,
MTL_TSA_ETS);
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_QWR, QW,
@@ -1359,7 +1347,8 @@ static void xgbe_config_dcb_pfc(struct xgbe_prv_data *pdata)
}
mask &= 0xff;
- DBGPR(" TC%u PFC mask=%#x\n", tc, mask);
+ netif_dbg(pdata, drv, pdata->netdev, "TC%u PFC mask=%#x\n",
+ tc, mask);
reg = MTL_TCPM0R + (MTL_TCPM_INC * (tc / MTL_TCPM_TC_PER_REG));
reg_val = XGMAC_IOREAD(pdata, reg);
@@ -1457,8 +1446,9 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
/* Create a context descriptor if this is a TSO packet */
if (tso_context || vlan_context) {
if (tso_context) {
- DBGPR(" TSO context descriptor, mss=%u\n",
- packet->mss);
+ netif_dbg(pdata, tx_queued, pdata->netdev,
+ "TSO context descriptor, mss=%u\n",
+ packet->mss);
/* Set the MSS size */
XGMAC_SET_BITS_LE(rdesc->desc2, TX_CONTEXT_DESC2,
@@ -1476,8 +1466,9 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
}
if (vlan_context) {
- DBGPR(" VLAN context descriptor, ctag=%u\n",
- packet->vlan_ctag);
+ netif_dbg(pdata, tx_queued, pdata->netdev,
+ "VLAN context descriptor, ctag=%u\n",
+ packet->vlan_ctag);
/* Mark it as a CONTEXT descriptor */
XGMAC_SET_BITS_LE(rdesc->desc3, TX_CONTEXT_DESC3,
@@ -1533,6 +1524,8 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
packet->tcp_payload_len);
XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, TCPHDRLEN,
packet->tcp_header_len / 4);
+
+ pdata->ext_stats.tx_tso_packets++;
} else {
/* Enable CRC and Pad Insertion */
XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CPC, 0);
@@ -1594,9 +1587,9 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
rdesc = rdata->rdesc;
XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN, 1);
-#ifdef XGMAC_ENABLE_TX_DESC_DUMP
- xgbe_dump_tx_desc(ring, start_index, packet->rdesc_count, 1);
-#endif
+ if (netif_msg_tx_queued(pdata))
+ xgbe_dump_tx_desc(pdata, ring, start_index,
+ packet->rdesc_count, 1);
/* Make sure ownership is written to the descriptor */
dma_wmb();
@@ -1618,11 +1611,12 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
static int xgbe_dev_read(struct xgbe_channel *channel)
{
+ struct xgbe_prv_data *pdata = channel->pdata;
struct xgbe_ring *ring = channel->rx_ring;
struct xgbe_ring_data *rdata;
struct xgbe_ring_desc *rdesc;
struct xgbe_packet_data *packet = &ring->packet_data;
- struct net_device *netdev = channel->pdata->netdev;
+ struct net_device *netdev = pdata->netdev;
unsigned int err, etlt, l34t;
DBGPR("-->xgbe_dev_read: cur = %d\n", ring->cur);
@@ -1637,9 +1631,8 @@ static int xgbe_dev_read(struct xgbe_channel *channel)
/* Make sure descriptor fields are read after reading the OWN bit */
dma_rmb();
-#ifdef XGMAC_ENABLE_RX_DESC_DUMP
- xgbe_dump_rx_desc(ring, rdesc, ring->cur);
-#endif
+ if (netif_msg_rx_status(pdata))
+ xgbe_dump_rx_desc(pdata, ring, ring->cur);
if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, CTXT)) {
/* Timestamp Context Descriptor */
@@ -1661,9 +1654,12 @@ static int xgbe_dev_read(struct xgbe_channel *channel)
CONTEXT_NEXT, 1);
/* Get the header length */
- if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, FD))
+ if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, FD)) {
rdata->rx.hdr_len = XGMAC_GET_BITS_LE(rdesc->desc2,
RX_NORMAL_DESC2, HL);
+ if (rdata->rx.hdr_len)
+ pdata->ext_stats.rx_split_header_packets++;
+ }
/* Get the RSS hash */
if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, RSV)) {
@@ -1700,14 +1696,14 @@ static int xgbe_dev_read(struct xgbe_channel *channel)
INCOMPLETE, 0);
/* Set checksum done indicator as appropriate */
- if (channel->pdata->netdev->features & NETIF_F_RXCSUM)
+ if (netdev->features & NETIF_F_RXCSUM)
XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
CSUM_DONE, 1);
/* Check for errors (only valid in last descriptor) */
err = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, ES);
etlt = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, ETLT);
- DBGPR(" err=%u, etlt=%#x\n", err, etlt);
+ netif_dbg(pdata, rx_status, netdev, "err=%u, etlt=%#x\n", err, etlt);
if (!err || !etlt) {
/* No error if err is 0 or etlt is 0 */
@@ -1718,7 +1714,8 @@ static int xgbe_dev_read(struct xgbe_channel *channel)
packet->vlan_ctag = XGMAC_GET_BITS_LE(rdesc->desc0,
RX_NORMAL_DESC0,
OVT);
- DBGPR(" vlan-ctag=0x%04x\n", packet->vlan_ctag);
+ netif_dbg(pdata, rx_status, netdev, "vlan-ctag=%#06x\n",
+ packet->vlan_ctag);
}
} else {
if ((etlt == 0x05) || (etlt == 0x06))
@@ -2026,9 +2023,9 @@ static void xgbe_config_tx_fifo_size(struct xgbe_prv_data *pdata)
for (i = 0; i < pdata->tx_q_count; i++)
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TQS, fifo_size);
- netdev_notice(pdata->netdev,
- "%d Tx hardware queues, %d byte fifo per queue\n",
- pdata->tx_q_count, ((fifo_size + 1) * 256));
+ netif_info(pdata, drv, pdata->netdev,
+ "%d Tx hardware queues, %d byte fifo per queue\n",
+ pdata->tx_q_count, ((fifo_size + 1) * 256));
}
static void xgbe_config_rx_fifo_size(struct xgbe_prv_data *pdata)
@@ -2042,9 +2039,9 @@ static void xgbe_config_rx_fifo_size(struct xgbe_prv_data *pdata)
for (i = 0; i < pdata->rx_q_count; i++)
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RQS, fifo_size);
- netdev_notice(pdata->netdev,
- "%d Rx hardware queues, %d byte fifo per queue\n",
- pdata->rx_q_count, ((fifo_size + 1) * 256));
+ netif_info(pdata, drv, pdata->netdev,
+ "%d Rx hardware queues, %d byte fifo per queue\n",
+ pdata->rx_q_count, ((fifo_size + 1) * 256));
}
static void xgbe_config_queue_mapping(struct xgbe_prv_data *pdata)
@@ -2063,14 +2060,16 @@ static void xgbe_config_queue_mapping(struct xgbe_prv_data *pdata)
for (i = 0, queue = 0; i < pdata->hw_feat.tc_cnt; i++) {
for (j = 0; j < qptc; j++) {
- DBGPR(" TXq%u mapped to TC%u\n", queue, i);
+ netif_dbg(pdata, drv, pdata->netdev,
+ "TXq%u mapped to TC%u\n", queue, i);
XGMAC_MTL_IOWRITE_BITS(pdata, queue, MTL_Q_TQOMR,
Q2TCMAP, i);
pdata->q2tc_map[queue++] = i;
}
if (i < qptc_extra) {
- DBGPR(" TXq%u mapped to TC%u\n", queue, i);
+ netif_dbg(pdata, drv, pdata->netdev,
+ "TXq%u mapped to TC%u\n", queue, i);
XGMAC_MTL_IOWRITE_BITS(pdata, queue, MTL_Q_TQOMR,
Q2TCMAP, i);
pdata->q2tc_map[queue++] = i;
@@ -2088,13 +2087,15 @@ static void xgbe_config_queue_mapping(struct xgbe_prv_data *pdata)
for (i = 0, prio = 0; i < prio_queues;) {
mask = 0;
for (j = 0; j < ppq; j++) {
- DBGPR(" PRIO%u mapped to RXq%u\n", prio, i);
+ netif_dbg(pdata, drv, pdata->netdev,
+ "PRIO%u mapped to RXq%u\n", prio, i);
mask |= (1 << prio);
pdata->prio2q_map[prio++] = i;
}
if (i < ppq_extra) {
- DBGPR(" PRIO%u mapped to RXq%u\n", prio, i);
+ netif_dbg(pdata, drv, pdata->netdev,
+ "PRIO%u mapped to RXq%u\n", prio, i);
mask |= (1 << prio);
pdata->prio2q_map[prio++] = i;
}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index 9fd6c69a8bac..1e9c28d19ef8 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -183,9 +183,10 @@ static int xgbe_alloc_channels(struct xgbe_prv_data *pdata)
channel->rx_ring = rx_ring++;
}
- DBGPR(" %s: queue=%u, dma_regs=%p, dma_irq=%d, tx=%p, rx=%p\n",
- channel->name, channel->queue_index, channel->dma_regs,
- channel->dma_irq, channel->tx_ring, channel->rx_ring);
+ netif_dbg(pdata, drv, pdata->netdev,
+ "%s: dma_regs=%p, dma_irq=%d, tx=%p, rx=%p\n",
+ channel->name, channel->dma_regs, channel->dma_irq,
+ channel->tx_ring, channel->rx_ring);
}
pdata->channel = channel_mem;
@@ -235,7 +236,8 @@ static int xgbe_maybe_stop_tx_queue(struct xgbe_channel *channel,
struct xgbe_prv_data *pdata = channel->pdata;
if (count > xgbe_tx_avail_desc(ring)) {
- DBGPR(" Tx queue stopped, not enough descriptors available\n");
+ netif_info(pdata, drv, pdata->netdev,
+ "Tx queue stopped, not enough descriptors available\n");
netif_stop_subqueue(pdata->netdev, channel->queue_index);
ring->tx.queue_stopped = 1;
@@ -330,7 +332,7 @@ static irqreturn_t xgbe_isr(int irq, void *data)
if (!dma_isr)
goto isr_done;
- DBGPR(" DMA_ISR = %08x\n", dma_isr);
+ netif_dbg(pdata, intr, pdata->netdev, "DMA_ISR=%#010x\n", dma_isr);
for (i = 0; i < pdata->channel_count; i++) {
if (!(dma_isr & (1 << i)))
@@ -339,7 +341,8 @@ static irqreturn_t xgbe_isr(int irq, void *data)
channel = pdata->channel + i;
dma_ch_isr = XGMAC_DMA_IOREAD(channel, DMA_CH_SR);
- DBGPR(" DMA_CH%u_ISR = %08x\n", i, dma_ch_isr);
+ netif_dbg(pdata, intr, pdata->netdev, "DMA_CH%u_ISR=%#010x\n",
+ i, dma_ch_isr);
/* The TI or RI interrupt bits may still be set even if using
* per channel DMA interrupts. Check to be sure those are not
@@ -386,8 +389,6 @@ static irqreturn_t xgbe_isr(int irq, void *data)
}
}
- DBGPR(" DMA_ISR = %08x\n", XGMAC_IOREAD(pdata, DMA_ISR));
-
isr_done:
return IRQ_HANDLED;
}
@@ -436,43 +437,61 @@ static void xgbe_tx_timer(unsigned long data)
DBGPR("<--xgbe_tx_timer\n");
}
-static void xgbe_init_tx_timers(struct xgbe_prv_data *pdata)
+static void xgbe_service(struct work_struct *work)
+{
+ struct xgbe_prv_data *pdata = container_of(work,
+ struct xgbe_prv_data,
+ service_work);
+
+ pdata->phy_if.phy_status(pdata);
+}
+
+static void xgbe_service_timer(unsigned long data)
+{
+ struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;
+
+ schedule_work(&pdata->service_work);
+
+ mod_timer(&pdata->service_timer, jiffies + HZ);
+}
+
+static void xgbe_init_timers(struct xgbe_prv_data *pdata)
{
struct xgbe_channel *channel;
unsigned int i;
- DBGPR("-->xgbe_init_tx_timers\n");
+ setup_timer(&pdata->service_timer, xgbe_service_timer,
+ (unsigned long)pdata);
channel = pdata->channel;
for (i = 0; i < pdata->channel_count; i++, channel++) {
if (!channel->tx_ring)
break;
- DBGPR(" %s adding tx timer\n", channel->name);
setup_timer(&channel->tx_timer, xgbe_tx_timer,
(unsigned long)channel);
}
+}
- DBGPR("<--xgbe_init_tx_timers\n");
+static void xgbe_start_timers(struct xgbe_prv_data *pdata)
+{
+ mod_timer(&pdata->service_timer, jiffies + HZ);
}
-static void xgbe_stop_tx_timers(struct xgbe_prv_data *pdata)
+static void xgbe_stop_timers(struct xgbe_prv_data *pdata)
{
struct xgbe_channel *channel;
unsigned int i;
- DBGPR("-->xgbe_stop_tx_timers\n");
+ del_timer_sync(&pdata->service_timer);
channel = pdata->channel;
for (i = 0; i < pdata->channel_count; i++, channel++) {
if (!channel->tx_ring)
break;
- DBGPR(" %s deleting tx timer\n", channel->name);
del_timer_sync(&channel->tx_timer);
}
-
- DBGPR("<--xgbe_stop_tx_timers\n");
}
void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata)
@@ -512,6 +531,7 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata)
RXFIFOSIZE);
hw_feat->tx_fifo_size = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R,
TXFIFOSIZE);
+ hw_feat->adv_ts_hi = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, ADVTHWORD);
hw_feat->dma_width = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, ADDR64);
hw_feat->dcb = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, DCBEN);
hw_feat->sph = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, SPHEN);
@@ -759,112 +779,12 @@ static void xgbe_free_rx_data(struct xgbe_prv_data *pdata)
DBGPR("<--xgbe_free_rx_data\n");
}
-static void xgbe_adjust_link(struct net_device *netdev)
-{
- struct xgbe_prv_data *pdata = netdev_priv(netdev);
- struct xgbe_hw_if *hw_if = &pdata->hw_if;
- struct phy_device *phydev = pdata->phydev;
- int new_state = 0;
-
- if (!phydev)
- return;
-
- if (phydev->link) {
- /* Flow control support */
- if (pdata->pause_autoneg) {
- if (phydev->pause || phydev->asym_pause) {
- pdata->tx_pause = 1;
- pdata->rx_pause = 1;
- } else {
- pdata->tx_pause = 0;
- pdata->rx_pause = 0;
- }
- }
-
- if (pdata->tx_pause != pdata->phy_tx_pause) {
- hw_if->config_tx_flow_control(pdata);
- pdata->phy_tx_pause = pdata->tx_pause;
- }
-
- if (pdata->rx_pause != pdata->phy_rx_pause) {
- hw_if->config_rx_flow_control(pdata);
- pdata->phy_rx_pause = pdata->rx_pause;
- }
-
- /* Speed support */
- if (phydev->speed != pdata->phy_speed) {
- new_state = 1;
-
- switch (phydev->speed) {
- case SPEED_10000:
- hw_if->set_xgmii_speed(pdata);
- break;
-
- case SPEED_2500:
- hw_if->set_gmii_2500_speed(pdata);
- break;
-
- case SPEED_1000:
- hw_if->set_gmii_speed(pdata);
- break;
- }
- pdata->phy_speed = phydev->speed;
- }
-
- if (phydev->link != pdata->phy_link) {
- new_state = 1;
- pdata->phy_link = 1;
- }
- } else if (pdata->phy_link) {
- new_state = 1;
- pdata->phy_link = 0;
- pdata->phy_speed = SPEED_UNKNOWN;
- }
-
- if (new_state)
- phy_print_status(phydev);
-}
-
static int xgbe_phy_init(struct xgbe_prv_data *pdata)
{
- struct net_device *netdev = pdata->netdev;
- struct phy_device *phydev = pdata->phydev;
- int ret;
-
pdata->phy_link = -1;
pdata->phy_speed = SPEED_UNKNOWN;
- pdata->phy_tx_pause = pdata->tx_pause;
- pdata->phy_rx_pause = pdata->rx_pause;
- ret = phy_connect_direct(netdev, phydev, &xgbe_adjust_link,
- pdata->phy_mode);
- if (ret) {
- netdev_err(netdev, "phy_connect_direct failed\n");
- return ret;
- }
-
- if (!phydev->drv || (phydev->drv->phy_id == 0)) {
- netdev_err(netdev, "phy_id not valid\n");
- ret = -ENODEV;
- goto err_phy_connect;
- }
- DBGPR(" phy_connect_direct succeeded for PHY %s, link=%d\n",
- dev_name(&phydev->dev), phydev->link);
-
- return 0;
-
-err_phy_connect:
- phy_disconnect(phydev);
-
- return ret;
-}
-
-static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
-{
- if (!pdata->phydev)
- return;
-
- phy_disconnect(pdata->phydev);
+ return pdata->phy_if.phy_reset(pdata);
}
int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
@@ -889,13 +809,14 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
netif_tx_stop_all_queues(netdev);
+ xgbe_stop_timers(pdata);
+ flush_workqueue(pdata->dev_workqueue);
+
hw_if->powerdown_tx(pdata);
hw_if->powerdown_rx(pdata);
xgbe_napi_disable(pdata, 0);
- phy_stop(pdata->phydev);
-
pdata->power_down = 1;
spin_unlock_irqrestore(&pdata->lock, flags);
@@ -924,8 +845,6 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
pdata->power_down = 0;
- phy_start(pdata->phydev);
-
xgbe_napi_enable(pdata, 0);
hw_if->powerup_tx(pdata);
@@ -936,6 +855,8 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
netif_tx_start_all_queues(netdev);
+ xgbe_start_timers(pdata);
+
spin_unlock_irqrestore(&pdata->lock, flags);
DBGPR("<--xgbe_powerup\n");
@@ -946,6 +867,7 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
static int xgbe_start(struct xgbe_prv_data *pdata)
{
struct xgbe_hw_if *hw_if = &pdata->hw_if;
+ struct xgbe_phy_if *phy_if = &pdata->phy_if;
struct net_device *netdev = pdata->netdev;
int ret;
@@ -953,7 +875,9 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
hw_if->init(pdata);
- phy_start(pdata->phydev);
+ ret = phy_if->phy_start(pdata);
+ if (ret)
+ goto err_phy;
xgbe_napi_enable(pdata, 1);
@@ -964,10 +888,11 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
hw_if->enable_tx(pdata);
hw_if->enable_rx(pdata);
- xgbe_init_tx_timers(pdata);
-
netif_tx_start_all_queues(netdev);
+ xgbe_start_timers(pdata);
+ schedule_work(&pdata->service_work);
+
DBGPR("<--xgbe_start\n");
return 0;
@@ -975,8 +900,9 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
err_napi:
xgbe_napi_disable(pdata, 1);
- phy_stop(pdata->phydev);
+ phy_if->phy_stop(pdata);
+err_phy:
hw_if->exit(pdata);
return ret;
@@ -985,6 +911,7 @@ err_napi:
static void xgbe_stop(struct xgbe_prv_data *pdata)
{
struct xgbe_hw_if *hw_if = &pdata->hw_if;
+ struct xgbe_phy_if *phy_if = &pdata->phy_if;
struct xgbe_channel *channel;
struct net_device *netdev = pdata->netdev;
struct netdev_queue *txq;
@@ -994,7 +921,8 @@ static void xgbe_stop(struct xgbe_prv_data *pdata)
netif_tx_stop_all_queues(netdev);
- xgbe_stop_tx_timers(pdata);
+ xgbe_stop_timers(pdata);
+ flush_workqueue(pdata->dev_workqueue);
hw_if->disable_tx(pdata);
hw_if->disable_rx(pdata);
@@ -1003,7 +931,7 @@ static void xgbe_stop(struct xgbe_prv_data *pdata)
xgbe_napi_disable(pdata, 1);
- phy_stop(pdata->phydev);
+ phy_if->phy_stop(pdata);
hw_if->exit(pdata);
@@ -1374,7 +1302,7 @@ static int xgbe_open(struct net_device *netdev)
ret = clk_prepare_enable(pdata->sysclk);
if (ret) {
netdev_alert(netdev, "dma clk_prepare_enable failed\n");
- goto err_phy_init;
+ return ret;
}
ret = clk_prepare_enable(pdata->ptpclk);
@@ -1399,14 +1327,17 @@ static int xgbe_open(struct net_device *netdev)
if (ret)
goto err_channels;
- /* Initialize the device restart and Tx timestamp work struct */
+ INIT_WORK(&pdata->service_work, xgbe_service);
INIT_WORK(&pdata->restart_work, xgbe_restart);
INIT_WORK(&pdata->tx_tstamp_work, xgbe_tx_tstamp);
+ xgbe_init_timers(pdata);
ret = xgbe_start(pdata);
if (ret)
goto err_rings;
+ clear_bit(XGBE_DOWN, &pdata->dev_state);
+
DBGPR("<--xgbe_open\n");
return 0;
@@ -1423,9 +1354,6 @@ err_ptpclk:
err_sysclk:
clk_disable_unprepare(pdata->sysclk);
-err_phy_init:
- xgbe_phy_exit(pdata);
-
return ret;
}
@@ -1449,8 +1377,7 @@ static int xgbe_close(struct net_device *netdev)
clk_disable_unprepare(pdata->ptpclk);
clk_disable_unprepare(pdata->sysclk);
- /* Release the phy */
- xgbe_phy_exit(pdata);
+ set_bit(XGBE_DOWN, &pdata->dev_state);
DBGPR("<--xgbe_close\n");
@@ -1478,7 +1405,8 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
ret = NETDEV_TX_OK;
if (skb->len == 0) {
- netdev_err(netdev, "empty skb received from stack\n");
+ netif_err(pdata, tx_err, netdev,
+ "empty skb received from stack\n");
dev_kfree_skb_any(skb);
goto tx_netdev_return;
}
@@ -1494,7 +1422,8 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
ret = xgbe_prep_tso(skb, packet);
if (ret) {
- netdev_err(netdev, "error processing TSO packet\n");
+ netif_err(pdata, tx_err, netdev,
+ "error processing TSO packet\n");
dev_kfree_skb_any(skb);
goto tx_netdev_return;
}
@@ -1513,9 +1442,8 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
/* Configure required descriptor fields for transmission */
hw_if->dev_xmit(channel);
-#ifdef XGMAC_ENABLE_TX_PKT_DUMP
- xgbe_print_pkt(netdev, skb, true);
-#endif
+ if (netif_msg_pktdata(pdata))
+ xgbe_print_pkt(netdev, skb, true);
/* Stop the queue in advance if there may not be enough descriptors */
xgbe_maybe_stop_tx_queue(channel, ring, XGBE_TX_MAX_DESCS);
@@ -1710,7 +1638,8 @@ static int xgbe_setup_tc(struct net_device *netdev, u8 tc)
(pdata->q2tc_map[queue] == i))
queue++;
- DBGPR(" TC%u using TXq%u-%u\n", i, offset, queue - 1);
+ netif_dbg(pdata, drv, netdev, "TC%u using TXq%u-%u\n",
+ i, offset, queue - 1);
netdev_set_tc_queue(netdev, i, queue - offset, offset);
offset = queue;
}
@@ -1820,9 +1749,10 @@ static void xgbe_rx_refresh(struct xgbe_channel *channel)
lower_32_bits(rdata->rdesc_dma));
}
-static struct sk_buff *xgbe_create_skb(struct napi_struct *napi,
+static struct sk_buff *xgbe_create_skb(struct xgbe_prv_data *pdata,
+ struct napi_struct *napi,
struct xgbe_ring_data *rdata,
- unsigned int *len)
+ unsigned int len)
{
struct sk_buff *skb;
u8 *packet;
@@ -1832,14 +1762,31 @@ static struct sk_buff *xgbe_create_skb(struct napi_struct *napi,
if (!skb)
return NULL;
+ /* Start with the header buffer which may contain just the header
+ * or the header plus data
+ */
+ dma_sync_single_for_cpu(pdata->dev, rdata->rx.hdr.dma,
+ rdata->rx.hdr.dma_len, DMA_FROM_DEVICE);
+
packet = page_address(rdata->rx.hdr.pa.pages) +
rdata->rx.hdr.pa.pages_offset;
- copy_len = (rdata->rx.hdr_len) ? rdata->rx.hdr_len : *len;
+ copy_len = (rdata->rx.hdr_len) ? rdata->rx.hdr_len : len;
copy_len = min(rdata->rx.hdr.dma_len, copy_len);
skb_copy_to_linear_data(skb, packet, copy_len);
skb_put(skb, copy_len);
- *len -= copy_len;
+ len -= copy_len;
+ if (len) {
+ /* Add the remaining data as a frag */
+ dma_sync_single_for_cpu(pdata->dev, rdata->rx.buf.dma,
+ rdata->rx.buf.dma_len, DMA_FROM_DEVICE);
+
+ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+ rdata->rx.buf.pa.pages,
+ rdata->rx.buf.pa.pages_offset,
+ len, rdata->rx.buf.dma_len);
+ rdata->rx.buf.pa.pages = NULL;
+ }
return skb;
}
@@ -1877,9 +1824,8 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
* bit */
dma_rmb();
-#ifdef XGMAC_ENABLE_TX_DESC_DUMP
- xgbe_dump_tx_desc(ring, ring->dirty, 1, 0);
-#endif
+ if (netif_msg_tx_done(pdata))
+ xgbe_dump_tx_desc(pdata, ring, ring->dirty, 1, 0);
if (hw_if->is_last_desc(rdesc)) {
tx_packets += rdata->tx.packets;
@@ -1922,7 +1868,7 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget)
struct sk_buff *skb;
struct skb_shared_hwtstamps *hwtstamps;
unsigned int incomplete, error, context_next, context;
- unsigned int len, put_len, max_len;
+ unsigned int len, rdesc_len, max_len;
unsigned int received = 0;
int packet_count = 0;
@@ -1932,6 +1878,9 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget)
if (!ring)
return 0;
+ incomplete = 0;
+ context_next = 0;
+
napi = (pdata->per_channel_irq) ? &channel->napi : &pdata->napi;
rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
@@ -1941,15 +1890,11 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget)
/* First time in loop see if we need to restore state */
if (!received && rdata->state_saved) {
- incomplete = rdata->state.incomplete;
- context_next = rdata->state.context_next;
skb = rdata->state.skb;
error = rdata->state.error;
len = rdata->state.len;
} else {
memset(packet, 0, sizeof(*packet));
- incomplete = 0;
- context_next = 0;
skb = NULL;
error = 0;
len = 0;
@@ -1983,29 +1928,23 @@ read_again:
if (error || packet->errors) {
if (packet->errors)
- DBGPR("Error in received packet\n");
+ netif_err(pdata, rx_err, netdev,
+ "error in received packet\n");
dev_kfree_skb(skb);
goto next_packet;
}
if (!context) {
- put_len = rdata->rx.len - len;
- len += put_len;
-
- if (!skb) {
- dma_sync_single_for_cpu(pdata->dev,
- rdata->rx.hdr.dma,
- rdata->rx.hdr.dma_len,
- DMA_FROM_DEVICE);
-
- skb = xgbe_create_skb(napi, rdata, &put_len);
- if (!skb) {
+ /* Length is cumulative, get this descriptor's length */
+ rdesc_len = rdata->rx.len - len;
+ len += rdesc_len;
+
+ if (rdesc_len && !skb) {
+ skb = xgbe_create_skb(pdata, napi, rdata,
+ rdesc_len);
+ if (!skb)
error = 1;
- goto skip_data;
- }
- }
-
- if (put_len) {
+ } else if (rdesc_len) {
dma_sync_single_for_cpu(pdata->dev,
rdata->rx.buf.dma,
rdata->rx.buf.dma_len,
@@ -2014,12 +1953,12 @@ read_again:
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
rdata->rx.buf.pa.pages,
rdata->rx.buf.pa.pages_offset,
- put_len, rdata->rx.buf.dma_len);
+ rdesc_len,
+ rdata->rx.buf.dma_len);
rdata->rx.buf.pa.pages = NULL;
}
}
-skip_data:
if (incomplete || context_next)
goto read_again;
@@ -2033,14 +1972,14 @@ skip_data:
max_len += VLAN_HLEN;
if (skb->len > max_len) {
- DBGPR("packet length exceeds configured MTU\n");
+ netif_err(pdata, rx_err, netdev,
+ "packet length exceeds configured MTU\n");
dev_kfree_skb(skb);
goto next_packet;
}
-#ifdef XGMAC_ENABLE_RX_PKT_DUMP
- xgbe_print_pkt(netdev, skb, false);
-#endif
+ if (netif_msg_pktdata(pdata))
+ xgbe_print_pkt(netdev, skb, false);
skb_checksum_none_assert(skb);
if (XGMAC_GET_BITS(packet->attributes,
@@ -2072,7 +2011,6 @@ skip_data:
skb_record_rx_queue(skb, channel->queue_index);
skb_mark_napi_id(skb, napi);
- netdev->last_rx = jiffies;
napi_gro_receive(napi, skb);
next_packet:
@@ -2083,8 +2021,6 @@ next_packet:
if (received && (incomplete || context_next)) {
rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
rdata->state_saved = 1;
- rdata->state.incomplete = incomplete;
- rdata->state.context_next = context_next;
rdata->state.skb = skb;
rdata->state.len = len;
rdata->state.error = error;
@@ -2165,8 +2101,8 @@ static int xgbe_all_poll(struct napi_struct *napi, int budget)
return processed;
}
-void xgbe_dump_tx_desc(struct xgbe_ring *ring, unsigned int idx,
- unsigned int count, unsigned int flag)
+void xgbe_dump_tx_desc(struct xgbe_prv_data *pdata, struct xgbe_ring *ring,
+ unsigned int idx, unsigned int count, unsigned int flag)
{
struct xgbe_ring_data *rdata;
struct xgbe_ring_desc *rdesc;
@@ -2174,20 +2110,29 @@ void xgbe_dump_tx_desc(struct xgbe_ring *ring, unsigned int idx,
while (count--) {
rdata = XGBE_GET_DESC_DATA(ring, idx);
rdesc = rdata->rdesc;
- pr_alert("TX_NORMAL_DESC[%d %s] = %08x:%08x:%08x:%08x\n", idx,
- (flag == 1) ? "QUEUED FOR TX" : "TX BY DEVICE",
- le32_to_cpu(rdesc->desc0), le32_to_cpu(rdesc->desc1),
- le32_to_cpu(rdesc->desc2), le32_to_cpu(rdesc->desc3));
+ netdev_dbg(pdata->netdev,
+ "TX_NORMAL_DESC[%d %s] = %08x:%08x:%08x:%08x\n", idx,
+ (flag == 1) ? "QUEUED FOR TX" : "TX BY DEVICE",
+ le32_to_cpu(rdesc->desc0),
+ le32_to_cpu(rdesc->desc1),
+ le32_to_cpu(rdesc->desc2),
+ le32_to_cpu(rdesc->desc3));
idx++;
}
}
-void xgbe_dump_rx_desc(struct xgbe_ring *ring, struct xgbe_ring_desc *desc,
+void xgbe_dump_rx_desc(struct xgbe_prv_data *pdata, struct xgbe_ring *ring,
unsigned int idx)
{
- pr_alert("RX_NORMAL_DESC[%d RX BY DEVICE] = %08x:%08x:%08x:%08x\n", idx,
- le32_to_cpu(desc->desc0), le32_to_cpu(desc->desc1),
- le32_to_cpu(desc->desc2), le32_to_cpu(desc->desc3));
+ struct xgbe_ring_data *rdata;
+ struct xgbe_ring_desc *rdesc;
+
+ rdata = XGBE_GET_DESC_DATA(ring, idx);
+ rdesc = rdata->rdesc;
+ netdev_dbg(pdata->netdev,
+ "RX_NORMAL_DESC[%d RX BY DEVICE] = %08x:%08x:%08x:%08x\n",
+ idx, le32_to_cpu(rdesc->desc0), le32_to_cpu(rdesc->desc1),
+ le32_to_cpu(rdesc->desc2), le32_to_cpu(rdesc->desc3));
}
void xgbe_print_pkt(struct net_device *netdev, struct sk_buff *skb, bool tx_rx)
@@ -2197,21 +2142,21 @@ void xgbe_print_pkt(struct net_device *netdev, struct sk_buff *skb, bool tx_rx)
unsigned char buffer[128];
unsigned int i, j;
- netdev_alert(netdev, "\n************** SKB dump ****************\n");
+ netdev_dbg(netdev, "\n************** SKB dump ****************\n");
- netdev_alert(netdev, "%s packet of %d bytes\n",
- (tx_rx ? "TX" : "RX"), skb->len);
+ netdev_dbg(netdev, "%s packet of %d bytes\n",
+ (tx_rx ? "TX" : "RX"), skb->len);
- netdev_alert(netdev, "Dst MAC addr: %pM\n", eth->h_dest);
- netdev_alert(netdev, "Src MAC addr: %pM\n", eth->h_source);
- netdev_alert(netdev, "Protocol: 0x%04hx\n", ntohs(eth->h_proto));
+ netdev_dbg(netdev, "Dst MAC addr: %pM\n", eth->h_dest);
+ netdev_dbg(netdev, "Src MAC addr: %pM\n", eth->h_source);
+ netdev_dbg(netdev, "Protocol: %#06hx\n", ntohs(eth->h_proto));
for (i = 0, j = 0; i < skb->len;) {
j += snprintf(buffer + j, sizeof(buffer) - j, "%02hhx",
buf[i++]);
if ((i % 32) == 0) {
- netdev_alert(netdev, " 0x%04x: %s\n", i - 32, buffer);
+ netdev_dbg(netdev, " %#06x: %s\n", i - 32, buffer);
j = 0;
} else if ((i % 16) == 0) {
buffer[j++] = ' ';
@@ -2221,7 +2166,7 @@ void xgbe_print_pkt(struct net_device *netdev, struct sk_buff *skb, bool tx_rx)
}
}
if (i % 32)
- netdev_alert(netdev, " 0x%04x: %s\n", i - (i % 32), buffer);
+ netdev_dbg(netdev, " %#06x: %s\n", i - (i % 32), buffer);
- netdev_alert(netdev, "\n************** SKB dump ****************\n");
+ netdev_dbg(netdev, "\n************** SKB dump ****************\n");
}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
index 5f149e8ee20f..59e090e95c0e 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
@@ -133,6 +133,12 @@ struct xgbe_stats {
offsetof(struct xgbe_prv_data, mmc_stats._var), \
}
+#define XGMAC_EXT_STAT(_string, _var) \
+ { _string, \
+ FIELD_SIZEOF(struct xgbe_ext_stats, _var), \
+ offsetof(struct xgbe_prv_data, ext_stats._var), \
+ }
+
static const struct xgbe_stats xgbe_gstring_stats[] = {
XGMAC_MMC_STAT("tx_bytes", txoctetcount_gb),
XGMAC_MMC_STAT("tx_packets", txframecount_gb),
@@ -140,6 +146,7 @@ static const struct xgbe_stats xgbe_gstring_stats[] = {
XGMAC_MMC_STAT("tx_broadcast_packets", txbroadcastframes_gb),
XGMAC_MMC_STAT("tx_multicast_packets", txmulticastframes_gb),
XGMAC_MMC_STAT("tx_vlan_packets", txvlanframes_g),
+ XGMAC_EXT_STAT("tx_tso_packets", tx_tso_packets),
XGMAC_MMC_STAT("tx_64_byte_packets", tx64octets_gb),
XGMAC_MMC_STAT("tx_65_to_127_byte_packets", tx65to127octets_gb),
XGMAC_MMC_STAT("tx_128_to_255_byte_packets", tx128to255octets_gb),
@@ -171,6 +178,7 @@ static const struct xgbe_stats xgbe_gstring_stats[] = {
XGMAC_MMC_STAT("rx_fifo_overflow_errors", rxfifooverflow),
XGMAC_MMC_STAT("rx_watchdog_errors", rxwatchdogerror),
XGMAC_MMC_STAT("rx_pause_frames", rxpauseframes),
+ XGMAC_EXT_STAT("rx_split_header_packets", rx_split_header_packets),
};
#define XGBE_STATS_COUNT ARRAY_SIZE(xgbe_gstring_stats)
@@ -239,9 +247,9 @@ static void xgbe_get_pauseparam(struct net_device *netdev,
DBGPR("-->xgbe_get_pauseparam\n");
- pause->autoneg = pdata->pause_autoneg;
- pause->tx_pause = pdata->tx_pause;
- pause->rx_pause = pdata->rx_pause;
+ pause->autoneg = pdata->phy.pause_autoneg;
+ pause->tx_pause = pdata->phy.tx_pause;
+ pause->rx_pause = pdata->phy.rx_pause;
DBGPR("<--xgbe_get_pauseparam\n");
}
@@ -250,7 +258,6 @@ static int xgbe_set_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
- struct phy_device *phydev = pdata->phydev;
int ret = 0;
DBGPR("-->xgbe_set_pauseparam\n");
@@ -258,21 +265,26 @@ static int xgbe_set_pauseparam(struct net_device *netdev,
DBGPR(" autoneg = %d, tx_pause = %d, rx_pause = %d\n",
pause->autoneg, pause->tx_pause, pause->rx_pause);
- pdata->pause_autoneg = pause->autoneg;
- if (pause->autoneg) {
- phydev->advertising |= ADVERTISED_Pause;
- phydev->advertising |= ADVERTISED_Asym_Pause;
+ if (pause->autoneg && (pdata->phy.autoneg != AUTONEG_ENABLE))
+ return -EINVAL;
+
+ pdata->phy.pause_autoneg = pause->autoneg;
+ pdata->phy.tx_pause = pause->tx_pause;
+ pdata->phy.rx_pause = pause->rx_pause;
- } else {
- phydev->advertising &= ~ADVERTISED_Pause;
- phydev->advertising &= ~ADVERTISED_Asym_Pause;
+ pdata->phy.advertising &= ~ADVERTISED_Pause;
+ pdata->phy.advertising &= ~ADVERTISED_Asym_Pause;
- pdata->tx_pause = pause->tx_pause;
- pdata->rx_pause = pause->rx_pause;
+ if (pause->rx_pause) {
+ pdata->phy.advertising |= ADVERTISED_Pause;
+ pdata->phy.advertising |= ADVERTISED_Asym_Pause;
}
+ if (pause->tx_pause)
+ pdata->phy.advertising ^= ADVERTISED_Asym_Pause;
+
if (netif_running(netdev))
- ret = phy_start_aneg(phydev);
+ ret = pdata->phy_if.phy_config_aneg(pdata);
DBGPR("<--xgbe_set_pauseparam\n");
@@ -283,36 +295,39 @@ static int xgbe_get_settings(struct net_device *netdev,
struct ethtool_cmd *cmd)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
- int ret;
DBGPR("-->xgbe_get_settings\n");
- if (!pdata->phydev)
- return -ENODEV;
+ cmd->phy_address = pdata->phy.address;
+
+ cmd->supported = pdata->phy.supported;
+ cmd->advertising = pdata->phy.advertising;
+ cmd->lp_advertising = pdata->phy.lp_advertising;
+
+ cmd->autoneg = pdata->phy.autoneg;
+ ethtool_cmd_speed_set(cmd, pdata->phy.speed);
+ cmd->duplex = pdata->phy.duplex;
- ret = phy_ethtool_gset(pdata->phydev, cmd);
+ cmd->port = PORT_NONE;
+ cmd->transceiver = XCVR_INTERNAL;
DBGPR("<--xgbe_get_settings\n");
- return ret;
+ return 0;
}
static int xgbe_set_settings(struct net_device *netdev,
struct ethtool_cmd *cmd)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
- struct phy_device *phydev = pdata->phydev;
u32 speed;
int ret;
DBGPR("-->xgbe_set_settings\n");
- if (!pdata->phydev)
- return -ENODEV;
-
speed = ethtool_cmd_speed(cmd);
- if (cmd->phy_address != phydev->addr)
+ if (cmd->phy_address != pdata->phy.address)
return -EINVAL;
if ((cmd->autoneg != AUTONEG_ENABLE) &&
@@ -333,23 +348,23 @@ static int xgbe_set_settings(struct net_device *netdev,
return -EINVAL;
}
- cmd->advertising &= phydev->supported;
+ cmd->advertising &= pdata->phy.supported;
if ((cmd->autoneg == AUTONEG_ENABLE) && !cmd->advertising)
return -EINVAL;
ret = 0;
- phydev->autoneg = cmd->autoneg;
- phydev->speed = speed;
- phydev->duplex = cmd->duplex;
- phydev->advertising = cmd->advertising;
+ pdata->phy.autoneg = cmd->autoneg;
+ pdata->phy.speed = speed;
+ pdata->phy.duplex = cmd->duplex;
+ pdata->phy.advertising = cmd->advertising;
if (cmd->autoneg == AUTONEG_ENABLE)
- phydev->advertising |= ADVERTISED_Autoneg;
+ pdata->phy.advertising |= ADVERTISED_Autoneg;
else
- phydev->advertising &= ~ADVERTISED_Autoneg;
+ pdata->phy.advertising &= ~ADVERTISED_Autoneg;
if (netif_running(netdev))
- ret = phy_start_aneg(phydev);
+ ret = pdata->phy_if.phy_config_aneg(pdata);
DBGPR("<--xgbe_set_settings\n");
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
index 6d2c702c8e4a..e83bd76abce6 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
@@ -124,9 +124,11 @@
#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/of_address.h>
+#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/property.h>
#include <linux/acpi.h>
+#include <linux/mdio.h>
#include "xgbe.h"
#include "xgbe-common.h"
@@ -136,6 +138,49 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(XGBE_DRV_VERSION);
MODULE_DESCRIPTION(XGBE_DRV_DESC);
+static int debug = -1;
+module_param(debug, int, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(debug, " Network interface message level setting");
+
+static const u32 default_msg_level = (NETIF_MSG_LINK | NETIF_MSG_IFDOWN |
+ NETIF_MSG_IFUP);
+
+static const u32 xgbe_serdes_blwc[] = {
+ XGBE_SPEED_1000_BLWC,
+ XGBE_SPEED_2500_BLWC,
+ XGBE_SPEED_10000_BLWC,
+};
+
+static const u32 xgbe_serdes_cdr_rate[] = {
+ XGBE_SPEED_1000_CDR,
+ XGBE_SPEED_2500_CDR,
+ XGBE_SPEED_10000_CDR,
+};
+
+static const u32 xgbe_serdes_pq_skew[] = {
+ XGBE_SPEED_1000_PQ,
+ XGBE_SPEED_2500_PQ,
+ XGBE_SPEED_10000_PQ,
+};
+
+static const u32 xgbe_serdes_tx_amp[] = {
+ XGBE_SPEED_1000_TXAMP,
+ XGBE_SPEED_2500_TXAMP,
+ XGBE_SPEED_10000_TXAMP,
+};
+
+static const u32 xgbe_serdes_dfe_tap_cfg[] = {
+ XGBE_SPEED_1000_DFE_TAP_CONFIG,
+ XGBE_SPEED_2500_DFE_TAP_CONFIG,
+ XGBE_SPEED_10000_DFE_TAP_CONFIG,
+};
+
+static const u32 xgbe_serdes_dfe_tap_ena[] = {
+ XGBE_SPEED_1000_DFE_TAP_ENABLE,
+ XGBE_SPEED_2500_DFE_TAP_ENABLE,
+ XGBE_SPEED_10000_DFE_TAP_ENABLE,
+};
+
static void xgbe_default_config(struct xgbe_prv_data *pdata)
{
DBGPR("-->xgbe_default_config\n");
@@ -153,8 +198,6 @@ static void xgbe_default_config(struct xgbe_prv_data *pdata)
pdata->rx_pause = 1;
pdata->phy_speed = SPEED_UNKNOWN;
pdata->power_down = 0;
- pdata->default_autoneg = AUTONEG_ENABLE;
- pdata->default_speed = SPEED_10000;
DBGPR("<--xgbe_default_config\n");
}
@@ -162,6 +205,7 @@ static void xgbe_default_config(struct xgbe_prv_data *pdata)
static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata)
{
xgbe_init_function_ptrs_dev(&pdata->hw_if);
+ xgbe_init_function_ptrs_phy(&pdata->phy_if);
xgbe_init_function_ptrs_desc(&pdata->desc_if);
}
@@ -222,23 +266,82 @@ static int xgbe_of_support(struct xgbe_prv_data *pdata)
return 0;
}
+
+static struct platform_device *xgbe_of_get_phy_pdev(struct xgbe_prv_data *pdata)
+{
+ struct device *dev = pdata->dev;
+ struct device_node *phy_node;
+ struct platform_device *phy_pdev;
+
+ phy_node = of_parse_phandle(dev->of_node, "phy-handle", 0);
+ if (phy_node) {
+ /* Old style device tree:
+ * The XGBE and PHY resources are separate
+ */
+ phy_pdev = of_find_device_by_node(phy_node);
+ of_node_put(phy_node);
+ } else {
+ /* New style device tree:
+ * The XGBE and PHY resources are grouped together with
+ * the PHY resources listed last
+ */
+ get_device(dev);
+ phy_pdev = pdata->pdev;
+ }
+
+ return phy_pdev;
+}
#else /* CONFIG_OF */
static int xgbe_of_support(struct xgbe_prv_data *pdata)
{
return -EINVAL;
}
-#endif /*CONFIG_OF */
+
+static struct platform_device *xgbe_of_get_phy_pdev(struct xgbe_prv_data *pdata)
+{
+ return NULL;
+}
+#endif /* CONFIG_OF */
+
+static unsigned int xgbe_resource_count(struct platform_device *pdev,
+ unsigned int type)
+{
+ unsigned int count;
+ int i;
+
+ for (i = 0, count = 0; i < pdev->num_resources; i++) {
+ struct resource *res = &pdev->resource[i];
+
+ if (type == resource_type(res))
+ count++;
+ }
+
+ return count;
+}
+
+static struct platform_device *xgbe_get_phy_pdev(struct xgbe_prv_data *pdata)
+{
+ struct platform_device *phy_pdev;
+
+ if (pdata->use_acpi) {
+ get_device(pdata->dev);
+ phy_pdev = pdata->pdev;
+ } else {
+ phy_pdev = xgbe_of_get_phy_pdev(pdata);
+ }
+
+ return phy_pdev;
+}
static int xgbe_probe(struct platform_device *pdev)
{
struct xgbe_prv_data *pdata;
- struct xgbe_hw_if *hw_if;
- struct xgbe_desc_if *desc_if;
struct net_device *netdev;
- struct device *dev = &pdev->dev;
+ struct device *dev = &pdev->dev, *phy_dev;
+ struct platform_device *phy_pdev;
struct resource *res;
const char *phy_mode;
- unsigned int i;
+ unsigned int i, phy_memnum, phy_irqnum;
int ret;
DBGPR("--> xgbe_probe\n");
@@ -263,9 +366,36 @@ static int xgbe_probe(struct platform_device *pdev)
mutex_init(&pdata->rss_mutex);
spin_lock_init(&pdata->tstamp_lock);
+ pdata->msg_enable = netif_msg_init(debug, default_msg_level);
+
+ set_bit(XGBE_DOWN, &pdata->dev_state);
+
/* Check if we should use ACPI or DT */
pdata->use_acpi = (!pdata->adev || acpi_disabled) ? 0 : 1;
+ phy_pdev = xgbe_get_phy_pdev(pdata);
+ if (!phy_pdev) {
+ dev_err(dev, "unable to obtain phy device\n");
+ ret = -EINVAL;
+ goto err_phydev;
+ }
+ phy_dev = &phy_pdev->dev;
+
+ if (pdev == phy_pdev) {
+ /* New style device tree or ACPI:
+ * The XGBE and PHY resources are grouped together with
+ * the PHY resources listed last
+ */
+ phy_memnum = xgbe_resource_count(pdev, IORESOURCE_MEM) - 3;
+ phy_irqnum = xgbe_resource_count(pdev, IORESOURCE_IRQ) - 1;
+ } else {
+ /* Old style device tree:
+ * The XGBE and PHY resources are separate
+ */
+ phy_memnum = 0;
+ phy_irqnum = 0;
+ }
+
/* Set and validate the number of descriptors for a ring */
BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_TX_DESC_CNT);
pdata->tx_desc_count = XGBE_TX_DESC_CNT;
@@ -292,7 +422,8 @@ static int xgbe_probe(struct platform_device *pdev)
ret = PTR_ERR(pdata->xgmac_regs);
goto err_io;
}
- DBGPR(" xgmac_regs = %p\n", pdata->xgmac_regs);
+ if (netif_msg_probe(pdata))
+ dev_dbg(dev, "xgmac_regs = %p\n", pdata->xgmac_regs);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
pdata->xpcs_regs = devm_ioremap_resource(dev, res);
@@ -301,7 +432,38 @@ static int xgbe_probe(struct platform_device *pdev)
ret = PTR_ERR(pdata->xpcs_regs);
goto err_io;
}
- DBGPR(" xpcs_regs = %p\n", pdata->xpcs_regs);
+ if (netif_msg_probe(pdata))
+ dev_dbg(dev, "xpcs_regs = %p\n", pdata->xpcs_regs);
+
+ res = platform_get_resource(phy_pdev, IORESOURCE_MEM, phy_memnum++);
+ pdata->rxtx_regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(pdata->rxtx_regs)) {
+ dev_err(dev, "rxtx ioremap failed\n");
+ ret = PTR_ERR(pdata->rxtx_regs);
+ goto err_io;
+ }
+ if (netif_msg_probe(pdata))
+ dev_dbg(dev, "rxtx_regs = %p\n", pdata->rxtx_regs);
+
+ res = platform_get_resource(phy_pdev, IORESOURCE_MEM, phy_memnum++);
+ pdata->sir0_regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(pdata->sir0_regs)) {
+ dev_err(dev, "sir0 ioremap failed\n");
+ ret = PTR_ERR(pdata->sir0_regs);
+ goto err_io;
+ }
+ if (netif_msg_probe(pdata))
+ dev_dbg(dev, "sir0_regs = %p\n", pdata->sir0_regs);
+
+ res = platform_get_resource(phy_pdev, IORESOURCE_MEM, phy_memnum++);
+ pdata->sir1_regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(pdata->sir1_regs)) {
+ dev_err(dev, "sir1 ioremap failed\n");
+ ret = PTR_ERR(pdata->sir1_regs);
+ goto err_io;
+ }
+ if (netif_msg_probe(pdata))
+ dev_dbg(dev, "sir1_regs = %p\n", pdata->sir1_regs);
/* Retrieve the MAC address */
ret = device_property_read_u8_array(dev, XGBE_MAC_ADDR_PROPERTY,
@@ -329,6 +491,115 @@ static int xgbe_probe(struct platform_device *pdev)
if (device_property_present(dev, XGBE_DMA_IRQS_PROPERTY))
pdata->per_channel_irq = 1;
+ /* Retrieve the PHY speedset */
+ ret = device_property_read_u32(phy_dev, XGBE_SPEEDSET_PROPERTY,
+ &pdata->speed_set);
+ if (ret) {
+ dev_err(dev, "invalid %s property\n", XGBE_SPEEDSET_PROPERTY);
+ goto err_io;
+ }
+
+ switch (pdata->speed_set) {
+ case XGBE_SPEEDSET_1000_10000:
+ case XGBE_SPEEDSET_2500_10000:
+ break;
+ default:
+ dev_err(dev, "invalid %s property\n", XGBE_SPEEDSET_PROPERTY);
+ ret = -EINVAL;
+ goto err_io;
+ }
+
+ /* Retrieve the PHY configuration properties */
+ if (device_property_present(phy_dev, XGBE_BLWC_PROPERTY)) {
+ ret = device_property_read_u32_array(phy_dev,
+ XGBE_BLWC_PROPERTY,
+ pdata->serdes_blwc,
+ XGBE_SPEEDS);
+ if (ret) {
+ dev_err(dev, "invalid %s property\n",
+ XGBE_BLWC_PROPERTY);
+ goto err_io;
+ }
+ } else {
+ memcpy(pdata->serdes_blwc, xgbe_serdes_blwc,
+ sizeof(pdata->serdes_blwc));
+ }
+
+ if (device_property_present(phy_dev, XGBE_CDR_RATE_PROPERTY)) {
+ ret = device_property_read_u32_array(phy_dev,
+ XGBE_CDR_RATE_PROPERTY,
+ pdata->serdes_cdr_rate,
+ XGBE_SPEEDS);
+ if (ret) {
+ dev_err(dev, "invalid %s property\n",
+ XGBE_CDR_RATE_PROPERTY);
+ goto err_io;
+ }
+ } else {
+ memcpy(pdata->serdes_cdr_rate, xgbe_serdes_cdr_rate,
+ sizeof(pdata->serdes_cdr_rate));
+ }
+
+ if (device_property_present(phy_dev, XGBE_PQ_SKEW_PROPERTY)) {
+ ret = device_property_read_u32_array(phy_dev,
+ XGBE_PQ_SKEW_PROPERTY,
+ pdata->serdes_pq_skew,
+ XGBE_SPEEDS);
+ if (ret) {
+ dev_err(dev, "invalid %s property\n",
+ XGBE_PQ_SKEW_PROPERTY);
+ goto err_io;
+ }
+ } else {
+ memcpy(pdata->serdes_pq_skew, xgbe_serdes_pq_skew,
+ sizeof(pdata->serdes_pq_skew));
+ }
+
+ if (device_property_present(phy_dev, XGBE_TX_AMP_PROPERTY)) {
+ ret = device_property_read_u32_array(phy_dev,
+ XGBE_TX_AMP_PROPERTY,
+ pdata->serdes_tx_amp,
+ XGBE_SPEEDS);
+ if (ret) {
+ dev_err(dev, "invalid %s property\n",
+ XGBE_TX_AMP_PROPERTY);
+ goto err_io;
+ }
+ } else {
+ memcpy(pdata->serdes_tx_amp, xgbe_serdes_tx_amp,
+ sizeof(pdata->serdes_tx_amp));
+ }
+
+ if (device_property_present(phy_dev, XGBE_DFE_CFG_PROPERTY)) {
+ ret = device_property_read_u32_array(phy_dev,
+ XGBE_DFE_CFG_PROPERTY,
+ pdata->serdes_dfe_tap_cfg,
+ XGBE_SPEEDS);
+ if (ret) {
+ dev_err(dev, "invalid %s property\n",
+ XGBE_DFE_CFG_PROPERTY);
+ goto err_io;
+ }
+ } else {
+ memcpy(pdata->serdes_dfe_tap_cfg, xgbe_serdes_dfe_tap_cfg,
+ sizeof(pdata->serdes_dfe_tap_cfg));
+ }
+
+ if (device_property_present(phy_dev, XGBE_DFE_ENA_PROPERTY)) {
+ ret = device_property_read_u32_array(phy_dev,
+ XGBE_DFE_ENA_PROPERTY,
+ pdata->serdes_dfe_tap_ena,
+ XGBE_SPEEDS);
+ if (ret) {
+ dev_err(dev, "invalid %s property\n",
+ XGBE_DFE_ENA_PROPERTY);
+ goto err_io;
+ }
+ } else {
+ memcpy(pdata->serdes_dfe_tap_ena, xgbe_serdes_dfe_tap_ena,
+ sizeof(pdata->serdes_dfe_tap_ena));
+ }
+
/* Obtain device settings unique to ACPI/OF */
if (pdata->use_acpi)
ret = xgbe_acpi_support(pdata);
@@ -357,17 +628,23 @@ static int xgbe_probe(struct platform_device *pdev)
}
pdata->dev_irq = ret;
+ /* Get the auto-negotiation interrupt */
+ ret = platform_get_irq(phy_pdev, phy_irqnum++);
+ if (ret < 0) {
+ dev_err(dev, "platform_get_irq phy 0 failed\n");
+ goto err_io;
+ }
+ pdata->an_irq = ret;
+
netdev->irq = pdata->dev_irq;
netdev->base_addr = (unsigned long)pdata->xgmac_regs;
memcpy(netdev->dev_addr, pdata->mac_addr, netdev->addr_len);
/* Set all the function pointers */
xgbe_init_all_fptrs(pdata);
- hw_if = &pdata->hw_if;
- desc_if = &pdata->desc_if;
/* Issue software reset to device */
- hw_if->exit(pdata);
+ pdata->hw_if.exit(pdata);
/* Populate the hardware features */
xgbe_get_all_hw_features(pdata);
@@ -376,8 +653,6 @@ static int xgbe_probe(struct platform_device *pdev)
xgbe_default_config(pdata);
/* Set the DMA mask */
- if (!dev->dma_mask)
- dev->dma_mask = &dev->coherent_dma_mask;
ret = dma_set_mask_and_coherent(dev,
DMA_BIT_MASK(pdata->hw_feat.dma_width));
if (ret) {
@@ -422,16 +697,8 @@ static int xgbe_probe(struct platform_device *pdev)
XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, TCP4TE, 1);
XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1);
- /* Prepare to regsiter with MDIO */
- pdata->mii_bus_id = kasprintf(GFP_KERNEL, "%s", pdev->name);
- if (!pdata->mii_bus_id) {
- dev_err(dev, "failed to allocate mii bus id\n");
- ret = -ENOMEM;
- goto err_io;
- }
- ret = xgbe_mdio_register(pdata);
- if (ret)
- goto err_bus_id;
+ /* Call MDIO/PHY initialization routine */
+ pdata->phy_if.phy_init(pdata);
/* Set device operations */
netdev->netdev_ops = xgbe_get_netdev_ops();
@@ -476,26 +743,52 @@ static int xgbe_probe(struct platform_device *pdev)
ret = register_netdev(netdev);
if (ret) {
dev_err(dev, "net device registration failed\n");
- goto err_reg_netdev;
+ goto err_io;
+ }
+
+ /* Create the PHY/ANEG name based on netdev name */
+ snprintf(pdata->an_name, sizeof(pdata->an_name) - 1, "%s-pcs",
+ netdev_name(netdev));
+
+ /* Create workqueues */
+ pdata->dev_workqueue =
+ create_singlethread_workqueue(netdev_name(netdev));
+ if (!pdata->dev_workqueue) {
+ netdev_err(netdev, "device workqueue creation failed\n");
+ ret = -ENOMEM;
+ goto err_netdev;
+ }
+
+ pdata->an_workqueue =
+ create_singlethread_workqueue(pdata->an_name);
+ if (!pdata->an_workqueue) {
+ netdev_err(netdev, "phy workqueue creation failed\n");
+ ret = -ENOMEM;
+ goto err_wq;
}
xgbe_ptp_register(pdata);
xgbe_debugfs_init(pdata);
+ platform_device_put(phy_pdev);
+
netdev_notice(netdev, "net device enabled\n");
DBGPR("<-- xgbe_probe\n");
return 0;
-err_reg_netdev:
- xgbe_mdio_unregister(pdata);
+err_wq:
+ destroy_workqueue(pdata->dev_workqueue);
-err_bus_id:
- kfree(pdata->mii_bus_id);
+err_netdev:
+ unregister_netdev(netdev);
err_io:
+ platform_device_put(phy_pdev);
+
+err_phydev:
free_netdev(netdev);
err_alloc:
@@ -515,11 +808,13 @@ static int xgbe_remove(struct platform_device *pdev)
xgbe_ptp_unregister(pdata);
- unregister_netdev(netdev);
+ flush_workqueue(pdata->an_workqueue);
+ destroy_workqueue(pdata->an_workqueue);
- xgbe_mdio_unregister(pdata);
+ flush_workqueue(pdata->dev_workqueue);
+ destroy_workqueue(pdata->dev_workqueue);
- kfree(pdata->mii_bus_id);
+ unregister_netdev(netdev);
free_netdev(netdev);
@@ -532,16 +827,17 @@ static int xgbe_remove(struct platform_device *pdev)
static int xgbe_suspend(struct device *dev)
{
struct net_device *netdev = dev_get_drvdata(dev);
- int ret;
+ struct xgbe_prv_data *pdata = netdev_priv(netdev);
+ int ret = 0;
DBGPR("-->xgbe_suspend\n");
- if (!netif_running(netdev)) {
- DBGPR("<--xgbe_dev_suspend\n");
- return -EINVAL;
- }
+ if (netif_running(netdev))
+ ret = xgbe_powerdown(netdev, XGMAC_DRIVER_CONTEXT);
- ret = xgbe_powerdown(netdev, XGMAC_DRIVER_CONTEXT);
+ pdata->lpm_ctrl = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
+ pdata->lpm_ctrl |= MDIO_CTRL1_LPOWER;
+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl);
DBGPR("<--xgbe_suspend\n");
@@ -551,16 +847,16 @@ static int xgbe_suspend(struct device *dev)
static int xgbe_resume(struct device *dev)
{
struct net_device *netdev = dev_get_drvdata(dev);
- int ret;
+ struct xgbe_prv_data *pdata = netdev_priv(netdev);
+ int ret = 0;
DBGPR("-->xgbe_resume\n");
- if (!netif_running(netdev)) {
- DBGPR("<--xgbe_dev_resume\n");
- return -EINVAL;
- }
+ pdata->lpm_ctrl &= ~MDIO_CTRL1_LPOWER;
+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl);
- ret = xgbe_powerup(netdev, XGMAC_DRIVER_CONTEXT);
+ if (netif_running(netdev))
+ ret = xgbe_powerup(netdev, XGMAC_DRIVER_CONTEXT);
DBGPR("<--xgbe_resume\n");
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
index 59e267f3f1b7..9088c3a35a20 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
@@ -119,194 +119,1246 @@
#include <linux/mdio.h>
#include <linux/phy.h>
#include <linux/of.h>
+#include <linux/bitops.h>
+#include <linux/jiffies.h>
#include "xgbe.h"
#include "xgbe-common.h"
-static int xgbe_mdio_read(struct mii_bus *mii, int prtad, int mmd_reg)
+static void xgbe_an_enable_kr_training(struct xgbe_prv_data *pdata)
{
- struct xgbe_prv_data *pdata = mii->priv;
- struct xgbe_hw_if *hw_if = &pdata->hw_if;
- int mmd_data;
+ unsigned int reg;
- DBGPR_MDIO("-->xgbe_mdio_read: prtad=%#x mmd_reg=%#x\n",
- prtad, mmd_reg);
+ reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
- mmd_data = hw_if->read_mmd_regs(pdata, prtad, mmd_reg);
+ reg |= XGBE_KR_TRAINING_ENABLE;
+ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
+}
+
+static void xgbe_an_disable_kr_training(struct xgbe_prv_data *pdata)
+{
+ unsigned int reg;
- DBGPR_MDIO("<--xgbe_mdio_read: mmd_data=%#x\n", mmd_data);
+ reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
- return mmd_data;
+ reg &= ~XGBE_KR_TRAINING_ENABLE;
+ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
}
-static int xgbe_mdio_write(struct mii_bus *mii, int prtad, int mmd_reg,
- u16 mmd_val)
+static void xgbe_pcs_power_cycle(struct xgbe_prv_data *pdata)
{
- struct xgbe_prv_data *pdata = mii->priv;
- struct xgbe_hw_if *hw_if = &pdata->hw_if;
- int mmd_data = mmd_val;
+ unsigned int reg;
- DBGPR_MDIO("-->xgbe_mdio_write: prtad=%#x mmd_reg=%#x mmd_data=%#x\n",
- prtad, mmd_reg, mmd_data);
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
- hw_if->write_mmd_regs(pdata, prtad, mmd_reg, mmd_data);
+ reg |= MDIO_CTRL1_LPOWER;
+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg);
- DBGPR_MDIO("<--xgbe_mdio_write\n");
+ usleep_range(75, 100);
- return 0;
+ reg &= ~MDIO_CTRL1_LPOWER;
+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg);
}
-void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata)
+static void xgbe_serdes_start_ratechange(struct xgbe_prv_data *pdata)
{
- struct device *dev = pdata->dev;
- struct phy_device *phydev = pdata->mii->phy_map[XGBE_PRTAD];
- int i;
-
- dev_alert(dev, "\n************* PHY Reg dump **********************\n");
-
- dev_alert(dev, "PCS Control Reg (%#04x) = %#04x\n", MDIO_CTRL1,
- XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1));
- dev_alert(dev, "PCS Status Reg (%#04x) = %#04x\n", MDIO_STAT1,
- XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1));
- dev_alert(dev, "Phy Id (PHYS ID 1 %#04x)= %#04x\n", MDIO_DEVID1,
- XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID1));
- dev_alert(dev, "Phy Id (PHYS ID 2 %#04x)= %#04x\n", MDIO_DEVID2,
- XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID2));
- dev_alert(dev, "Devices in Package (%#04x)= %#04x\n", MDIO_DEVS1,
- XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS1));
- dev_alert(dev, "Devices in Package (%#04x)= %#04x\n", MDIO_DEVS2,
- XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS2));
-
- dev_alert(dev, "Auto-Neg Control Reg (%#04x) = %#04x\n", MDIO_CTRL1,
- XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1));
- dev_alert(dev, "Auto-Neg Status Reg (%#04x) = %#04x\n", MDIO_STAT1,
- XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_STAT1));
- dev_alert(dev, "Auto-Neg Ad Reg 1 (%#04x) = %#04x\n",
- MDIO_AN_ADVERTISE,
- XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE));
- dev_alert(dev, "Auto-Neg Ad Reg 2 (%#04x) = %#04x\n",
- MDIO_AN_ADVERTISE + 1,
- XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1));
- dev_alert(dev, "Auto-Neg Ad Reg 3 (%#04x) = %#04x\n",
- MDIO_AN_ADVERTISE + 2,
- XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2));
- dev_alert(dev, "Auto-Neg Completion Reg (%#04x) = %#04x\n",
- MDIO_AN_COMP_STAT,
- XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_COMP_STAT));
-
- dev_alert(dev, "MMD Device Mask = %#x\n",
- phydev->c45_ids.devices_in_package);
- for (i = 0; i < ARRAY_SIZE(phydev->c45_ids.device_ids); i++)
- dev_alert(dev, " MMD %d: ID = %#08x\n", i,
- phydev->c45_ids.device_ids[i]);
-
- dev_alert(dev, "\n*************************************************\n");
-}
-
-int xgbe_mdio_register(struct xgbe_prv_data *pdata)
-{
- struct mii_bus *mii;
- struct phy_device *phydev;
- int ret = 0;
-
- DBGPR("-->xgbe_mdio_register\n");
-
- mii = mdiobus_alloc();
- if (!mii) {
- dev_err(pdata->dev, "mdiobus_alloc failed\n");
- return -ENOMEM;
+ /* Assert Rx and Tx ratechange */
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, RATECHANGE, 1);
+}
+
+static void xgbe_serdes_complete_ratechange(struct xgbe_prv_data *pdata)
+{
+ unsigned int wait;
+ u16 status;
+
+ /* Release Rx and Tx ratechange */
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, RATECHANGE, 0);
+
+ /* Wait for Rx and Tx ready */
+ wait = XGBE_RATECHANGE_COUNT;
+ while (wait--) {
+ usleep_range(50, 75);
+
+ status = XSIR0_IOREAD(pdata, SIR0_STATUS);
+ if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) &&
+ XSIR_GET_BITS(status, SIR0_STATUS, TX_READY))
+ goto rx_reset;
}
- /* Register on the MDIO bus (don't probe any PHYs) */
- mii->name = XGBE_PHY_NAME;
- mii->read = xgbe_mdio_read;
- mii->write = xgbe_mdio_write;
- snprintf(mii->id, sizeof(mii->id), "%s", pdata->mii_bus_id);
- mii->priv = pdata;
- mii->phy_mask = ~0;
- mii->parent = pdata->dev;
- ret = mdiobus_register(mii);
- if (ret) {
- dev_err(pdata->dev, "mdiobus_register failed\n");
- goto err_mdiobus_alloc;
+ netif_dbg(pdata, link, pdata->netdev, "SerDes rx/tx not ready (%#hx)\n",
+ status);
+
+rx_reset:
+ /* Perform Rx reset for the DFE changes */
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG6, RESETB_RXD, 0);
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG6, RESETB_RXD, 1);
+}
+
+static void xgbe_xgmii_mode(struct xgbe_prv_data *pdata)
+{
+ unsigned int reg;
+
+ /* Enable KR training */
+ xgbe_an_enable_kr_training(pdata);
+
+ /* Set MAC to 10G speed */
+ pdata->hw_if.set_xgmii_speed(pdata);
+
+ /* Set PCS to KR/10G speed */
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2);
+ reg &= ~MDIO_PCS_CTRL2_TYPE;
+ reg |= MDIO_PCS_CTRL2_10GBR;
+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg);
+
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
+ reg &= ~MDIO_CTRL1_SPEEDSEL;
+ reg |= MDIO_CTRL1_SPEED10G;
+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg);
+
+ xgbe_pcs_power_cycle(pdata);
+
+ /* Set SerDes to 10G speed */
+ xgbe_serdes_start_ratechange(pdata);
+
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_10000_RATE);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_10000_WORD);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_10000_PLL);
+
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE,
+ pdata->serdes_cdr_rate[XGBE_SPEED_10000]);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP,
+ pdata->serdes_tx_amp[XGBE_SPEED_10000]);
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA,
+ pdata->serdes_blwc[XGBE_SPEED_10000]);
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG,
+ pdata->serdes_pq_skew[XGBE_SPEED_10000]);
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG,
+ pdata->serdes_dfe_tap_cfg[XGBE_SPEED_10000]);
+ XRXTX_IOWRITE(pdata, RXTX_REG22,
+ pdata->serdes_dfe_tap_ena[XGBE_SPEED_10000]);
+
+ xgbe_serdes_complete_ratechange(pdata);
+
+ netif_dbg(pdata, link, pdata->netdev, "10GbE KR mode set\n");
+}
+
+static void xgbe_gmii_2500_mode(struct xgbe_prv_data *pdata)
+{
+ unsigned int reg;
+
+ /* Disable KR training */
+ xgbe_an_disable_kr_training(pdata);
+
+ /* Set MAC to 2.5G speed */
+ pdata->hw_if.set_gmii_2500_speed(pdata);
+
+ /* Set PCS to KX/1G speed */
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2);
+ reg &= ~MDIO_PCS_CTRL2_TYPE;
+ reg |= MDIO_PCS_CTRL2_10GBX;
+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg);
+
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
+ reg &= ~MDIO_CTRL1_SPEEDSEL;
+ reg |= MDIO_CTRL1_SPEED1G;
+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg);
+
+ xgbe_pcs_power_cycle(pdata);
+
+ /* Set SerDes to 2.5G speed */
+ xgbe_serdes_start_ratechange(pdata);
+
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_2500_RATE);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_2500_WORD);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_2500_PLL);
+
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE,
+ pdata->serdes_cdr_rate[XGBE_SPEED_2500]);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP,
+ pdata->serdes_tx_amp[XGBE_SPEED_2500]);
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA,
+ pdata->serdes_blwc[XGBE_SPEED_2500]);
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG,
+ pdata->serdes_pq_skew[XGBE_SPEED_2500]);
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG,
+ pdata->serdes_dfe_tap_cfg[XGBE_SPEED_2500]);
+ XRXTX_IOWRITE(pdata, RXTX_REG22,
+ pdata->serdes_dfe_tap_ena[XGBE_SPEED_2500]);
+
+ xgbe_serdes_complete_ratechange(pdata);
+
+ netif_dbg(pdata, link, pdata->netdev, "2.5GbE KX mode set\n");
+}
+
+static void xgbe_gmii_mode(struct xgbe_prv_data *pdata)
+{
+ unsigned int reg;
+
+ /* Disable KR training */
+ xgbe_an_disable_kr_training(pdata);
+
+ /* Set MAC to 1G speed */
+ pdata->hw_if.set_gmii_speed(pdata);
+
+ /* Set PCS to KX/1G speed */
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2);
+ reg &= ~MDIO_PCS_CTRL2_TYPE;
+ reg |= MDIO_PCS_CTRL2_10GBX;
+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg);
+
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
+ reg &= ~MDIO_CTRL1_SPEEDSEL;
+ reg |= MDIO_CTRL1_SPEED1G;
+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg);
+
+ xgbe_pcs_power_cycle(pdata);
+
+ /* Set SerDes to 1G speed */
+ xgbe_serdes_start_ratechange(pdata);
+
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_1000_RATE);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_1000_WORD);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_1000_PLL);
+
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE,
+ pdata->serdes_cdr_rate[XGBE_SPEED_1000]);
+ XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP,
+ pdata->serdes_tx_amp[XGBE_SPEED_1000]);
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA,
+ pdata->serdes_blwc[XGBE_SPEED_1000]);
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG,
+ pdata->serdes_pq_skew[XGBE_SPEED_1000]);
+ XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG,
+ pdata->serdes_dfe_tap_cfg[XGBE_SPEED_1000]);
+ XRXTX_IOWRITE(pdata, RXTX_REG22,
+ pdata->serdes_dfe_tap_ena[XGBE_SPEED_1000]);
+
+ xgbe_serdes_complete_ratechange(pdata);
+
+ netif_dbg(pdata, link, pdata->netdev, "1GbE KX mode set\n");
+}
+
+static void xgbe_cur_mode(struct xgbe_prv_data *pdata,
+ enum xgbe_mode *mode)
+{
+ unsigned int reg;
+
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2);
+ if ((reg & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR)
+ *mode = XGBE_MODE_KR;
+ else
+ *mode = XGBE_MODE_KX;
+}
+
+static bool xgbe_in_kr_mode(struct xgbe_prv_data *pdata)
+{
+ enum xgbe_mode mode;
+
+ xgbe_cur_mode(pdata, &mode);
+
+ return (mode == XGBE_MODE_KR);
+}
+
+static void xgbe_switch_mode(struct xgbe_prv_data *pdata)
+{
+ /* If we are in KR switch to KX, and vice-versa */
+ if (xgbe_in_kr_mode(pdata)) {
+ if (pdata->speed_set == XGBE_SPEEDSET_1000_10000)
+ xgbe_gmii_mode(pdata);
+ else
+ xgbe_gmii_2500_mode(pdata);
+ } else {
+ xgbe_xgmii_mode(pdata);
}
- DBGPR(" mdiobus_register succeeded for %s\n", pdata->mii_bus_id);
-
- /* Probe the PCS using Clause 45 */
- phydev = get_phy_device(mii, XGBE_PRTAD, true);
- if (IS_ERR(phydev) || !phydev ||
- !phydev->c45_ids.device_ids[MDIO_MMD_PCS]) {
- dev_err(pdata->dev, "get_phy_device failed\n");
- ret = phydev ? PTR_ERR(phydev) : -ENOLINK;
- goto err_mdiobus_register;
+}
+
+static void xgbe_set_mode(struct xgbe_prv_data *pdata,
+ enum xgbe_mode mode)
+{
+ enum xgbe_mode cur_mode;
+
+ xgbe_cur_mode(pdata, &cur_mode);
+ if (mode != cur_mode)
+ xgbe_switch_mode(pdata);
+}
+
+static bool xgbe_use_xgmii_mode(struct xgbe_prv_data *pdata)
+{
+ if (pdata->phy.autoneg == AUTONEG_ENABLE) {
+ if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full)
+ return true;
+ } else {
+ if (pdata->phy.speed == SPEED_10000)
+ return true;
}
- request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT,
- MDIO_ID_ARGS(phydev->c45_ids.device_ids[MDIO_MMD_PCS]));
- ret = phy_device_register(phydev);
- if (ret) {
- dev_err(pdata->dev, "phy_device_register failed\n");
- goto err_phy_device;
+ return false;
+}
+
+static bool xgbe_use_gmii_2500_mode(struct xgbe_prv_data *pdata)
+{
+ if (pdata->phy.autoneg == AUTONEG_ENABLE) {
+ if (pdata->phy.advertising & ADVERTISED_2500baseX_Full)
+ return true;
+ } else {
+ if (pdata->phy.speed == SPEED_2500)
+ return true;
}
- if (!phydev->dev.driver) {
- dev_err(pdata->dev, "phy driver probe failed\n");
- ret = -EIO;
- goto err_phy_device;
+
+ return false;
+}
+
+static bool xgbe_use_gmii_mode(struct xgbe_prv_data *pdata)
+{
+ if (pdata->phy.autoneg == AUTONEG_ENABLE) {
+ if (pdata->phy.advertising & ADVERTISED_1000baseKX_Full)
+ return true;
+ } else {
+ if (pdata->phy.speed == SPEED_1000)
+ return true;
}
- /* Add a reference to the PHY driver so it can't be unloaded */
- pdata->phy_module = phydev->dev.driver->owner;
- if (!try_module_get(pdata->phy_module)) {
- dev_err(pdata->dev, "try_module_get failed\n");
- ret = -EIO;
- goto err_phy_device;
+ return false;
+}
+
+static void xgbe_set_an(struct xgbe_prv_data *pdata, bool enable, bool restart)
+{
+ unsigned int reg;
+
+ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1);
+ reg &= ~MDIO_AN_CTRL1_ENABLE;
+
+ if (enable)
+ reg |= MDIO_AN_CTRL1_ENABLE;
+
+ if (restart)
+ reg |= MDIO_AN_CTRL1_RESTART;
+
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg);
+}
+
+static void xgbe_restart_an(struct xgbe_prv_data *pdata)
+{
+ xgbe_set_an(pdata, true, true);
+
+ netif_dbg(pdata, link, pdata->netdev, "AN enabled/restarted\n");
+}
+
+static void xgbe_disable_an(struct xgbe_prv_data *pdata)
+{
+ xgbe_set_an(pdata, false, false);
+
+ netif_dbg(pdata, link, pdata->netdev, "AN disabled\n");
+}
+
+static enum xgbe_an xgbe_an_tx_training(struct xgbe_prv_data *pdata,
+ enum xgbe_rx *state)
+{
+ unsigned int ad_reg, lp_reg, reg;
+
+ *state = XGBE_RX_COMPLETE;
+
+ /* If we're not in KR mode then we're done */
+ if (!xgbe_in_kr_mode(pdata))
+ return XGBE_AN_PAGE_RECEIVED;
+
+ /* Enable/Disable FEC */
+ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
+ lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
+
+ reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL);
+ reg &= ~(MDIO_PMA_10GBR_FECABLE_ABLE | MDIO_PMA_10GBR_FECABLE_ERRABLE);
+ if ((ad_reg & 0xc000) && (lp_reg & 0xc000))
+ reg |= pdata->fec_ability;
+
+ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL, reg);
+
+ /* Start KR training */
+ reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
+ if (reg & XGBE_KR_TRAINING_ENABLE) {
+ XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 1);
+
+ reg |= XGBE_KR_TRAINING_START;
+ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
+ reg);
+
+ XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 0);
+
+ netif_dbg(pdata, link, pdata->netdev,
+ "KR training initiated\n");
}
- pdata->mii = mii;
- pdata->mdio_mmd = MDIO_MMD_PCS;
+ return XGBE_AN_PAGE_RECEIVED;
+}
+
+static enum xgbe_an xgbe_an_tx_xnp(struct xgbe_prv_data *pdata,
+ enum xgbe_rx *state)
+{
+ u16 msg;
+
+ *state = XGBE_RX_XNP;
+
+ msg = XGBE_XNP_MCF_NULL_MESSAGE;
+ msg |= XGBE_XNP_MP_FORMATTED;
+
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 2, 0);
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0);
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP, msg);
+
+ return XGBE_AN_PAGE_RECEIVED;
+}
+
+static enum xgbe_an xgbe_an_rx_bpa(struct xgbe_prv_data *pdata,
+ enum xgbe_rx *state)
+{
+ unsigned int link_support;
+ unsigned int reg, ad_reg, lp_reg;
+
+ /* Read Base Ability register 2 first */
+ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
+
+ /* Check for a supported mode, otherwise restart in a different one */
+ link_support = xgbe_in_kr_mode(pdata) ? 0x80 : 0x20;
+ if (!(reg & link_support))
+ return XGBE_AN_INCOMPAT_LINK;
+
+ /* Check Extended Next Page support */
+ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
+ lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
+
+ return ((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
+ (lp_reg & XGBE_XNP_NP_EXCHANGE))
+ ? xgbe_an_tx_xnp(pdata, state)
+ : xgbe_an_tx_training(pdata, state);
+}
+
+static enum xgbe_an xgbe_an_rx_xnp(struct xgbe_prv_data *pdata,
+ enum xgbe_rx *state)
+{
+ unsigned int ad_reg, lp_reg;
+
+ /* Check Extended Next Page support */
+ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_XNP);
+ lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPX);
+
+ return ((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
+ (lp_reg & XGBE_XNP_NP_EXCHANGE))
+ ? xgbe_an_tx_xnp(pdata, state)
+ : xgbe_an_tx_training(pdata, state);
+}
+
+static enum xgbe_an xgbe_an_page_received(struct xgbe_prv_data *pdata)
+{
+ enum xgbe_rx *state;
+ unsigned long an_timeout;
+ enum xgbe_an ret;
+
+ if (!pdata->an_start) {
+ pdata->an_start = jiffies;
+ } else {
+ an_timeout = pdata->an_start +
+ msecs_to_jiffies(XGBE_AN_MS_TIMEOUT);
+ if (time_after(jiffies, an_timeout)) {
+ /* Auto-negotiation timed out, reset state */
+ pdata->kr_state = XGBE_RX_BPA;
+ pdata->kx_state = XGBE_RX_BPA;
+
+ pdata->an_start = jiffies;
+
+ netif_dbg(pdata, link, pdata->netdev,
+ "AN timed out, resetting state\n");
+ }
+ }
- phydev->autoneg = pdata->default_autoneg;
- if (phydev->autoneg == AUTONEG_DISABLE) {
- phydev->speed = pdata->default_speed;
- phydev->duplex = DUPLEX_FULL;
+ state = xgbe_in_kr_mode(pdata) ? &pdata->kr_state
+ : &pdata->kx_state;
- phydev->advertising &= ~ADVERTISED_Autoneg;
+ switch (*state) {
+ case XGBE_RX_BPA:
+ ret = xgbe_an_rx_bpa(pdata, state);
+ break;
+
+ case XGBE_RX_XNP:
+ ret = xgbe_an_rx_xnp(pdata, state);
+ break;
+
+ default:
+ ret = XGBE_AN_ERROR;
+ }
+
+ return ret;
+}
+
+static enum xgbe_an xgbe_an_incompat_link(struct xgbe_prv_data *pdata)
+{
+ /* Be sure we aren't looping trying to negotiate */
+ if (xgbe_in_kr_mode(pdata)) {
+ pdata->kr_state = XGBE_RX_ERROR;
+
+ if (!(pdata->phy.advertising & ADVERTISED_1000baseKX_Full) &&
+ !(pdata->phy.advertising & ADVERTISED_2500baseX_Full))
+ return XGBE_AN_NO_LINK;
+
+ if (pdata->kx_state != XGBE_RX_BPA)
+ return XGBE_AN_NO_LINK;
+ } else {
+ pdata->kx_state = XGBE_RX_ERROR;
+
+ if (!(pdata->phy.advertising & ADVERTISED_10000baseKR_Full))
+ return XGBE_AN_NO_LINK;
+
+ if (pdata->kr_state != XGBE_RX_BPA)
+ return XGBE_AN_NO_LINK;
+ }
+
+ xgbe_disable_an(pdata);
+
+ xgbe_switch_mode(pdata);
+
+ xgbe_restart_an(pdata);
+
+ return XGBE_AN_INCOMPAT_LINK;
+}
+
+static irqreturn_t xgbe_an_isr(int irq, void *data)
+{
+ struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;
+
+ netif_dbg(pdata, intr, pdata->netdev, "AN interrupt received\n");
+
+ /* Interrupt reason must be read and cleared outside of IRQ context */
+ disable_irq_nosync(pdata->an_irq);
+
+ queue_work(pdata->an_workqueue, &pdata->an_irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static void xgbe_an_irq_work(struct work_struct *work)
+{
+ struct xgbe_prv_data *pdata = container_of(work,
+ struct xgbe_prv_data,
+ an_irq_work);
+
+ /* Avoid a race between enabling the IRQ and exiting the work by
+ * waiting for the work to finish and then queueing it
+ */
+ flush_work(&pdata->an_work);
+ queue_work(pdata->an_workqueue, &pdata->an_work);
+}
+
+static const char *xgbe_state_as_string(enum xgbe_an state)
+{
+ switch (state) {
+ case XGBE_AN_READY:
+ return "Ready";
+ case XGBE_AN_PAGE_RECEIVED:
+ return "Page-Received";
+ case XGBE_AN_INCOMPAT_LINK:
+ return "Incompatible-Link";
+ case XGBE_AN_COMPLETE:
+ return "Complete";
+ case XGBE_AN_NO_LINK:
+ return "No-Link";
+ case XGBE_AN_ERROR:
+ return "Error";
+ default:
+ return "Undefined";
+ }
+}
+
+static void xgbe_an_state_machine(struct work_struct *work)
+{
+ struct xgbe_prv_data *pdata = container_of(work,
+ struct xgbe_prv_data,
+ an_work);
+ enum xgbe_an cur_state = pdata->an_state;
+ unsigned int int_reg, int_mask;
+
+ mutex_lock(&pdata->an_mutex);
+
+ /* Read the interrupt */
+ int_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT);
+ if (!int_reg)
+ goto out;
+
+next_int:
+ if (int_reg & XGBE_AN_PG_RCV) {
+ pdata->an_state = XGBE_AN_PAGE_RECEIVED;
+ int_mask = XGBE_AN_PG_RCV;
+ } else if (int_reg & XGBE_AN_INC_LINK) {
+ pdata->an_state = XGBE_AN_INCOMPAT_LINK;
+ int_mask = XGBE_AN_INC_LINK;
+ } else if (int_reg & XGBE_AN_INT_CMPLT) {
+ pdata->an_state = XGBE_AN_COMPLETE;
+ int_mask = XGBE_AN_INT_CMPLT;
+ } else {
+ pdata->an_state = XGBE_AN_ERROR;
+ int_mask = 0;
}
- pdata->phydev = phydev;
+ /* Clear the interrupt to be processed */
+ int_reg &= ~int_mask;
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, int_reg);
+
+ pdata->an_result = pdata->an_state;
+
+again:
+ netif_dbg(pdata, link, pdata->netdev, "AN %s\n",
+ xgbe_state_as_string(pdata->an_state));
+
+ cur_state = pdata->an_state;
+
+ switch (pdata->an_state) {
+ case XGBE_AN_READY:
+ pdata->an_supported = 0;
+ break;
+
+ case XGBE_AN_PAGE_RECEIVED:
+ pdata->an_state = xgbe_an_page_received(pdata);
+ pdata->an_supported++;
+ break;
+
+ case XGBE_AN_INCOMPAT_LINK:
+ pdata->an_supported = 0;
+ pdata->parallel_detect = 0;
+ pdata->an_state = xgbe_an_incompat_link(pdata);
+ break;
- DBGPHY_REGS(pdata);
+ case XGBE_AN_COMPLETE:
+ pdata->parallel_detect = pdata->an_supported ? 0 : 1;
+ netif_dbg(pdata, link, pdata->netdev, "%s successful\n",
+ pdata->an_supported ? "Auto negotiation"
+ : "Parallel detection");
+ break;
- DBGPR("<--xgbe_mdio_register\n");
+ case XGBE_AN_NO_LINK:
+ break;
+
+ default:
+ pdata->an_state = XGBE_AN_ERROR;
+ }
+
+ if (pdata->an_state == XGBE_AN_NO_LINK) {
+ int_reg = 0;
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
+ } else if (pdata->an_state == XGBE_AN_ERROR) {
+ netdev_err(pdata->netdev,
+ "error during auto-negotiation, state=%u\n",
+ cur_state);
+
+ int_reg = 0;
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
+ }
+
+ if (pdata->an_state >= XGBE_AN_COMPLETE) {
+ pdata->an_result = pdata->an_state;
+ pdata->an_state = XGBE_AN_READY;
+ pdata->kr_state = XGBE_RX_BPA;
+ pdata->kx_state = XGBE_RX_BPA;
+ pdata->an_start = 0;
+
+ netif_dbg(pdata, link, pdata->netdev, "AN result: %s\n",
+ xgbe_state_as_string(pdata->an_result));
+ }
+
+ if (cur_state != pdata->an_state)
+ goto again;
+
+ if (int_reg)
+ goto next_int;
+
+out:
+ enable_irq(pdata->an_irq);
+
+ mutex_unlock(&pdata->an_mutex);
+}
+
+static void xgbe_an_init(struct xgbe_prv_data *pdata)
+{
+ unsigned int reg;
+
+ /* Set up Advertisement register 3 first */
+ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
+ if (pdata->phy.advertising & ADVERTISED_10000baseR_FEC)
+ reg |= 0xc000;
+ else
+ reg &= ~0xc000;
+
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, reg);
+
+ /* Set up Advertisement register 2 next */
+ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
+ if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full)
+ reg |= 0x80;
+ else
+ reg &= ~0x80;
+
+ if ((pdata->phy.advertising & ADVERTISED_1000baseKX_Full) ||
+ (pdata->phy.advertising & ADVERTISED_2500baseX_Full))
+ reg |= 0x20;
+ else
+ reg &= ~0x20;
+
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, reg);
+
+ /* Set up Advertisement register 1 last */
+ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
+ if (pdata->phy.advertising & ADVERTISED_Pause)
+ reg |= 0x400;
+ else
+ reg &= ~0x400;
+
+ if (pdata->phy.advertising & ADVERTISED_Asym_Pause)
+ reg |= 0x800;
+ else
+ reg &= ~0x800;
+
+ /* We don't intend to perform XNP */
+ reg &= ~XGBE_XNP_NP_EXCHANGE;
+
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
+
+ netif_dbg(pdata, link, pdata->netdev, "AN initialized\n");
+}
+
+static const char *xgbe_phy_fc_string(struct xgbe_prv_data *pdata)
+{
+ if (pdata->tx_pause && pdata->rx_pause)
+ return "rx/tx";
+ else if (pdata->rx_pause)
+ return "rx";
+ else if (pdata->tx_pause)
+ return "tx";
+ else
+ return "off";
+}
+
+static const char *xgbe_phy_speed_string(int speed)
+{
+ switch (speed) {
+ case SPEED_1000:
+ return "1Gbps";
+ case SPEED_2500:
+ return "2.5Gbps";
+ case SPEED_10000:
+ return "10Gbps";
+ case SPEED_UNKNOWN:
+ return "Unknown";
+ default:
+ return "Unsupported";
+ }
+}
+
+static void xgbe_phy_print_status(struct xgbe_prv_data *pdata)
+{
+ if (pdata->phy.link)
+ netdev_info(pdata->netdev,
+ "Link is Up - %s/%s - flow control %s\n",
+ xgbe_phy_speed_string(pdata->phy.speed),
+ pdata->phy.duplex == DUPLEX_FULL ? "Full" : "Half",
+ xgbe_phy_fc_string(pdata));
+ else
+ netdev_info(pdata->netdev, "Link is Down\n");
+}
+
+static void xgbe_phy_adjust_link(struct xgbe_prv_data *pdata)
+{
+ int new_state = 0;
+
+ if (pdata->phy.link) {
+ /* Flow control support */
+ pdata->pause_autoneg = pdata->phy.pause_autoneg;
+
+ if (pdata->tx_pause != pdata->phy.tx_pause) {
+ new_state = 1;
+ pdata->hw_if.config_tx_flow_control(pdata);
+ pdata->tx_pause = pdata->phy.tx_pause;
+ }
+
+ if (pdata->rx_pause != pdata->phy.rx_pause) {
+ new_state = 1;
+ pdata->hw_if.config_rx_flow_control(pdata);
+ pdata->rx_pause = pdata->phy.rx_pause;
+ }
+
+ /* Speed support */
+ if (pdata->phy_speed != pdata->phy.speed) {
+ new_state = 1;
+ pdata->phy_speed = pdata->phy.speed;
+ }
+
+ if (pdata->phy_link != pdata->phy.link) {
+ new_state = 1;
+ pdata->phy_link = pdata->phy.link;
+ }
+ } else if (pdata->phy_link) {
+ new_state = 1;
+ pdata->phy_link = 0;
+ pdata->phy_speed = SPEED_UNKNOWN;
+ }
+
+ if (new_state && netif_msg_link(pdata))
+ xgbe_phy_print_status(pdata);
+}
+
+static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
+{
+ netif_dbg(pdata, link, pdata->netdev, "fixed PHY configuration\n");
+
+ /* Disable auto-negotiation */
+ xgbe_disable_an(pdata);
+
+ /* Validate/Set specified speed */
+ switch (pdata->phy.speed) {
+ case SPEED_10000:
+ xgbe_set_mode(pdata, XGBE_MODE_KR);
+ break;
+
+ case SPEED_2500:
+ case SPEED_1000:
+ xgbe_set_mode(pdata, XGBE_MODE_KX);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Validate duplex mode */
+ if (pdata->phy.duplex != DUPLEX_FULL)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
+{
+ set_bit(XGBE_LINK_INIT, &pdata->dev_state);
+ pdata->link_check = jiffies;
+
+ if (pdata->phy.autoneg != AUTONEG_ENABLE)
+ return xgbe_phy_config_fixed(pdata);
+
+ netif_dbg(pdata, link, pdata->netdev, "AN PHY configuration\n");
+
+ /* Disable auto-negotiation interrupt */
+ disable_irq(pdata->an_irq);
+
+ /* Start auto-negotiation in a supported mode */
+ if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full) {
+ xgbe_set_mode(pdata, XGBE_MODE_KR);
+ } else if ((pdata->phy.advertising & ADVERTISED_1000baseKX_Full) ||
+ (pdata->phy.advertising & ADVERTISED_2500baseX_Full)) {
+ xgbe_set_mode(pdata, XGBE_MODE_KX);
+ } else {
+ enable_irq(pdata->an_irq);
+ return -EINVAL;
+ }
+
+ /* Disable and stop any in progress auto-negotiation */
+ xgbe_disable_an(pdata);
+
+ /* Clear any auto-negotitation interrupts */
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
+
+ pdata->an_result = XGBE_AN_READY;
+ pdata->an_state = XGBE_AN_READY;
+ pdata->kr_state = XGBE_RX_BPA;
+ pdata->kx_state = XGBE_RX_BPA;
+
+ /* Re-enable auto-negotiation interrupt */
+ enable_irq(pdata->an_irq);
+
+ /* Set up advertisement registers based on current settings */
+ xgbe_an_init(pdata);
+
+ /* Enable and start auto-negotiation */
+ xgbe_restart_an(pdata);
return 0;
+}
+
+static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
+{
+ int ret;
+
+ mutex_lock(&pdata->an_mutex);
+
+ ret = __xgbe_phy_config_aneg(pdata);
+ if (ret)
+ set_bit(XGBE_LINK_ERR, &pdata->dev_state);
+ else
+ clear_bit(XGBE_LINK_ERR, &pdata->dev_state);
+
+ mutex_unlock(&pdata->an_mutex);
+
+ return ret;
+}
+
+static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata)
+{
+ return (pdata->an_result == XGBE_AN_COMPLETE);
+}
+
+static void xgbe_check_link_timeout(struct xgbe_prv_data *pdata)
+{
+ unsigned long link_timeout;
+
+ link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * HZ);
+ if (time_after(jiffies, link_timeout)) {
+ netif_dbg(pdata, link, pdata->netdev, "AN link timeout\n");
+ xgbe_phy_config_aneg(pdata);
+ }
+}
+
+static void xgbe_phy_status_force(struct xgbe_prv_data *pdata)
+{
+ if (xgbe_in_kr_mode(pdata)) {
+ pdata->phy.speed = SPEED_10000;
+ } else {
+ switch (pdata->speed_set) {
+ case XGBE_SPEEDSET_1000_10000:
+ pdata->phy.speed = SPEED_1000;
+ break;
+
+ case XGBE_SPEEDSET_2500_10000:
+ pdata->phy.speed = SPEED_2500;
+ break;
+ }
+ }
+ pdata->phy.duplex = DUPLEX_FULL;
+}
+
+static void xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
+{
+ unsigned int ad_reg, lp_reg;
+
+ pdata->phy.lp_advertising = 0;
+
+ if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect)
+ return xgbe_phy_status_force(pdata);
+
+ pdata->phy.lp_advertising |= ADVERTISED_Autoneg;
+ pdata->phy.lp_advertising |= ADVERTISED_Backplane;
+
+ /* Compare Advertisement and Link Partner register 1 */
+ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
+ lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
+ if (lp_reg & 0x400)
+ pdata->phy.lp_advertising |= ADVERTISED_Pause;
+ if (lp_reg & 0x800)
+ pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause;
+
+ if (pdata->phy.pause_autoneg) {
+ /* Set flow control based on auto-negotiation result */
+ pdata->phy.tx_pause = 0;
+ pdata->phy.rx_pause = 0;
+
+ if (ad_reg & lp_reg & 0x400) {
+ pdata->phy.tx_pause = 1;
+ pdata->phy.rx_pause = 1;
+ } else if (ad_reg & lp_reg & 0x800) {
+ if (ad_reg & 0x400)
+ pdata->phy.rx_pause = 1;
+ else if (lp_reg & 0x400)
+ pdata->phy.tx_pause = 1;
+ }
+ }
+
+ /* Compare Advertisement and Link Partner register 2 */
+ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
+ lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
+ if (lp_reg & 0x80)
+ pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full;
+ if (lp_reg & 0x20) {
+ switch (pdata->speed_set) {
+ case XGBE_SPEEDSET_1000_10000:
+ pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full;
+ break;
+ case XGBE_SPEEDSET_2500_10000:
+ pdata->phy.lp_advertising |= ADVERTISED_2500baseX_Full;
+ break;
+ }
+ }
+
+ ad_reg &= lp_reg;
+ if (ad_reg & 0x80) {
+ pdata->phy.speed = SPEED_10000;
+ xgbe_set_mode(pdata, XGBE_MODE_KR);
+ } else if (ad_reg & 0x20) {
+ switch (pdata->speed_set) {
+ case XGBE_SPEEDSET_1000_10000:
+ pdata->phy.speed = SPEED_1000;
+ break;
+
+ case XGBE_SPEEDSET_2500_10000:
+ pdata->phy.speed = SPEED_2500;
+ break;
+ }
+
+ xgbe_set_mode(pdata, XGBE_MODE_KX);
+ } else {
+ pdata->phy.speed = SPEED_UNKNOWN;
+ }
+
+ /* Compare Advertisement and Link Partner register 3 */
+ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
+ lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
+ if (lp_reg & 0xc000)
+ pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC;
+
+ pdata->phy.duplex = DUPLEX_FULL;
+}
+
+static void xgbe_phy_status(struct xgbe_prv_data *pdata)
+{
+ unsigned int reg, link_aneg;
+
+ if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) {
+ if (test_and_clear_bit(XGBE_LINK, &pdata->dev_state))
+ netif_carrier_off(pdata->netdev);
+
+ pdata->phy.link = 0;
+ goto adjust_link;
+ }
+
+ link_aneg = (pdata->phy.autoneg == AUTONEG_ENABLE);
+
+ /* Get the link status. Link status is latched low, so read
+ * once to clear and then read again to get current state
+ */
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
+ pdata->phy.link = (reg & MDIO_STAT1_LSTATUS) ? 1 : 0;
+
+ if (pdata->phy.link) {
+ if (link_aneg && !xgbe_phy_aneg_done(pdata)) {
+ xgbe_check_link_timeout(pdata);
+ return;
+ }
+
+ xgbe_phy_status_aneg(pdata);
+
+ if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
+ clear_bit(XGBE_LINK_INIT, &pdata->dev_state);
+
+ if (!test_bit(XGBE_LINK, &pdata->dev_state)) {
+ set_bit(XGBE_LINK, &pdata->dev_state);
+ netif_carrier_on(pdata->netdev);
+ }
+ } else {
+ if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) {
+ xgbe_check_link_timeout(pdata);
+
+ if (link_aneg)
+ return;
+ }
+
+ xgbe_phy_status_aneg(pdata);
+
+ if (test_bit(XGBE_LINK, &pdata->dev_state)) {
+ clear_bit(XGBE_LINK, &pdata->dev_state);
+ netif_carrier_off(pdata->netdev);
+ }
+ }
+
+adjust_link:
+ xgbe_phy_adjust_link(pdata);
+}
+
+static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
+{
+ netif_dbg(pdata, link, pdata->netdev, "stopping PHY\n");
+
+ /* Disable auto-negotiation */
+ xgbe_disable_an(pdata);
+
+ /* Disable auto-negotiation interrupts */
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
+
+ devm_free_irq(pdata->dev, pdata->an_irq, pdata);
-err_phy_device:
- phy_device_free(phydev);
+ pdata->phy.link = 0;
+ if (test_and_clear_bit(XGBE_LINK, &pdata->dev_state))
+ netif_carrier_off(pdata->netdev);
-err_mdiobus_register:
- mdiobus_unregister(mii);
+ xgbe_phy_adjust_link(pdata);
+}
+
+static int xgbe_phy_start(struct xgbe_prv_data *pdata)
+{
+ struct net_device *netdev = pdata->netdev;
+ int ret;
+
+ netif_dbg(pdata, link, pdata->netdev, "starting PHY\n");
+
+ ret = devm_request_irq(pdata->dev, pdata->an_irq,
+ xgbe_an_isr, 0, pdata->an_name,
+ pdata);
+ if (ret) {
+ netdev_err(netdev, "phy irq request failed\n");
+ return ret;
+ }
+
+ /* Set initial mode - call the mode setting routines
+ * directly to insure we are properly configured
+ */
+ if (xgbe_use_xgmii_mode(pdata)) {
+ xgbe_xgmii_mode(pdata);
+ } else if (xgbe_use_gmii_mode(pdata)) {
+ xgbe_gmii_mode(pdata);
+ } else if (xgbe_use_gmii_2500_mode(pdata)) {
+ xgbe_gmii_2500_mode(pdata);
+ } else {
+ ret = -EINVAL;
+ goto err_irq;
+ }
+
+ /* Set up advertisement registers based on current settings */
+ xgbe_an_init(pdata);
+
+ /* Enable auto-negotiation interrupts */
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07);
-err_mdiobus_alloc:
- mdiobus_free(mii);
+ return xgbe_phy_config_aneg(pdata);
+
+err_irq:
+ devm_free_irq(pdata->dev, pdata->an_irq, pdata);
return ret;
}
-void xgbe_mdio_unregister(struct xgbe_prv_data *pdata)
+static int xgbe_phy_reset(struct xgbe_prv_data *pdata)
+{
+ unsigned int count, reg;
+
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
+ reg |= MDIO_CTRL1_RESET;
+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg);
+
+ count = 50;
+ do {
+ msleep(20);
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
+ } while ((reg & MDIO_CTRL1_RESET) && --count);
+
+ if (reg & MDIO_CTRL1_RESET)
+ return -ETIMEDOUT;
+
+ /* Disable auto-negotiation for now */
+ xgbe_disable_an(pdata);
+
+ /* Clear auto-negotiation interrupts */
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
+
+ return 0;
+}
+
+static void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata)
{
- DBGPR("-->xgbe_mdio_unregister\n");
+ struct device *dev = pdata->dev;
+
+ dev_dbg(dev, "\n************* PHY Reg dump **********************\n");
+
+ dev_dbg(dev, "PCS Control Reg (%#04x) = %#04x\n", MDIO_CTRL1,
+ XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1));
+ dev_dbg(dev, "PCS Status Reg (%#04x) = %#04x\n", MDIO_STAT1,
+ XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1));
+ dev_dbg(dev, "Phy Id (PHYS ID 1 %#04x)= %#04x\n", MDIO_DEVID1,
+ XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID1));
+ dev_dbg(dev, "Phy Id (PHYS ID 2 %#04x)= %#04x\n", MDIO_DEVID2,
+ XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID2));
+ dev_dbg(dev, "Devices in Package (%#04x)= %#04x\n", MDIO_DEVS1,
+ XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS1));
+ dev_dbg(dev, "Devices in Package (%#04x)= %#04x\n", MDIO_DEVS2,
+ XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS2));
+
+ dev_dbg(dev, "Auto-Neg Control Reg (%#04x) = %#04x\n", MDIO_CTRL1,
+ XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1));
+ dev_dbg(dev, "Auto-Neg Status Reg (%#04x) = %#04x\n", MDIO_STAT1,
+ XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_STAT1));
+ dev_dbg(dev, "Auto-Neg Ad Reg 1 (%#04x) = %#04x\n",
+ MDIO_AN_ADVERTISE,
+ XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE));
+ dev_dbg(dev, "Auto-Neg Ad Reg 2 (%#04x) = %#04x\n",
+ MDIO_AN_ADVERTISE + 1,
+ XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1));
+ dev_dbg(dev, "Auto-Neg Ad Reg 3 (%#04x) = %#04x\n",
+ MDIO_AN_ADVERTISE + 2,
+ XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2));
+ dev_dbg(dev, "Auto-Neg Completion Reg (%#04x) = %#04x\n",
+ MDIO_AN_COMP_STAT,
+ XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_COMP_STAT));
+
+ dev_dbg(dev, "\n*************************************************\n");
+}
+
+static void xgbe_phy_init(struct xgbe_prv_data *pdata)
+{
+ mutex_init(&pdata->an_mutex);
+ INIT_WORK(&pdata->an_irq_work, xgbe_an_irq_work);
+ INIT_WORK(&pdata->an_work, xgbe_an_state_machine);
+ pdata->mdio_mmd = MDIO_MMD_PCS;
+
+ /* Initialize supported features */
+ pdata->phy.supported = SUPPORTED_Autoneg;
+ pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+ pdata->phy.supported |= SUPPORTED_Backplane;
+ pdata->phy.supported |= SUPPORTED_10000baseKR_Full;
+ switch (pdata->speed_set) {
+ case XGBE_SPEEDSET_1000_10000:
+ pdata->phy.supported |= SUPPORTED_1000baseKX_Full;
+ break;
+ case XGBE_SPEEDSET_2500_10000:
+ pdata->phy.supported |= SUPPORTED_2500baseX_Full;
+ break;
+ }
- pdata->phydev = NULL;
+ pdata->fec_ability = XMDIO_READ(pdata, MDIO_MMD_PMAPMD,
+ MDIO_PMA_10GBR_FECABLE);
+ pdata->fec_ability &= (MDIO_PMA_10GBR_FECABLE_ABLE |
+ MDIO_PMA_10GBR_FECABLE_ERRABLE);
+ if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
+ pdata->phy.supported |= SUPPORTED_10000baseR_FEC;
- module_put(pdata->phy_module);
- pdata->phy_module = NULL;
+ pdata->phy.advertising = pdata->phy.supported;
- mdiobus_unregister(pdata->mii);
- pdata->mii->priv = NULL;
+ pdata->phy.address = 0;
+
+ pdata->phy.autoneg = AUTONEG_ENABLE;
+ pdata->phy.speed = SPEED_UNKNOWN;
+ pdata->phy.duplex = DUPLEX_UNKNOWN;
+
+ pdata->phy.link = 0;
+
+ pdata->phy.pause_autoneg = pdata->pause_autoneg;
+ pdata->phy.tx_pause = pdata->tx_pause;
+ pdata->phy.rx_pause = pdata->rx_pause;
+
+ /* Fix up Flow Control advertising */
+ pdata->phy.advertising &= ~ADVERTISED_Pause;
+ pdata->phy.advertising &= ~ADVERTISED_Asym_Pause;
+
+ if (pdata->rx_pause) {
+ pdata->phy.advertising |= ADVERTISED_Pause;
+ pdata->phy.advertising |= ADVERTISED_Asym_Pause;
+ }
+
+ if (pdata->tx_pause)
+ pdata->phy.advertising ^= ADVERTISED_Asym_Pause;
+
+ if (netif_msg_drv(pdata))
+ xgbe_dump_phy_registers(pdata);
+}
+
+void xgbe_init_function_ptrs_phy(struct xgbe_phy_if *phy_if)
+{
+ phy_if->phy_init = xgbe_phy_init;
- mdiobus_free(pdata->mii);
- pdata->mii = NULL;
+ phy_if->phy_reset = xgbe_phy_reset;
+ phy_if->phy_start = xgbe_phy_start;
+ phy_if->phy_stop = xgbe_phy_stop;
- DBGPR("<--xgbe_mdio_unregister\n");
+ phy_if->phy_status = xgbe_phy_status;
+ phy_if->phy_config_aneg = xgbe_phy_config_aneg;
}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index e62dfa2deab6..63d72a140053 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -129,7 +129,7 @@
#include <net/dcbnl.h>
#define XGBE_DRV_NAME "amd-xgbe"
-#define XGBE_DRV_VERSION "1.0.0-a"
+#define XGBE_DRV_VERSION "1.0.2"
#define XGBE_DRV_DESC "AMD 10 Gigabit Ethernet Driver"
/* Descriptor related defines */
@@ -178,14 +178,17 @@
#define XGMAC_JUMBO_PACKET_MTU 9000
#define XGMAC_MAX_JUMBO_PACKET 9018
-/* MDIO bus phy name */
-#define XGBE_PHY_NAME "amd_xgbe_phy"
-#define XGBE_PRTAD 0
-
/* Common property names */
#define XGBE_MAC_ADDR_PROPERTY "mac-address"
#define XGBE_PHY_MODE_PROPERTY "phy-mode"
#define XGBE_DMA_IRQS_PROPERTY "amd,per-channel-interrupt"
+#define XGBE_SPEEDSET_PROPERTY "amd,speed-set"
+#define XGBE_BLWC_PROPERTY "amd,serdes-blwc"
+#define XGBE_CDR_RATE_PROPERTY "amd,serdes-cdr-rate"
+#define XGBE_PQ_SKEW_PROPERTY "amd,serdes-pq-skew"
+#define XGBE_TX_AMP_PROPERTY "amd,serdes-tx-amp"
+#define XGBE_DFE_CFG_PROPERTY "amd,serdes-dfe-tap-config"
+#define XGBE_DFE_ENA_PROPERTY "amd,serdes-dfe-tap-enable"
/* Device-tree clock names */
#define XGBE_DMA_CLOCK "dma_clk"
@@ -241,6 +244,49 @@
#define XGBE_RSS_LOOKUP_TABLE_TYPE 0
#define XGBE_RSS_HASH_KEY_TYPE 1
+/* Auto-negotiation */
+#define XGBE_AN_MS_TIMEOUT 500
+#define XGBE_LINK_TIMEOUT 10
+
+#define XGBE_AN_INT_CMPLT 0x01
+#define XGBE_AN_INC_LINK 0x02
+#define XGBE_AN_PG_RCV 0x04
+#define XGBE_AN_INT_MASK 0x07
+
+/* Rate-change complete wait/retry count */
+#define XGBE_RATECHANGE_COUNT 500
+
+/* Default SerDes settings */
+#define XGBE_SPEED_10000_BLWC 0
+#define XGBE_SPEED_10000_CDR 0x7
+#define XGBE_SPEED_10000_PLL 0x1
+#define XGBE_SPEED_10000_PQ 0x12
+#define XGBE_SPEED_10000_RATE 0x0
+#define XGBE_SPEED_10000_TXAMP 0xa
+#define XGBE_SPEED_10000_WORD 0x7
+#define XGBE_SPEED_10000_DFE_TAP_CONFIG 0x1
+#define XGBE_SPEED_10000_DFE_TAP_ENABLE 0x7f
+
+#define XGBE_SPEED_2500_BLWC 1
+#define XGBE_SPEED_2500_CDR 0x2
+#define XGBE_SPEED_2500_PLL 0x0
+#define XGBE_SPEED_2500_PQ 0xa
+#define XGBE_SPEED_2500_RATE 0x1
+#define XGBE_SPEED_2500_TXAMP 0xf
+#define XGBE_SPEED_2500_WORD 0x1
+#define XGBE_SPEED_2500_DFE_TAP_CONFIG 0x3
+#define XGBE_SPEED_2500_DFE_TAP_ENABLE 0x0
+
+#define XGBE_SPEED_1000_BLWC 1
+#define XGBE_SPEED_1000_CDR 0x2
+#define XGBE_SPEED_1000_PLL 0x0
+#define XGBE_SPEED_1000_PQ 0xa
+#define XGBE_SPEED_1000_RATE 0x3
+#define XGBE_SPEED_1000_TXAMP 0xf
+#define XGBE_SPEED_1000_WORD 0x1
+#define XGBE_SPEED_1000_DFE_TAP_CONFIG 0x3
+#define XGBE_SPEED_1000_DFE_TAP_ENABLE 0x0
+
struct xgbe_prv_data;
struct xgbe_packet_data {
@@ -334,8 +380,6 @@ struct xgbe_ring_data {
*/
unsigned int state_saved;
struct {
- unsigned int incomplete;
- unsigned int context_next;
struct sk_buff *skb;
unsigned int len;
unsigned int error;
@@ -414,6 +458,13 @@ struct xgbe_channel {
struct xgbe_ring *rx_ring;
} ____cacheline_aligned;
+enum xgbe_state {
+ XGBE_DOWN,
+ XGBE_LINK,
+ XGBE_LINK_INIT,
+ XGBE_LINK_ERR,
+};
+
enum xgbe_int {
XGMAC_INT_DMA_CH_SR_TI,
XGMAC_INT_DMA_CH_SR_TPS,
@@ -445,6 +496,57 @@ enum xgbe_mtl_fifo_size {
XGMAC_MTL_FIFO_SIZE_256K = 0x3ff,
};
+enum xgbe_speed {
+ XGBE_SPEED_1000 = 0,
+ XGBE_SPEED_2500,
+ XGBE_SPEED_10000,
+ XGBE_SPEEDS,
+};
+
+enum xgbe_an {
+ XGBE_AN_READY = 0,
+ XGBE_AN_PAGE_RECEIVED,
+ XGBE_AN_INCOMPAT_LINK,
+ XGBE_AN_COMPLETE,
+ XGBE_AN_NO_LINK,
+ XGBE_AN_ERROR,
+};
+
+enum xgbe_rx {
+ XGBE_RX_BPA = 0,
+ XGBE_RX_XNP,
+ XGBE_RX_COMPLETE,
+ XGBE_RX_ERROR,
+};
+
+enum xgbe_mode {
+ XGBE_MODE_KR = 0,
+ XGBE_MODE_KX,
+};
+
+enum xgbe_speedset {
+ XGBE_SPEEDSET_1000_10000 = 0,
+ XGBE_SPEEDSET_2500_10000,
+};
+
+struct xgbe_phy {
+ u32 supported;
+ u32 advertising;
+ u32 lp_advertising;
+
+ int address;
+
+ int autoneg;
+ int speed;
+ int duplex;
+
+ int link;
+
+ int pause_autoneg;
+ int tx_pause;
+ int rx_pause;
+};
+
struct xgbe_mmc_stats {
/* Tx Stats */
u64 txoctetcount_gb;
@@ -492,6 +594,11 @@ struct xgbe_mmc_stats {
u64 rxwatchdogerror;
};
+struct xgbe_ext_stats {
+ u64 tx_tso_packets;
+ u64 rx_split_header_packets;
+};
+
struct xgbe_hw_if {
int (*tx_complete)(struct xgbe_ring_desc *);
@@ -591,6 +698,20 @@ struct xgbe_hw_if {
int (*set_rss_lookup_table)(struct xgbe_prv_data *, const u32 *);
};
+struct xgbe_phy_if {
+ /* For initial PHY setup */
+ void (*phy_init)(struct xgbe_prv_data *);
+
+ /* For PHY support when setting device up/down */
+ int (*phy_reset)(struct xgbe_prv_data *);
+ int (*phy_start)(struct xgbe_prv_data *);
+ void (*phy_stop)(struct xgbe_prv_data *);
+
+ /* For PHY support while device is up */
+ void (*phy_status)(struct xgbe_prv_data *);
+ int (*phy_config_aneg)(struct xgbe_prv_data *);
+};
+
struct xgbe_desc_if {
int (*alloc_ring_resources)(struct xgbe_prv_data *);
void (*free_ring_resources)(struct xgbe_prv_data *);
@@ -660,6 +781,9 @@ struct xgbe_prv_data {
/* XGMAC/XPCS related mmio registers */
void __iomem *xgmac_regs; /* XGMAC CSRs */
void __iomem *xpcs_regs; /* XPCS MMD registers */
+ void __iomem *rxtx_regs; /* SerDes Rx/Tx CSRs */
+ void __iomem *sir0_regs; /* SerDes integration registers (1/2) */
+ void __iomem *sir1_regs; /* SerDes integration registers (2/2) */
/* Overall device lock */
spinlock_t lock;
@@ -670,10 +794,14 @@ struct xgbe_prv_data {
/* RSS addressing mutex */
struct mutex rss_mutex;
+ /* Flags representing xgbe_state */
+ unsigned long dev_state;
+
int dev_irq;
unsigned int per_channel_irq;
struct xgbe_hw_if hw_if;
+ struct xgbe_phy_if phy_if;
struct xgbe_desc_if desc_if;
/* AXI DMA settings */
@@ -682,6 +810,11 @@ struct xgbe_prv_data {
unsigned int arcache;
unsigned int awcache;
+ /* Service routine support */
+ struct workqueue_struct *dev_workqueue;
+ struct work_struct service_work;
+ struct timer_list service_timer;
+
/* Rings for Tx/Rx on a DMA channel */
struct xgbe_channel *channel;
unsigned int channel_count;
@@ -729,27 +862,12 @@ struct xgbe_prv_data {
u32 rss_table[XGBE_RSS_MAX_TABLE_SIZE];
u32 rss_options;
- /* MDIO settings */
- struct module *phy_module;
- char *mii_bus_id;
- struct mii_bus *mii;
- int mdio_mmd;
- struct phy_device *phydev;
- int default_autoneg;
- int default_speed;
-
- /* Current PHY settings */
- phy_interface_t phy_mode;
- int phy_link;
- int phy_speed;
- unsigned int phy_tx_pause;
- unsigned int phy_rx_pause;
-
/* Netdev related settings */
unsigned char mac_addr[ETH_ALEN];
netdev_features_t netdev_features;
struct napi_struct napi;
struct xgbe_mmc_stats mmc_stats;
+ struct xgbe_ext_stats ext_stats;
/* Filtering support */
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
@@ -787,6 +905,54 @@ struct xgbe_prv_data {
/* Keeps track of power mode */
unsigned int power_down;
+ /* Network interface message level setting */
+ u32 msg_enable;
+
+ /* Current PHY settings */
+ phy_interface_t phy_mode;
+ int phy_link;
+ int phy_speed;
+
+ /* MDIO/PHY related settings */
+ struct xgbe_phy phy;
+ int mdio_mmd;
+ unsigned long link_check;
+
+ char an_name[IFNAMSIZ + 32];
+ struct workqueue_struct *an_workqueue;
+
+ int an_irq;
+ struct work_struct an_irq_work;
+
+ unsigned int speed_set;
+
+ /* SerDes UEFI configurable settings.
+ * Switching between modes/speeds requires new values for some
+ * SerDes settings. The values can be supplied as device
+ * properties in array format. The first array entry is for
+ * 1GbE, second for 2.5GbE and third for 10GbE
+ */
+ u32 serdes_blwc[XGBE_SPEEDS];
+ u32 serdes_cdr_rate[XGBE_SPEEDS];
+ u32 serdes_pq_skew[XGBE_SPEEDS];
+ u32 serdes_tx_amp[XGBE_SPEEDS];
+ u32 serdes_dfe_tap_cfg[XGBE_SPEEDS];
+ u32 serdes_dfe_tap_ena[XGBE_SPEEDS];
+
+ /* Auto-negotiation state machine support */
+ struct mutex an_mutex;
+ enum xgbe_an an_result;
+ enum xgbe_an an_state;
+ enum xgbe_rx kr_state;
+ enum xgbe_rx kx_state;
+ struct work_struct an_work;
+ unsigned int an_supported;
+ unsigned int parallel_detect;
+ unsigned int fec_ability;
+ unsigned long an_start;
+
+ unsigned int lpm_ctrl; /* CTRL1 for resume */
+
#ifdef CONFIG_DEBUG_FS
struct dentry *xgbe_debugfs;
@@ -800,6 +966,7 @@ struct xgbe_prv_data {
/* Function prototypes*/
void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *);
+void xgbe_init_function_ptrs_phy(struct xgbe_phy_if *);
void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *);
struct net_device_ops *xgbe_get_netdev_ops(void);
struct ethtool_ops *xgbe_get_ethtool_ops(void);
@@ -807,14 +974,11 @@ struct ethtool_ops *xgbe_get_ethtool_ops(void);
const struct dcbnl_rtnl_ops *xgbe_get_dcbnl_ops(void);
#endif
-int xgbe_mdio_register(struct xgbe_prv_data *);
-void xgbe_mdio_unregister(struct xgbe_prv_data *);
-void xgbe_dump_phy_registers(struct xgbe_prv_data *);
void xgbe_ptp_register(struct xgbe_prv_data *);
void xgbe_ptp_unregister(struct xgbe_prv_data *);
-void xgbe_dump_tx_desc(struct xgbe_ring *, unsigned int, unsigned int,
- unsigned int);
-void xgbe_dump_rx_desc(struct xgbe_ring *, struct xgbe_ring_desc *,
+void xgbe_dump_tx_desc(struct xgbe_prv_data *, struct xgbe_ring *,
+ unsigned int, unsigned int, unsigned int);
+void xgbe_dump_rx_desc(struct xgbe_prv_data *, struct xgbe_ring *,
unsigned int);
void xgbe_print_pkt(struct net_device *, struct sk_buff *, bool);
void xgbe_get_all_hw_features(struct xgbe_prv_data *);
@@ -831,18 +995,6 @@ static inline void xgbe_debugfs_init(struct xgbe_prv_data *pdata) {}
static inline void xgbe_debugfs_exit(struct xgbe_prv_data *pdata) {}
#endif /* CONFIG_DEBUG_FS */
-/* NOTE: Uncomment for TX and RX DESCRIPTOR DUMP in KERNEL LOG */
-#if 0
-#define XGMAC_ENABLE_TX_DESC_DUMP
-#define XGMAC_ENABLE_RX_DESC_DUMP
-#endif
-
-/* NOTE: Uncomment for TX and RX PACKET DUMP in KERNEL LOG */
-#if 0
-#define XGMAC_ENABLE_TX_PKT_DUMP
-#define XGMAC_ENABLE_RX_PKT_DUMP
-#endif
-
/* NOTE: Uncomment for function trace log messages in KERNEL LOG */
#if 0
#define YDEBUG
@@ -852,10 +1004,8 @@ static inline void xgbe_debugfs_exit(struct xgbe_prv_data *pdata) {}
/* For debug prints */
#ifdef YDEBUG
#define DBGPR(x...) pr_alert(x)
-#define DBGPHY_REGS(x...) xgbe_dump_phy_registers(x)
#else
#define DBGPR(x...) do { } while (0)
-#define DBGPHY_REGS(x...) do { } while (0)
#endif
#ifdef YDEBUG_MDIO
diff --git a/drivers/net/ethernet/apm/xgene/Makefile b/drivers/net/ethernet/apm/xgene/Makefile
index 68be565548c0..700b5abe5de5 100644
--- a/drivers/net/ethernet/apm/xgene/Makefile
+++ b/drivers/net/ethernet/apm/xgene/Makefile
@@ -3,5 +3,5 @@
#
xgene-enet-objs := xgene_enet_hw.o xgene_enet_sgmac.o xgene_enet_xgmac.o \
- xgene_enet_main.o xgene_enet_ethtool.o
+ xgene_enet_main.o xgene_enet_ring2.o xgene_enet_ethtool.o
obj-$(CONFIG_NET_XGENE) += xgene-enet.o
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
index b927021c6c40..a626c4315a89 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
@@ -87,10 +87,11 @@ static void xgene_enet_ring_rd32(struct xgene_enet_desc_ring *ring,
static void xgene_enet_write_ring_state(struct xgene_enet_desc_ring *ring)
{
+ struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
int i;
xgene_enet_ring_wr32(ring, CSR_RING_CONFIG, ring->num);
- for (i = 0; i < NUM_RING_CONFIG; i++) {
+ for (i = 0; i < pdata->ring_ops->num_ring_config; i++) {
xgene_enet_ring_wr32(ring, CSR_RING_WR_BASE + (i * 4),
ring->state[i]);
}
@@ -98,7 +99,7 @@ static void xgene_enet_write_ring_state(struct xgene_enet_desc_ring *ring)
static void xgene_enet_clr_ring_state(struct xgene_enet_desc_ring *ring)
{
- memset(ring->state, 0, sizeof(u32) * NUM_RING_CONFIG);
+ memset(ring->state, 0, sizeof(ring->state));
xgene_enet_write_ring_state(ring);
}
@@ -141,8 +142,8 @@ static void xgene_enet_clr_desc_ring_id(struct xgene_enet_desc_ring *ring)
xgene_enet_ring_wr32(ring, CSR_RING_ID_BUF, 0);
}
-struct xgene_enet_desc_ring *xgene_enet_setup_ring(
- struct xgene_enet_desc_ring *ring)
+static struct xgene_enet_desc_ring *xgene_enet_setup_ring(
+ struct xgene_enet_desc_ring *ring)
{
u32 size = ring->size;
u32 i, data;
@@ -168,7 +169,7 @@ struct xgene_enet_desc_ring *xgene_enet_setup_ring(
return ring;
}
-void xgene_enet_clear_ring(struct xgene_enet_desc_ring *ring)
+static void xgene_enet_clear_ring(struct xgene_enet_desc_ring *ring)
{
u32 data;
bool is_bufpool;
@@ -186,6 +187,22 @@ out:
xgene_enet_clr_ring_state(ring);
}
+static void xgene_enet_wr_cmd(struct xgene_enet_desc_ring *ring, int count)
+{
+ iowrite32(count, ring->cmd);
+}
+
+static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring)
+{
+ u32 __iomem *cmd_base = ring->cmd_base;
+ u32 ring_state, num_msgs;
+
+ ring_state = ioread32(&cmd_base[1]);
+ num_msgs = GET_VAL(NUMMSGSINQ, ring_state);
+
+ return num_msgs;
+}
+
void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring,
struct xgene_enet_pdata *pdata,
enum xgene_enet_err_code status)
@@ -593,7 +610,7 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
if (!xgene_ring_mgr_init(pdata))
return -ENODEV;
- if (pdata->clk) {
+ if (!IS_ERR(pdata->clk)) {
clk_prepare_enable(pdata->clk);
clk_disable_unprepare(pdata->clk);
clk_prepare_enable(pdata->clk);
@@ -612,7 +629,8 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
{
- clk_disable_unprepare(pdata->clk);
+ if (!IS_ERR(pdata->clk))
+ clk_disable_unprepare(pdata->clk);
}
static int xgene_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
@@ -734,7 +752,7 @@ static int xgene_mdiobus_register(struct xgene_enet_pdata *pdata,
if (ret)
return -EINVAL;
- phy = get_phy_device(mdio, phy_id, true);
+ phy = get_phy_device(mdio, phy_id, false);
if (!phy || IS_ERR(phy))
return -EIO;
@@ -803,3 +821,12 @@ struct xgene_port_ops xgene_gport_ops = {
.cle_bypass = xgene_enet_cle_bypass,
.shutdown = xgene_gport_shutdown,
};
+
+struct xgene_ring_ops xgene_ring1_ops = {
+ .num_ring_config = NUM_RING_CONFIG,
+ .num_ring_id_shift = 6,
+ .setup = xgene_enet_setup_ring,
+ .clear = xgene_enet_clear_ring,
+ .wr_cmd = xgene_enet_wr_cmd,
+ .len = xgene_enet_ring_len,
+};
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
index d9bc89d69266..541bed056012 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
@@ -26,6 +26,7 @@
struct xgene_enet_pdata;
struct xgene_enet_stats;
+struct xgene_enet_desc_ring;
/* clears and then set bits */
static inline void xgene_set_bits(u32 *dst, u32 val, u32 start, u32 len)
@@ -101,8 +102,8 @@ enum xgene_enet_rm {
#define BLOCK_ETH_CSR_OFFSET 0x2000
#define BLOCK_ETH_RING_IF_OFFSET 0x9000
+#define BLOCK_ETH_CLKRST_CSR_OFFSET 0xc000
#define BLOCK_ETH_DIAG_CSR_OFFSET 0xD000
-
#define BLOCK_ETH_MAC_OFFSET 0x0000
#define BLOCK_ETH_MAC_CSR_OFFSET 0x2800
@@ -261,6 +262,7 @@ enum xgene_enet_ring_type {
enum xgene_ring_owner {
RING_OWNER_ETH0,
+ RING_OWNER_ETH1,
RING_OWNER_CPU = 15,
RING_OWNER_INVALID
};
@@ -314,9 +316,6 @@ static inline u16 xgene_enet_get_numslots(u16 id, u32 size)
size / WORK_DESC_SIZE;
}
-struct xgene_enet_desc_ring *xgene_enet_setup_ring(
- struct xgene_enet_desc_ring *ring);
-void xgene_enet_clear_ring(struct xgene_enet_desc_ring *ring);
void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring,
struct xgene_enet_pdata *pdata,
enum xgene_enet_err_code status);
@@ -327,5 +326,6 @@ bool xgene_ring_mgr_init(struct xgene_enet_pdata *p);
extern struct xgene_mac_ops xgene_gmac_ops;
extern struct xgene_port_ops xgene_gport_ops;
+extern struct xgene_ring_ops xgene_ring1_ops;
#endif /* __XGENE_ENET_HW_H__ */
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
index 40d3530d7f30..95153b234c71 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
@@ -28,6 +28,9 @@
#define RES_RING_CSR 1
#define RES_RING_CMD 2
+static const struct of_device_id xgene_enet_of_match[];
+static const struct acpi_device_id xgene_enet_acpi_match[];
+
static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool)
{
struct xgene_enet_raw_desc16 *raw_desc;
@@ -48,6 +51,7 @@ static int xgene_enet_refill_bufpool(struct xgene_enet_desc_ring *buf_pool,
{
struct sk_buff *skb;
struct xgene_enet_raw_desc16 *raw_desc;
+ struct xgene_enet_pdata *pdata;
struct net_device *ndev;
struct device *dev;
dma_addr_t dma_addr;
@@ -58,6 +62,7 @@ static int xgene_enet_refill_bufpool(struct xgene_enet_desc_ring *buf_pool,
ndev = buf_pool->ndev;
dev = ndev_to_dev(buf_pool->ndev);
+ pdata = netdev_priv(ndev);
bufdatalen = BUF_LEN_CODE_2K | (SKB_BUFFER_SIZE & GENMASK(11, 0));
len = XGENE_ENET_MAX_MTU;
@@ -82,7 +87,7 @@ static int xgene_enet_refill_bufpool(struct xgene_enet_desc_ring *buf_pool,
tail = (tail + 1) & slots;
}
- iowrite32(nbuf, buf_pool->cmd);
+ pdata->ring_ops->wr_cmd(buf_pool, nbuf);
buf_pool->tail = tail;
return 0;
@@ -102,26 +107,16 @@ static u8 xgene_enet_hdr_len(const void *data)
return (eth->h_proto == htons(ETH_P_8021Q)) ? VLAN_ETH_HLEN : ETH_HLEN;
}
-static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring)
-{
- u32 __iomem *cmd_base = ring->cmd_base;
- u32 ring_state, num_msgs;
-
- ring_state = ioread32(&cmd_base[1]);
- num_msgs = ring_state & CREATE_MASK(NUMMSGSINQ_POS, NUMMSGSINQ_LEN);
-
- return num_msgs >> NUMMSGSINQ_POS;
-}
-
static void xgene_enet_delete_bufpool(struct xgene_enet_desc_ring *buf_pool)
{
+ struct xgene_enet_pdata *pdata = netdev_priv(buf_pool->ndev);
struct xgene_enet_raw_desc16 *raw_desc;
u32 slots = buf_pool->slots - 1;
u32 tail = buf_pool->tail;
u32 userinfo;
int i, len;
- len = xgene_enet_ring_len(buf_pool);
+ len = pdata->ring_ops->len(buf_pool);
for (i = 0; i < len; i++) {
tail = (tail - 1) & slots;
raw_desc = &buf_pool->raw_desc16[tail];
@@ -131,7 +126,7 @@ static void xgene_enet_delete_bufpool(struct xgene_enet_desc_ring *buf_pool)
dev_kfree_skb_any(buf_pool->rx_skb[userinfo]);
}
- iowrite32(-len, buf_pool->cmd);
+ pdata->ring_ops->wr_cmd(buf_pool, -len);
buf_pool->tail = tail;
}
@@ -263,8 +258,8 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb,
struct xgene_enet_desc_ring *cp_ring = tx_ring->cp_ring;
u32 tx_level, cq_level;
- tx_level = xgene_enet_ring_len(tx_ring);
- cq_level = xgene_enet_ring_len(cp_ring);
+ tx_level = pdata->ring_ops->len(tx_ring);
+ cq_level = pdata->ring_ops->len(cp_ring);
if (unlikely(tx_level > pdata->tx_qcnt_hi ||
cq_level > pdata->cp_qcnt_hi)) {
netif_stop_queue(ndev);
@@ -276,7 +271,7 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
- iowrite32(1, tx_ring->cmd);
+ pdata->ring_ops->wr_cmd(tx_ring, 1);
skb_tx_timestamp(skb);
tx_ring->tail = (tx_ring->tail + 1) & (tx_ring->slots - 1);
@@ -389,11 +384,11 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring,
} while (--budget);
if (likely(count)) {
- iowrite32(-count, ring->cmd);
+ pdata->ring_ops->wr_cmd(ring, -count);
ring->head = head;
if (netif_queue_stopped(ring->ndev)) {
- if (xgene_enet_ring_len(ring) < pdata->cp_qcnt_low)
+ if (pdata->ring_ops->len(ring) < pdata->cp_qcnt_low)
netif_wake_queue(ring->ndev);
}
}
@@ -510,6 +505,7 @@ static int xgene_enet_open(struct net_device *ndev)
else
schedule_delayed_work(&pdata->link_work, PHY_POLL_LINK_OFF);
+ netif_carrier_off(ndev);
netif_start_queue(ndev);
return ret;
@@ -545,7 +541,7 @@ static void xgene_enet_delete_ring(struct xgene_enet_desc_ring *ring)
pdata = netdev_priv(ring->ndev);
dev = ndev_to_dev(ring->ndev);
- xgene_enet_clear_ring(ring);
+ pdata->ring_ops->clear(ring);
dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma);
}
@@ -598,15 +594,17 @@ static int xgene_enet_get_ring_size(struct device *dev,
static void xgene_enet_free_desc_ring(struct xgene_enet_desc_ring *ring)
{
+ struct xgene_enet_pdata *pdata;
struct device *dev;
if (!ring)
return;
dev = ndev_to_dev(ring->ndev);
+ pdata = netdev_priv(ring->ndev);
if (ring->desc_addr) {
- xgene_enet_clear_ring(ring);
+ pdata->ring_ops->clear(ring);
dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma);
}
devm_kfree(dev, ring);
@@ -637,6 +635,25 @@ static void xgene_enet_free_desc_rings(struct xgene_enet_pdata *pdata)
}
}
+static bool is_irq_mbox_required(struct xgene_enet_pdata *pdata,
+ struct xgene_enet_desc_ring *ring)
+{
+ if ((pdata->enet_id == XGENE_ENET2) &&
+ (xgene_enet_ring_owner(ring->id) == RING_OWNER_CPU)) {
+ return true;
+ }
+
+ return false;
+}
+
+static void __iomem *xgene_enet_ring_cmd_base(struct xgene_enet_pdata *pdata,
+ struct xgene_enet_desc_ring *ring)
+{
+ u8 num_ring_id_shift = pdata->ring_ops->num_ring_id_shift;
+
+ return pdata->ring_cmd_addr + (ring->num << num_ring_id_shift);
+}
+
static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring(
struct net_device *ndev, u32 ring_num,
enum xgene_enet_ring_cfgsize cfgsize, u32 ring_id)
@@ -668,9 +685,20 @@ static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring(
}
ring->size = size;
- ring->cmd_base = pdata->ring_cmd_addr + (ring->num << 6);
+ if (is_irq_mbox_required(pdata, ring)) {
+ ring->irq_mbox_addr = dma_zalloc_coherent(dev, INTR_MBOX_SIZE,
+ &ring->irq_mbox_dma, GFP_KERNEL);
+ if (!ring->irq_mbox_addr) {
+ dma_free_coherent(dev, size, ring->desc_addr,
+ ring->dma);
+ devm_kfree(dev, ring);
+ return NULL;
+ }
+ }
+
+ ring->cmd_base = xgene_enet_ring_cmd_base(pdata, ring);
ring->cmd = ring->cmd_base + INC_DEC_CMD_ADDR;
- ring = xgene_enet_setup_ring(ring);
+ ring = pdata->ring_ops->setup(ring);
netdev_dbg(ndev, "ring info: num=%d size=%d id=%d slots=%d\n",
ring->num, ring->size, ring->id, ring->slots);
@@ -682,12 +710,34 @@ static u16 xgene_enet_get_ring_id(enum xgene_ring_owner owner, u8 bufnum)
return (owner << 6) | (bufnum & GENMASK(5, 0));
}
+static enum xgene_ring_owner xgene_derive_ring_owner(struct xgene_enet_pdata *p)
+{
+ enum xgene_ring_owner owner;
+
+ if (p->enet_id == XGENE_ENET1) {
+ switch (p->phy_mode) {
+ case PHY_INTERFACE_MODE_SGMII:
+ owner = RING_OWNER_ETH0;
+ break;
+ default:
+ owner = (!p->port_id) ? RING_OWNER_ETH0 :
+ RING_OWNER_ETH1;
+ break;
+ }
+ } else {
+ owner = (!p->port_id) ? RING_OWNER_ETH0 : RING_OWNER_ETH1;
+ }
+
+ return owner;
+}
+
static int xgene_enet_create_desc_rings(struct net_device *ndev)
{
struct xgene_enet_pdata *pdata = netdev_priv(ndev);
struct device *dev = ndev_to_dev(ndev);
struct xgene_enet_desc_ring *rx_ring, *tx_ring, *cp_ring;
struct xgene_enet_desc_ring *buf_pool = NULL;
+ enum xgene_ring_owner owner;
u8 cpu_bufnum = pdata->cpu_bufnum;
u8 eth_bufnum = pdata->eth_bufnum;
u8 bp_bufnum = pdata->bp_bufnum;
@@ -696,6 +746,7 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
int ret;
/* allocate rx descriptor ring */
+ owner = xgene_derive_ring_owner(pdata);
ring_id = xgene_enet_get_ring_id(RING_OWNER_CPU, cpu_bufnum++);
rx_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
RING_CFGSIZE_16KB, ring_id);
@@ -705,7 +756,8 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
}
/* allocate buffer pool for receiving packets */
- ring_id = xgene_enet_get_ring_id(RING_OWNER_ETH0, bp_bufnum++);
+ owner = xgene_derive_ring_owner(pdata);
+ ring_id = xgene_enet_get_ring_id(owner, bp_bufnum++);
buf_pool = xgene_enet_create_desc_ring(ndev, ring_num++,
RING_CFGSIZE_2KB, ring_id);
if (!buf_pool) {
@@ -734,7 +786,8 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
pdata->rx_ring = rx_ring;
/* allocate tx descriptor ring */
- ring_id = xgene_enet_get_ring_id(RING_OWNER_ETH0, eth_bufnum++);
+ owner = xgene_derive_ring_owner(pdata);
+ ring_id = xgene_enet_get_ring_id(owner, eth_bufnum++);
tx_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
RING_CFGSIZE_16KB, ring_id);
if (!tx_ring) {
@@ -818,20 +871,38 @@ static const struct net_device_ops xgene_ndev_ops = {
.ndo_set_mac_address = xgene_enet_set_mac_address,
};
-static int xgene_get_port_id(struct device *dev, struct xgene_enet_pdata *pdata)
+#ifdef CONFIG_ACPI
+static int xgene_get_port_id_acpi(struct device *dev,
+ struct xgene_enet_pdata *pdata)
+{
+ acpi_status status;
+ u64 temp;
+
+ status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_SUN", NULL, &temp);
+ if (ACPI_FAILURE(status)) {
+ pdata->port_id = 0;
+ } else {
+ pdata->port_id = temp;
+ }
+
+ return 0;
+}
+#endif
+
+static int xgene_get_port_id_dt(struct device *dev, struct xgene_enet_pdata *pdata)
{
u32 id = 0;
int ret;
- ret = device_property_read_u32(dev, "port-id", &id);
- if (!ret && id > 1) {
- dev_err(dev, "Incorrect port-id specified\n");
- return -ENODEV;
+ ret = of_property_read_u32(dev->of_node, "port-id", &id);
+ if (ret) {
+ pdata->port_id = 0;
+ ret = 0;
+ } else {
+ pdata->port_id = id & BIT(0);
}
- pdata->port_id = id;
-
- return 0;
+ return ret;
}
static int xgene_get_mac_address(struct device *dev,
@@ -876,6 +947,7 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
struct device *dev;
struct resource *res;
void __iomem *base_addr;
+ u32 offset;
int ret;
pdev = pdata->pdev;
@@ -917,7 +989,12 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
return -ENOMEM;
}
- ret = xgene_get_port_id(dev, pdata);
+ if (dev->of_node)
+ ret = xgene_get_port_id_dt(dev, pdata);
+#ifdef CONFIG_ACPI
+ else
+ ret = xgene_get_port_id_acpi(dev, pdata);
+#endif
if (ret)
return ret;
@@ -949,27 +1026,35 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
if (pdata->phy_mode != PHY_INTERFACE_MODE_RGMII) {
ret = platform_get_irq(pdev, 1);
if (ret <= 0) {
- dev_err(dev, "Unable to get ENET Tx completion IRQ\n");
- ret = ret ? : -ENXIO;
- return ret;
+ pdata->cq_cnt = 0;
+ dev_info(dev, "Unable to get Tx completion IRQ,"
+ "using Rx IRQ instead\n");
+ } else {
+ pdata->cq_cnt = XGENE_MAX_TXC_RINGS;
+ pdata->txc_irq = ret;
}
- pdata->txc_irq = ret;
}
pdata->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pdata->clk)) {
/* Firmware may have set up the clock already. */
- pdata->clk = NULL;
+ dev_info(dev, "clocks have been setup already\n");
}
- base_addr = pdata->base_addr - (pdata->port_id * MAC_OFFSET);
+ if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII)
+ base_addr = pdata->base_addr - (pdata->port_id * MAC_OFFSET);
+ else
+ base_addr = pdata->base_addr;
pdata->eth_csr_addr = base_addr + BLOCK_ETH_CSR_OFFSET;
pdata->eth_ring_if_addr = base_addr + BLOCK_ETH_RING_IF_OFFSET;
pdata->eth_diag_csr_addr = base_addr + BLOCK_ETH_DIAG_CSR_OFFSET;
if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII ||
pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
pdata->mcx_mac_addr = pdata->base_addr + BLOCK_ETH_MAC_OFFSET;
- pdata->mcx_mac_csr_addr = base_addr + BLOCK_ETH_MAC_CSR_OFFSET;
+ offset = (pdata->enet_id == XGENE_ENET1) ?
+ BLOCK_ETH_MAC_CSR_OFFSET :
+ X2_BLOCK_ETH_MAC_CSR_OFFSET;
+ pdata->mcx_mac_csr_addr = base_addr + offset;
} else {
pdata->mcx_mac_addr = base_addr + BLOCK_AXG_MAC_OFFSET;
pdata->mcx_mac_csr_addr = base_addr + BLOCK_AXG_MAC_CSR_OFFSET;
@@ -1024,33 +1109,52 @@ static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata)
pdata->mac_ops = &xgene_sgmac_ops;
pdata->port_ops = &xgene_sgport_ops;
pdata->rm = RM1;
- pdata->cq_cnt = XGENE_MAX_TXC_RINGS;
break;
default:
pdata->mac_ops = &xgene_xgmac_ops;
pdata->port_ops = &xgene_xgport_ops;
pdata->rm = RM0;
- pdata->cq_cnt = XGENE_MAX_TXC_RINGS;
break;
}
- switch (pdata->port_id) {
- case 0:
- pdata->cpu_bufnum = START_CPU_BUFNUM_0;
- pdata->eth_bufnum = START_ETH_BUFNUM_0;
- pdata->bp_bufnum = START_BP_BUFNUM_0;
- pdata->ring_num = START_RING_NUM_0;
- break;
- case 1:
- pdata->cpu_bufnum = START_CPU_BUFNUM_1;
- pdata->eth_bufnum = START_ETH_BUFNUM_1;
- pdata->bp_bufnum = START_BP_BUFNUM_1;
- pdata->ring_num = START_RING_NUM_1;
- break;
- default:
- break;
+ if (pdata->enet_id == XGENE_ENET1) {
+ switch (pdata->port_id) {
+ case 0:
+ pdata->cpu_bufnum = START_CPU_BUFNUM_0;
+ pdata->eth_bufnum = START_ETH_BUFNUM_0;
+ pdata->bp_bufnum = START_BP_BUFNUM_0;
+ pdata->ring_num = START_RING_NUM_0;
+ break;
+ case 1:
+ pdata->cpu_bufnum = START_CPU_BUFNUM_1;
+ pdata->eth_bufnum = START_ETH_BUFNUM_1;
+ pdata->bp_bufnum = START_BP_BUFNUM_1;
+ pdata->ring_num = START_RING_NUM_1;
+ break;
+ default:
+ break;
+ }
+ pdata->ring_ops = &xgene_ring1_ops;
+ } else {
+ switch (pdata->port_id) {
+ case 0:
+ pdata->cpu_bufnum = X2_START_CPU_BUFNUM_0;
+ pdata->eth_bufnum = X2_START_ETH_BUFNUM_0;
+ pdata->bp_bufnum = X2_START_BP_BUFNUM_0;
+ pdata->ring_num = X2_START_RING_NUM_0;
+ break;
+ case 1:
+ pdata->cpu_bufnum = X2_START_CPU_BUFNUM_1;
+ pdata->eth_bufnum = X2_START_ETH_BUFNUM_1;
+ pdata->bp_bufnum = X2_START_BP_BUFNUM_1;
+ pdata->ring_num = X2_START_RING_NUM_1;
+ break;
+ default:
+ break;
+ }
+ pdata->rm = RM0;
+ pdata->ring_ops = &xgene_ring2_ops;
}
-
}
static void xgene_enet_napi_add(struct xgene_enet_pdata *pdata)
@@ -1086,6 +1190,7 @@ static int xgene_enet_probe(struct platform_device *pdev)
struct xgene_enet_pdata *pdata;
struct device *dev = &pdev->dev;
struct xgene_mac_ops *mac_ops;
+ const struct of_device_id *of_id;
int ret;
ndev = alloc_etherdev(sizeof(struct xgene_enet_pdata));
@@ -1104,6 +1209,24 @@ static int xgene_enet_probe(struct platform_device *pdev)
NETIF_F_GSO |
NETIF_F_GRO;
+ of_id = of_match_device(xgene_enet_of_match, &pdev->dev);
+ if (of_id) {
+ pdata->enet_id = (enum xgene_enet_id)of_id->data;
+ }
+#ifdef CONFIG_ACPI
+ else {
+ const struct acpi_device_id *acpi_id;
+
+ acpi_id = acpi_match_device(xgene_enet_acpi_match, &pdev->dev);
+ if (acpi_id)
+ pdata->enet_id = (enum xgene_enet_id) acpi_id->driver_data;
+ }
+#endif
+ if (!pdata->enet_id) {
+ free_netdev(ndev);
+ return -ENODEV;
+ }
+
ret = xgene_enet_get_resources(pdata);
if (ret)
goto err;
@@ -1165,9 +1288,11 @@ static int xgene_enet_remove(struct platform_device *pdev)
#ifdef CONFIG_ACPI
static const struct acpi_device_id xgene_enet_acpi_match[] = {
- { "APMC0D05", },
- { "APMC0D30", },
- { "APMC0D31", },
+ { "APMC0D05", XGENE_ENET1},
+ { "APMC0D30", XGENE_ENET1},
+ { "APMC0D31", XGENE_ENET1},
+ { "APMC0D26", XGENE_ENET2},
+ { "APMC0D25", XGENE_ENET2},
{ }
};
MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
@@ -1175,9 +1300,11 @@ MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
#ifdef CONFIG_OF
static const struct of_device_id xgene_enet_of_match[] = {
- {.compatible = "apm,xgene-enet",},
- {.compatible = "apm,xgene1-sgenet",},
- {.compatible = "apm,xgene1-xgenet",},
+ {.compatible = "apm,xgene-enet", .data = (void *)XGENE_ENET1},
+ {.compatible = "apm,xgene1-sgenet", .data = (void *)XGENE_ENET1},
+ {.compatible = "apm,xgene1-xgenet", .data = (void *)XGENE_ENET1},
+ {.compatible = "apm,xgene2-sgenet", .data = (void *)XGENE_ENET2},
+ {.compatible = "apm,xgene2-xgenet", .data = (void *)XGENE_ENET2},
{},
};
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
index 8f3d232b09bc..1c85fc87703a 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
@@ -35,6 +35,7 @@
#include <linux/if_vlan.h>
#include <linux/phy.h>
#include "xgene_enet_hw.h"
+#include "xgene_enet_ring2.h"
#define XGENE_DRV_VERSION "v1.0"
#define XGENE_ENET_MAX_MTU 1536
@@ -51,12 +52,26 @@
#define START_BP_BUFNUM_1 0x2A
#define START_RING_NUM_1 264
+#define X2_START_CPU_BUFNUM_0 0
+#define X2_START_ETH_BUFNUM_0 0
+#define X2_START_BP_BUFNUM_0 0x20
+#define X2_START_RING_NUM_0 0
+#define X2_START_CPU_BUFNUM_1 0xc
+#define X2_START_ETH_BUFNUM_1 0
+#define X2_START_BP_BUFNUM_1 0x20
+#define X2_START_RING_NUM_1 256
+
#define IRQ_ID_SIZE 16
#define XGENE_MAX_TXC_RINGS 1
#define PHY_POLL_LINK_ON (10 * HZ)
#define PHY_POLL_LINK_OFF (PHY_POLL_LINK_ON / 5)
+enum xgene_enet_id {
+ XGENE_ENET1 = 1,
+ XGENE_ENET2
+};
+
/* software context of a descriptor ring */
struct xgene_enet_desc_ring {
struct net_device *ndev;
@@ -68,10 +83,12 @@ struct xgene_enet_desc_ring {
u16 irq;
char irq_name[IRQ_ID_SIZE];
u32 size;
- u32 state[NUM_RING_CONFIG];
+ u32 state[X2_NUM_RING_CONFIG];
void __iomem *cmd_base;
void __iomem *cmd;
dma_addr_t dma;
+ dma_addr_t irq_mbox_dma;
+ void *irq_mbox_addr;
u16 dst_ring_num;
u8 nbufpool;
struct sk_buff *(*rx_skb);
@@ -105,6 +122,15 @@ struct xgene_port_ops {
void (*shutdown)(struct xgene_enet_pdata *pdata);
};
+struct xgene_ring_ops {
+ u8 num_ring_config;
+ u8 num_ring_id_shift;
+ struct xgene_enet_desc_ring * (*setup)(struct xgene_enet_desc_ring *);
+ void (*clear)(struct xgene_enet_desc_ring *);
+ void (*wr_cmd)(struct xgene_enet_desc_ring *, int);
+ u32 (*len)(struct xgene_enet_desc_ring *);
+};
+
/* ethernet private data */
struct xgene_enet_pdata {
struct net_device *ndev;
@@ -113,6 +139,7 @@ struct xgene_enet_pdata {
int phy_speed;
struct clk *clk;
struct platform_device *pdev;
+ enum xgene_enet_id enet_id;
struct xgene_enet_desc_ring *tx_ring;
struct xgene_enet_desc_ring *rx_ring;
char *dev_name;
@@ -136,6 +163,7 @@ struct xgene_enet_pdata {
struct rtnl_link_stats64 stats;
struct xgene_mac_ops *mac_ops;
struct xgene_port_ops *port_ops;
+ struct xgene_ring_ops *ring_ops;
struct delayed_work link_work;
u32 port_id;
u8 cpu_bufnum;
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ring2.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ring2.c
new file mode 100644
index 000000000000..0b6896bb351e
--- /dev/null
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ring2.c
@@ -0,0 +1,200 @@
+/* Applied Micro X-Gene SoC Ethernet Driver
+ *
+ * Copyright (c) 2015, Applied Micro Circuits Corporation
+ * Author: Iyappan Subramanian <isubramanian@apm.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "xgene_enet_main.h"
+#include "xgene_enet_hw.h"
+#include "xgene_enet_ring2.h"
+
+static void xgene_enet_ring_init(struct xgene_enet_desc_ring *ring)
+{
+ u32 *ring_cfg = ring->state;
+ u64 addr = ring->dma;
+
+ if (xgene_enet_ring_owner(ring->id) == RING_OWNER_CPU) {
+ ring_cfg[0] |= SET_VAL(X2_INTLINE, ring->id & RING_BUFNUM_MASK);
+ ring_cfg[3] |= SET_BIT(X2_DEQINTEN);
+ }
+ ring_cfg[0] |= SET_VAL(X2_CFGCRID, 1);
+
+ addr >>= 8;
+ ring_cfg[2] |= QCOHERENT | SET_VAL(RINGADDRL, addr);
+
+ addr >>= 27;
+ ring_cfg[3] |= SET_VAL(RINGSIZE, ring->cfgsize)
+ | ACCEPTLERR
+ | SET_VAL(RINGADDRH, addr);
+ ring_cfg[4] |= SET_VAL(X2_SELTHRSH, 1);
+ ring_cfg[5] |= SET_BIT(X2_QBASE_AM) | SET_BIT(X2_MSG_AM);
+}
+
+static void xgene_enet_ring_set_type(struct xgene_enet_desc_ring *ring)
+{
+ u32 *ring_cfg = ring->state;
+ bool is_bufpool;
+ u32 val;
+
+ is_bufpool = xgene_enet_is_bufpool(ring->id);
+ val = (is_bufpool) ? RING_BUFPOOL : RING_REGULAR;
+ ring_cfg[4] |= SET_VAL(X2_RINGTYPE, val);
+ if (is_bufpool)
+ ring_cfg[3] |= SET_VAL(RINGMODE, BUFPOOL_MODE);
+}
+
+static void xgene_enet_ring_set_recombbuf(struct xgene_enet_desc_ring *ring)
+{
+ u32 *ring_cfg = ring->state;
+
+ ring_cfg[3] |= RECOMBBUF;
+ ring_cfg[4] |= SET_VAL(X2_RECOMTIMEOUT, 0x7);
+}
+
+static void xgene_enet_ring_wr32(struct xgene_enet_desc_ring *ring,
+ u32 offset, u32 data)
+{
+ struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
+
+ iowrite32(data, pdata->ring_csr_addr + offset);
+}
+
+static void xgene_enet_write_ring_state(struct xgene_enet_desc_ring *ring)
+{
+ struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
+ int i;
+
+ xgene_enet_ring_wr32(ring, CSR_RING_CONFIG, ring->num);
+ for (i = 0; i < pdata->ring_ops->num_ring_config; i++) {
+ xgene_enet_ring_wr32(ring, CSR_RING_WR_BASE + (i * 4),
+ ring->state[i]);
+ }
+}
+
+static void xgene_enet_clr_ring_state(struct xgene_enet_desc_ring *ring)
+{
+ memset(ring->state, 0, sizeof(ring->state));
+ xgene_enet_write_ring_state(ring);
+}
+
+static void xgene_enet_set_ring_state(struct xgene_enet_desc_ring *ring)
+{
+ enum xgene_ring_owner owner;
+
+ xgene_enet_ring_set_type(ring);
+
+ owner = xgene_enet_ring_owner(ring->id);
+ if (owner == RING_OWNER_ETH0 || owner == RING_OWNER_ETH1)
+ xgene_enet_ring_set_recombbuf(ring);
+
+ xgene_enet_ring_init(ring);
+ xgene_enet_write_ring_state(ring);
+}
+
+static void xgene_enet_set_ring_id(struct xgene_enet_desc_ring *ring)
+{
+ u32 ring_id_val, ring_id_buf;
+ bool is_bufpool;
+
+ if (xgene_enet_ring_owner(ring->id) == RING_OWNER_CPU)
+ return;
+
+ is_bufpool = xgene_enet_is_bufpool(ring->id);
+
+ ring_id_val = ring->id & GENMASK(9, 0);
+ ring_id_val |= OVERWRITE;
+
+ ring_id_buf = (ring->num << 9) & GENMASK(18, 9);
+ ring_id_buf |= PREFETCH_BUF_EN;
+ if (is_bufpool)
+ ring_id_buf |= IS_BUFFER_POOL;
+
+ xgene_enet_ring_wr32(ring, CSR_RING_ID, ring_id_val);
+ xgene_enet_ring_wr32(ring, CSR_RING_ID_BUF, ring_id_buf);
+}
+
+static void xgene_enet_clr_desc_ring_id(struct xgene_enet_desc_ring *ring)
+{
+ u32 ring_id;
+
+ ring_id = ring->id | OVERWRITE;
+ xgene_enet_ring_wr32(ring, CSR_RING_ID, ring_id);
+ xgene_enet_ring_wr32(ring, CSR_RING_ID_BUF, 0);
+}
+
+static struct xgene_enet_desc_ring *xgene_enet_setup_ring(
+ struct xgene_enet_desc_ring *ring)
+{
+ bool is_bufpool;
+ u32 addr, i;
+
+ xgene_enet_clr_ring_state(ring);
+ xgene_enet_set_ring_state(ring);
+ xgene_enet_set_ring_id(ring);
+
+ ring->slots = xgene_enet_get_numslots(ring->id, ring->size);
+
+ is_bufpool = xgene_enet_is_bufpool(ring->id);
+ if (is_bufpool || xgene_enet_ring_owner(ring->id) != RING_OWNER_CPU)
+ return ring;
+
+ addr = CSR_VMID0_INTR_MBOX + (4 * (ring->id & RING_BUFNUM_MASK));
+ xgene_enet_ring_wr32(ring, addr, ring->irq_mbox_dma >> 10);
+
+ for (i = 0; i < ring->slots; i++)
+ xgene_enet_mark_desc_slot_empty(&ring->raw_desc[i]);
+
+ return ring;
+}
+
+static void xgene_enet_clear_ring(struct xgene_enet_desc_ring *ring)
+{
+ xgene_enet_clr_desc_ring_id(ring);
+ xgene_enet_clr_ring_state(ring);
+}
+
+static void xgene_enet_wr_cmd(struct xgene_enet_desc_ring *ring, int count)
+{
+ u32 data = 0;
+
+ if (xgene_enet_ring_owner(ring->id) == RING_OWNER_CPU) {
+ data = SET_VAL(X2_INTLINE, ring->id & RING_BUFNUM_MASK) |
+ INTR_CLEAR;
+ }
+ data |= (count & GENMASK(16, 0));
+
+ iowrite32(data, ring->cmd);
+}
+
+static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring)
+{
+ u32 __iomem *cmd_base = ring->cmd_base;
+ u32 ring_state, num_msgs;
+
+ ring_state = ioread32(&cmd_base[1]);
+ num_msgs = GET_VAL(X2_NUMMSGSINQ, ring_state);
+
+ return num_msgs;
+}
+
+struct xgene_ring_ops xgene_ring2_ops = {
+ .num_ring_config = X2_NUM_RING_CONFIG,
+ .num_ring_id_shift = 13,
+ .setup = xgene_enet_setup_ring,
+ .clear = xgene_enet_clear_ring,
+ .wr_cmd = xgene_enet_wr_cmd,
+ .len = xgene_enet_ring_len,
+};
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ring2.h b/drivers/net/ethernet/apm/xgene/xgene_enet_ring2.h
new file mode 100644
index 000000000000..8b235db23c42
--- /dev/null
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ring2.h
@@ -0,0 +1,49 @@
+/* Applied Micro X-Gene SoC Ethernet Driver
+ *
+ * Copyright (c) 2015, Applied Micro Circuits Corporation
+ * Author: Iyappan Subramanian <isubramanian@apm.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __XGENE_ENET_RING2_H__
+#define __XGENE_ENET_RING2_H__
+
+#include "xgene_enet_main.h"
+
+#define X2_NUM_RING_CONFIG 6
+
+#define INTR_MBOX_SIZE 1024
+#define CSR_VMID0_INTR_MBOX 0x0270
+#define INTR_CLEAR BIT(23)
+
+#define X2_MSG_AM_POS 10
+#define X2_QBASE_AM_POS 11
+#define X2_INTLINE_POS 24
+#define X2_INTLINE_LEN 5
+#define X2_CFGCRID_POS 29
+#define X2_CFGCRID_LEN 3
+#define X2_SELTHRSH_POS 7
+#define X2_SELTHRSH_LEN 3
+#define X2_RINGTYPE_POS 23
+#define X2_RINGTYPE_LEN 2
+#define X2_DEQINTEN_POS 29
+#define X2_RECOMTIMEOUT_POS 0
+#define X2_RECOMTIMEOUT_LEN 7
+#define X2_NUMMSGSINQ_POS 0
+#define X2_NUMMSGSINQ_LEN 17
+
+extern struct xgene_ring_ops xgene_ring2_ops;
+
+#endif /* __XGENE_ENET_RING2_H__ */
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c
index f27fb6f2a93b..05b817e56fde 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c
@@ -21,6 +21,7 @@
#include "xgene_enet_main.h"
#include "xgene_enet_hw.h"
#include "xgene_enet_sgmac.h"
+#include "xgene_enet_xgmac.h"
static void xgene_enet_wr_csr(struct xgene_enet_pdata *p, u32 offset, u32 val)
{
@@ -39,6 +40,14 @@ static void xgene_enet_wr_diag_csr(struct xgene_enet_pdata *p,
iowrite32(val, p->eth_diag_csr_addr + offset);
}
+static void xgene_enet_wr_mcx_csr(struct xgene_enet_pdata *pdata,
+ u32 offset, u32 val)
+{
+ void __iomem *addr = pdata->mcx_mac_csr_addr + offset;
+
+ iowrite32(val, addr);
+}
+
static bool xgene_enet_wr_indirect(struct xgene_indirect_ctl *ctl,
u32 wr_addr, u32 wr_data)
{
@@ -140,8 +149,9 @@ static int xgene_enet_ecc_init(struct xgene_enet_pdata *p)
static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *p)
{
- u32 val = 0xffffffff;
+ u32 val;
+ val = (p->enet_id == XGENE_ENET1) ? 0xffffffff : 0;
xgene_enet_wr_ring_if(p, ENET_CFGSSQMIWQASSOC_ADDR, val);
xgene_enet_wr_ring_if(p, ENET_CFGSSQMIFPQASSOC_ADDR, val);
}
@@ -227,6 +237,8 @@ static void xgene_sgmac_init(struct xgene_enet_pdata *p)
{
u32 data, loop = 10;
u32 offset = p->port_id * 4;
+ u32 enet_spare_cfg_reg, rsif_config_reg;
+ u32 cfg_bypass_reg, rx_dv_gate_reg;
xgene_sgmac_reset(p);
@@ -239,7 +251,7 @@ static void xgene_sgmac_init(struct xgene_enet_pdata *p)
SGMII_STATUS_ADDR >> 2);
if ((data & AUTO_NEG_COMPLETE) && (data & LINK_STATUS))
break;
- usleep_range(10, 20);
+ usleep_range(1000, 2000);
}
if (!(data & AUTO_NEG_COMPLETE) || !(data & LINK_STATUS))
netdev_err(p->ndev, "Auto-negotiation failed\n");
@@ -249,33 +261,38 @@ static void xgene_sgmac_init(struct xgene_enet_pdata *p)
xgene_enet_wr_mac(p, MAC_CONFIG_2_ADDR, data | FULL_DUPLEX2);
xgene_enet_wr_mac(p, INTERFACE_CONTROL_ADDR, ENET_GHD_MODE);
- data = xgene_enet_rd_csr(p, ENET_SPARE_CFG_REG_ADDR);
+ if (p->enet_id == XGENE_ENET1) {
+ enet_spare_cfg_reg = ENET_SPARE_CFG_REG_ADDR;
+ rsif_config_reg = RSIF_CONFIG_REG_ADDR;
+ cfg_bypass_reg = CFG_BYPASS_ADDR;
+ rx_dv_gate_reg = SG_RX_DV_GATE_REG_0_ADDR;
+ } else {
+ enet_spare_cfg_reg = XG_ENET_SPARE_CFG_REG_ADDR;
+ rsif_config_reg = XG_RSIF_CONFIG_REG_ADDR;
+ cfg_bypass_reg = XG_CFG_BYPASS_ADDR;
+ rx_dv_gate_reg = XG_MCX_RX_DV_GATE_REG_0_ADDR;
+ }
+
+ data = xgene_enet_rd_csr(p, enet_spare_cfg_reg);
data |= MPA_IDLE_WITH_QMI_EMPTY;
- xgene_enet_wr_csr(p, ENET_SPARE_CFG_REG_ADDR, data);
+ xgene_enet_wr_csr(p, enet_spare_cfg_reg, data);
xgene_sgmac_set_mac_addr(p);
- data = xgene_enet_rd_csr(p, DEBUG_REG_ADDR);
- data |= CFG_BYPASS_UNISEC_TX | CFG_BYPASS_UNISEC_RX;
- xgene_enet_wr_csr(p, DEBUG_REG_ADDR, data);
-
/* Adjust MDC clock frequency */
data = xgene_enet_rd_mac(p, MII_MGMT_CONFIG_ADDR);
MGMT_CLOCK_SEL_SET(&data, 7);
xgene_enet_wr_mac(p, MII_MGMT_CONFIG_ADDR, data);
/* Enable drop if bufpool not available */
- data = xgene_enet_rd_csr(p, RSIF_CONFIG_REG_ADDR);
+ data = xgene_enet_rd_csr(p, rsif_config_reg);
data |= CFG_RSIF_FPBUFF_TIMEOUT_EN;
- xgene_enet_wr_csr(p, RSIF_CONFIG_REG_ADDR, data);
-
- /* Rtype should be copied from FP */
- xgene_enet_wr_csr(p, RSIF_RAM_DBG_REG0_ADDR, 0);
+ xgene_enet_wr_csr(p, rsif_config_reg, data);
/* Bypass traffic gating */
- xgene_enet_wr_csr(p, CFG_LINK_AGGR_RESUME_0_ADDR + offset, TX_PORT0);
- xgene_enet_wr_csr(p, CFG_BYPASS_ADDR, RESUME_TX);
- xgene_enet_wr_csr(p, SG_RX_DV_GATE_REG_0_ADDR + offset, RESUME_RX0);
+ xgene_enet_wr_csr(p, XG_ENET_SPARE_CFG_REG_1_ADDR, 0x84);
+ xgene_enet_wr_csr(p, cfg_bypass_reg, RESUME_TX);
+ xgene_enet_wr_mcx_csr(p, rx_dv_gate_reg + offset, RESUME_RX0);
}
static void xgene_sgmac_rxtx(struct xgene_enet_pdata *p, u32 bits, bool set)
@@ -317,9 +334,11 @@ static int xgene_enet_reset(struct xgene_enet_pdata *p)
if (!xgene_ring_mgr_init(p))
return -ENODEV;
- clk_prepare_enable(p->clk);
- clk_disable_unprepare(p->clk);
- clk_prepare_enable(p->clk);
+ if (!IS_ERR(p->clk)) {
+ clk_prepare_enable(p->clk);
+ clk_disable_unprepare(p->clk);
+ clk_prepare_enable(p->clk);
+ }
xgene_enet_ecc_init(p);
xgene_enet_config_ring_if_assoc(p);
@@ -331,19 +350,29 @@ static void xgene_enet_cle_bypass(struct xgene_enet_pdata *p,
u32 dst_ring_num, u16 bufpool_id)
{
u32 data, fpsel;
+ u32 cle_bypass_reg0, cle_bypass_reg1;
u32 offset = p->port_id * MAC_OFFSET;
+ if (p->enet_id == XGENE_ENET1) {
+ cle_bypass_reg0 = CLE_BYPASS_REG0_0_ADDR;
+ cle_bypass_reg1 = CLE_BYPASS_REG1_0_ADDR;
+ } else {
+ cle_bypass_reg0 = XCLE_BYPASS_REG0_ADDR;
+ cle_bypass_reg1 = XCLE_BYPASS_REG1_ADDR;
+ }
+
data = CFG_CLE_BYPASS_EN0;
- xgene_enet_wr_csr(p, CLE_BYPASS_REG0_0_ADDR + offset, data);
+ xgene_enet_wr_csr(p, cle_bypass_reg0 + offset, data);
fpsel = xgene_enet_ring_bufnum(bufpool_id) - 0x20;
data = CFG_CLE_DSTQID0(dst_ring_num) | CFG_CLE_FPSEL0(fpsel);
- xgene_enet_wr_csr(p, CLE_BYPASS_REG1_0_ADDR + offset, data);
+ xgene_enet_wr_csr(p, cle_bypass_reg1 + offset, data);
}
static void xgene_enet_shutdown(struct xgene_enet_pdata *p)
{
- clk_disable_unprepare(p->clk);
+ if (!IS_ERR(p->clk))
+ clk_disable_unprepare(p->clk);
}
static void xgene_enet_link_state(struct work_struct *work)
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
index a18a9d1f1143..05edb847cf26 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
@@ -122,7 +122,6 @@ static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd,
return true;
}
-
static void xgene_enet_rd_mac(struct xgene_enet_pdata *pdata,
u32 rd_addr, u32 *rd_data)
{
@@ -257,9 +256,11 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
if (!xgene_ring_mgr_init(pdata))
return -ENODEV;
- clk_prepare_enable(pdata->clk);
- clk_disable_unprepare(pdata->clk);
- clk_prepare_enable(pdata->clk);
+ if (!IS_ERR(pdata->clk)) {
+ clk_prepare_enable(pdata->clk);
+ clk_disable_unprepare(pdata->clk);
+ clk_prepare_enable(pdata->clk);
+ }
xgene_enet_ecc_init(pdata);
xgene_enet_config_ring_if_assoc(pdata);
@@ -286,7 +287,8 @@ static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata,
static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata)
{
- clk_disable_unprepare(pdata->clk);
+ if (!IS_ERR(pdata->clk))
+ clk_disable_unprepare(pdata->clk);
}
static void xgene_enet_link_state(struct work_struct *work)
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h
index 5a5296a6d1df..bf0a99435737 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h
@@ -21,9 +21,28 @@
#ifndef __XGENE_ENET_XGMAC_H__
#define __XGENE_ENET_XGMAC_H__
+#define X2_BLOCK_ETH_MAC_CSR_OFFSET 0x3000
#define BLOCK_AXG_MAC_OFFSET 0x0800
#define BLOCK_AXG_MAC_CSR_OFFSET 0x2000
+#define XGENET_CONFIG_REG_ADDR 0x20
+#define XGENET_SRST_ADDR 0x00
+#define XGENET_CLKEN_ADDR 0x08
+
+#define CSR_CLK BIT(0)
+#define XGENET_CLK BIT(1)
+#define PCS_CLK BIT(3)
+#define AN_REF_CLK BIT(4)
+#define AN_CLK BIT(5)
+#define AD_CLK BIT(6)
+
+#define CSR_RST BIT(0)
+#define XGENET_RST BIT(1)
+#define PCS_RST BIT(3)
+#define AN_REF_RST BIT(4)
+#define AN_RST BIT(5)
+#define AD_RST BIT(6)
+
#define AXGMAC_CONFIG_0 0x0000
#define AXGMAC_CONFIG_1 0x0004
#define HSTMACRST BIT(31)
@@ -38,6 +57,7 @@
#define HSTMACADR_MSW_ADDR 0x0014
#define HSTMAXFRAME_LENGTH_ADDR 0x0020
+#define XG_MCX_RX_DV_GATE_REG_0_ADDR 0x0004
#define XG_RSIF_CONFIG_REG_ADDR 0x00a0
#define XCLE_BYPASS_REG0_ADDR 0x0160
#define XCLE_BYPASS_REG1_ADDR 0x0164
diff --git a/drivers/net/ethernet/apple/Kconfig b/drivers/net/ethernet/apple/Kconfig
index 1375e2dc9468..d19a41b0c6d2 100644
--- a/drivers/net/ethernet/apple/Kconfig
+++ b/drivers/net/ethernet/apple/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_APPLE
default y
depends on (PPC_PMAC && PPC32) || MAC
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
@@ -59,7 +57,6 @@ config MACMACE
---help---
Support for the onboard AMD 79C940 MACE Ethernet controller used in
the 660AV and 840AV Macintosh. If you have one of these Macintoshes
- say Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ say Y here.
endif # NET_VENDOR_APPLE
diff --git a/drivers/net/ethernet/arc/Kconfig b/drivers/net/ethernet/arc/Kconfig
index dea29ee24da4..52a6b16f57d2 100644
--- a/drivers/net/ethernet/arc/Kconfig
+++ b/drivers/net/ethernet/arc/Kconfig
@@ -6,9 +6,7 @@ config NET_VENDOR_ARC
bool "ARC devices"
default y
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/atheros/Kconfig b/drivers/net/ethernet/atheros/Kconfig
index 58ad37c733bc..e05b25675333 100644
--- a/drivers/net/ethernet/atheros/Kconfig
+++ b/drivers/net/ethernet/atheros/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_ATHEROS
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index a6f9142b9048..8be9eab73320 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -26,8 +26,7 @@ config B44
select PHYLIB
---help---
If you have a network (Ethernet) controller of this type, say Y
- or M and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ or M here.
To compile this driver as a module, choose M here. The module
will be called b44.
diff --git a/drivers/net/ethernet/broadcom/b44.h b/drivers/net/ethernet/broadcom/b44.h
index 3e9c3fc7591b..65d88d7c5581 100644
--- a/drivers/net/ethernet/broadcom/b44.h
+++ b/drivers/net/ethernet/broadcom/b44.h
@@ -1,6 +1,8 @@
#ifndef _B44_H
#define _B44_H
+#include <linux/brcmphy.h>
+
/* Register layout. (These correspond to struct _bcmenettregs in bcm4400.) */
#define B44_DEVCTRL 0x0000UL /* Device Control */
#define DEVCTRL_MPM 0x00000040 /* Magic Packet PME Enable (B0 only) */
@@ -281,8 +283,10 @@ struct ring_info {
};
#define B44_MCAST_TABLE_SIZE 32
-#define B44_PHY_ADDR_NO_LOCAL_PHY 30 /* no local phy regs */
-#define B44_PHY_ADDR_NO_PHY 31 /* no phy present at all */
+/* no local phy regs, e.g: Broadcom switches pseudo-PHY */
+#define B44_PHY_ADDR_NO_LOCAL_PHY BRCM_PSEUDO_PHY_ADDR
+/* no phy present at all */
+#define B44_PHY_ADDR_NO_PHY 31
#define B44_MDC_RATIO 5000000
#define B44_STAT_REG_DECLARE \
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 783543ad1fcf..909ad7a0d480 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -456,6 +456,67 @@ static int bcm_sysport_set_wol(struct net_device *dev,
return 0;
}
+static int bcm_sysport_get_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *ec)
+{
+ struct bcm_sysport_priv *priv = netdev_priv(dev);
+ u32 reg;
+
+ reg = tdma_readl(priv, TDMA_DESC_RING_INTR_CONTROL(0));
+
+ ec->tx_coalesce_usecs = (reg >> RING_TIMEOUT_SHIFT) * 8192 / 1000;
+ ec->tx_max_coalesced_frames = reg & RING_INTR_THRESH_MASK;
+
+ reg = rdma_readl(priv, RDMA_MBDONE_INTR);
+
+ ec->rx_coalesce_usecs = (reg >> RDMA_TIMEOUT_SHIFT) * 8192 / 1000;
+ ec->rx_max_coalesced_frames = reg & RDMA_INTR_THRESH_MASK;
+
+ return 0;
+}
+
+static int bcm_sysport_set_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *ec)
+{
+ struct bcm_sysport_priv *priv = netdev_priv(dev);
+ unsigned int i;
+ u32 reg;
+
+ /* Base system clock is 125Mhz, DMA timeout is this reference clock
+ * divided by 1024, which yield roughly 8.192 us, our maximum value has
+ * to fit in the RING_TIMEOUT_MASK (16 bits).
+ */
+ if (ec->tx_max_coalesced_frames > RING_INTR_THRESH_MASK ||
+ ec->tx_coalesce_usecs > (RING_TIMEOUT_MASK * 8) + 1 ||
+ ec->rx_max_coalesced_frames > RDMA_INTR_THRESH_MASK ||
+ ec->rx_coalesce_usecs > (RDMA_TIMEOUT_MASK * 8) + 1)
+ return -EINVAL;
+
+ if ((ec->tx_coalesce_usecs == 0 && ec->tx_max_coalesced_frames == 0) ||
+ (ec->rx_coalesce_usecs == 0 && ec->rx_max_coalesced_frames == 0))
+ return -EINVAL;
+
+ for (i = 0; i < dev->num_tx_queues; i++) {
+ reg = tdma_readl(priv, TDMA_DESC_RING_INTR_CONTROL(i));
+ reg &= ~(RING_INTR_THRESH_MASK |
+ RING_TIMEOUT_MASK << RING_TIMEOUT_SHIFT);
+ reg |= ec->tx_max_coalesced_frames;
+ reg |= DIV_ROUND_UP(ec->tx_coalesce_usecs * 1000, 8192) <<
+ RING_TIMEOUT_SHIFT;
+ tdma_writel(priv, reg, TDMA_DESC_RING_INTR_CONTROL(i));
+ }
+
+ reg = rdma_readl(priv, RDMA_MBDONE_INTR);
+ reg &= ~(RDMA_INTR_THRESH_MASK |
+ RDMA_TIMEOUT_MASK << RDMA_TIMEOUT_SHIFT);
+ reg |= ec->rx_max_coalesced_frames;
+ reg |= DIV_ROUND_UP(ec->rx_coalesce_usecs * 1000, 8192) <<
+ RDMA_TIMEOUT_SHIFT;
+ rdma_writel(priv, reg, RDMA_MBDONE_INTR);
+
+ return 0;
+}
+
static void bcm_sysport_free_cb(struct bcm_sysport_cb *cb)
{
dev_kfree_skb_any(cb->skb);
@@ -463,67 +524,70 @@ static void bcm_sysport_free_cb(struct bcm_sysport_cb *cb)
dma_unmap_addr_set(cb, dma_addr, 0);
}
-static int bcm_sysport_rx_refill(struct bcm_sysport_priv *priv,
- struct bcm_sysport_cb *cb)
+static struct sk_buff *bcm_sysport_rx_refill(struct bcm_sysport_priv *priv,
+ struct bcm_sysport_cb *cb)
{
struct device *kdev = &priv->pdev->dev;
struct net_device *ndev = priv->netdev;
+ struct sk_buff *skb, *rx_skb;
dma_addr_t mapping;
- int ret;
- cb->skb = netdev_alloc_skb(priv->netdev, RX_BUF_LENGTH);
- if (!cb->skb) {
+ /* Allocate a new SKB for a new packet */
+ skb = netdev_alloc_skb(priv->netdev, RX_BUF_LENGTH);
+ if (!skb) {
+ priv->mib.alloc_rx_buff_failed++;
netif_err(priv, rx_err, ndev, "SKB alloc failed\n");
- return -ENOMEM;
+ return NULL;
}
- mapping = dma_map_single(kdev, cb->skb->data,
+ mapping = dma_map_single(kdev, skb->data,
RX_BUF_LENGTH, DMA_FROM_DEVICE);
- ret = dma_mapping_error(kdev, mapping);
- if (ret) {
+ if (dma_mapping_error(kdev, mapping)) {
priv->mib.rx_dma_failed++;
- bcm_sysport_free_cb(cb);
+ dev_kfree_skb_any(skb);
netif_err(priv, rx_err, ndev, "DMA mapping failure\n");
- return ret;
+ return NULL;
}
- dma_unmap_addr_set(cb, dma_addr, mapping);
- dma_desc_set_addr(priv, priv->rx_bd_assign_ptr, mapping);
+ /* Grab the current SKB on the ring */
+ rx_skb = cb->skb;
+ if (likely(rx_skb))
+ dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr),
+ RX_BUF_LENGTH, DMA_FROM_DEVICE);
- priv->rx_bd_assign_index++;
- priv->rx_bd_assign_index &= (priv->num_rx_bds - 1);
- priv->rx_bd_assign_ptr = priv->rx_bds +
- (priv->rx_bd_assign_index * DESC_SIZE);
+ /* Put the new SKB on the ring */
+ cb->skb = skb;
+ dma_unmap_addr_set(cb, dma_addr, mapping);
+ dma_desc_set_addr(priv, cb->bd_addr, mapping);
netif_dbg(priv, rx_status, ndev, "RX refill\n");
- return 0;
+ /* Return the current SKB to the caller */
+ return rx_skb;
}
static int bcm_sysport_alloc_rx_bufs(struct bcm_sysport_priv *priv)
{
struct bcm_sysport_cb *cb;
- int ret = 0;
+ struct sk_buff *skb;
unsigned int i;
for (i = 0; i < priv->num_rx_bds; i++) {
- cb = &priv->rx_cbs[priv->rx_bd_assign_index];
- if (cb->skb)
- continue;
-
- ret = bcm_sysport_rx_refill(priv, cb);
- if (ret)
- break;
+ cb = &priv->rx_cbs[i];
+ skb = bcm_sysport_rx_refill(priv, cb);
+ if (skb)
+ dev_kfree_skb(skb);
+ if (!cb->skb)
+ return -ENOMEM;
}
- return ret;
+ return 0;
}
/* Poll the hardware for up to budget packets to process */
static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
unsigned int budget)
{
- struct device *kdev = &priv->pdev->dev;
struct net_device *ndev = priv->netdev;
unsigned int processed = 0, to_process;
struct bcm_sysport_cb *cb;
@@ -531,7 +595,6 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
unsigned int p_index;
u16 len, status;
struct bcm_rsb *rsb;
- int ret;
/* Determine how much we should process since last call */
p_index = rdma_readl(priv, RDMA_PROD_INDEX);
@@ -549,13 +612,8 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
while ((processed < to_process) && (processed < budget)) {
cb = &priv->rx_cbs[priv->rx_read_ptr];
- skb = cb->skb;
+ skb = bcm_sysport_rx_refill(priv, cb);
- processed++;
- priv->rx_read_ptr++;
-
- if (priv->rx_read_ptr == priv->num_rx_bds)
- priv->rx_read_ptr = 0;
/* We do not have a backing SKB, so we do not a corresponding
* DMA mapping for this incoming packet since
@@ -566,12 +624,9 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
netif_err(priv, rx_err, ndev, "out of memory!\n");
ndev->stats.rx_dropped++;
ndev->stats.rx_errors++;
- goto refill;
+ goto next;
}
- dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr),
- RX_BUF_LENGTH, DMA_FROM_DEVICE);
-
/* Extract the Receive Status Block prepended */
rsb = (struct bcm_rsb *)skb->data;
len = (rsb->rx_status_len >> DESC_LEN_SHIFT) & DESC_LEN_MASK;
@@ -583,12 +638,20 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
p_index, priv->rx_c_index, priv->rx_read_ptr,
len, status);
+ if (unlikely(len > RX_BUF_LENGTH)) {
+ netif_err(priv, rx_status, ndev, "oversized packet\n");
+ ndev->stats.rx_length_errors++;
+ ndev->stats.rx_errors++;
+ dev_kfree_skb_any(skb);
+ goto next;
+ }
+
if (unlikely(!(status & DESC_EOP) || !(status & DESC_SOP))) {
netif_err(priv, rx_status, ndev, "fragmented packet!\n");
ndev->stats.rx_dropped++;
ndev->stats.rx_errors++;
- bcm_sysport_free_cb(cb);
- goto refill;
+ dev_kfree_skb_any(skb);
+ goto next;
}
if (unlikely(status & (RX_STATUS_ERR | RX_STATUS_OVFLOW))) {
@@ -597,8 +660,8 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
ndev->stats.rx_over_errors++;
ndev->stats.rx_dropped++;
ndev->stats.rx_errors++;
- bcm_sysport_free_cb(cb);
- goto refill;
+ dev_kfree_skb_any(skb);
+ goto next;
}
skb_put(skb, len);
@@ -625,10 +688,12 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
ndev->stats.rx_bytes += len;
napi_gro_receive(&priv->napi, skb);
-refill:
- ret = bcm_sysport_rx_refill(priv, cb);
- if (ret)
- priv->mib.alloc_rx_buff_failed++;
+next:
+ processed++;
+ priv->rx_read_ptr++;
+
+ if (priv->rx_read_ptr == priv->num_rx_bds)
+ priv->rx_read_ptr = 0;
}
return processed;
@@ -1269,14 +1334,14 @@ static inline int tdma_enable_set(struct bcm_sysport_priv *priv,
static int bcm_sysport_init_rx_ring(struct bcm_sysport_priv *priv)
{
+ struct bcm_sysport_cb *cb;
u32 reg;
int ret;
+ int i;
/* Initialize SW view of the RX ring */
priv->num_rx_bds = NUM_RX_DESC;
priv->rx_bds = priv->base + SYS_PORT_RDMA_OFFSET;
- priv->rx_bd_assign_ptr = priv->rx_bds;
- priv->rx_bd_assign_index = 0;
priv->rx_c_index = 0;
priv->rx_read_ptr = 0;
priv->rx_cbs = kcalloc(priv->num_rx_bds, sizeof(struct bcm_sysport_cb),
@@ -1286,6 +1351,11 @@ static int bcm_sysport_init_rx_ring(struct bcm_sysport_priv *priv)
return -ENOMEM;
}
+ for (i = 0; i < priv->num_rx_bds; i++) {
+ cb = priv->rx_cbs + i;
+ cb->bd_addr = priv->rx_bds + i * DESC_SIZE;
+ }
+
ret = bcm_sysport_alloc_rx_bufs(priv);
if (ret) {
netif_err(priv, hw, priv->netdev, "SKB allocation failed\n");
@@ -1641,6 +1711,8 @@ static struct ethtool_ops bcm_sysport_ethtool_ops = {
.get_sset_count = bcm_sysport_get_sset_count,
.get_wol = bcm_sysport_get_wol,
.set_wol = bcm_sysport_set_wol,
+ .get_coalesce = bcm_sysport_get_coalesce,
+ .set_coalesce = bcm_sysport_set_coalesce,
};
static const struct net_device_ops bcm_sysport_netdev_ops = {
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h
index e2c043eabbf3..f28bf545d7f4 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.h
+++ b/drivers/net/ethernet/broadcom/bcmsysport.h
@@ -292,7 +292,7 @@ struct bcm_rsb {
#define RDMA_END_ADDR_LO 0x102c
#define RDMA_MBDONE_INTR 0x1030
-#define RDMA_INTR_THRESH_MASK 0xff
+#define RDMA_INTR_THRESH_MASK 0x1ff
#define RDMA_TIMEOUT_SHIFT 16
#define RDMA_TIMEOUT_MASK 0xffff
@@ -663,8 +663,6 @@ struct bcm_sysport_priv {
/* Receive queue */
void __iomem *rx_bds;
- void __iomem *rx_bd_assign_ptr;
- unsigned int rx_bd_assign_index;
struct bcm_sysport_cb *rx_cbs;
unsigned int num_rx_bds;
unsigned int rx_read_ptr;
diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h
index db27febbb215..4fbb093e0d84 100644
--- a/drivers/net/ethernet/broadcom/bgmac.h
+++ b/drivers/net/ethernet/broadcom/bgmac.h
@@ -13,6 +13,7 @@
dev_dbg(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
#include <linux/bcma/bcma.h>
+#include <linux/brcmphy.h>
#include <linux/netdevice.h>
#define BGMAC_DEV_CTL 0x000
@@ -349,7 +350,7 @@
#define BGMAC_DESC_CTL0_SOF 0x80000000 /* Start of frame */
#define BGMAC_DESC_CTL1_LEN 0x00001FFF
-#define BGMAC_PHY_NOREGS 0x1E
+#define BGMAC_PHY_NOREGS BRCM_PSEUDO_PHY_ADDR
#define BGMAC_PHY_MASK 0x1F
#define BGMAC_MAX_TX_RINGS 4
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index 1f82a04ce01a..7a4aaa3c01b6 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -357,6 +357,7 @@ struct sw_tx_bd {
struct sw_rx_page {
struct page *page;
DEFINE_DMA_UNMAP_ADDR(mapping);
+ unsigned int offset;
};
union db_prod {
@@ -381,9 +382,10 @@ union db_prod {
#define PAGES_PER_SGE_SHIFT 0
#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_SHIFT 12
+#define SGE_PAGE_SIZE (1 << SGE_PAGE_SHIFT)
+#define SGE_PAGE_MASK (~(SGE_PAGE_SIZE - 1))
+#define SGE_PAGE_ALIGN(addr) (((addr) + SGE_PAGE_SIZE - 1) & SGE_PAGE_MASK)
#define SGE_PAGES (SGE_PAGE_SIZE * PAGES_PER_SGE)
#define TPA_AGG_SIZE min_t(u32, (min_t(u32, 8, MAX_SKB_FRAGS) * \
SGE_PAGES), 0xffff)
@@ -526,6 +528,12 @@ enum bnx2x_tpa_mode_t {
TPA_MODE_GRO
};
+struct bnx2x_alloc_pool {
+ struct page *page;
+ dma_addr_t dma;
+ unsigned int offset;
+};
+
struct bnx2x_fastpath {
struct bnx2x *bp; /* parent */
@@ -599,6 +607,8 @@ struct bnx2x_fastpath {
4 (for the digits and to make it DWORD aligned) */
#define FP_NAME_SIZE (sizeof(((struct net_device *)0)->name) + 8)
char name[FP_NAME_SIZE];
+
+ struct bnx2x_alloc_pool page_pool;
};
#define bnx2x_fp(bp, nr, var) ((bp)->fp[(nr)].var)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index ec56a9b65dc3..e2a65334708d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -544,30 +544,49 @@ static void bnx2x_set_gro_params(struct sk_buff *skb, u16 parsing_flags,
static int bnx2x_alloc_rx_sge(struct bnx2x *bp, struct bnx2x_fastpath *fp,
u16 index, gfp_t gfp_mask)
{
- struct page *page = alloc_pages(gfp_mask, PAGES_PER_SGE_SHIFT);
struct sw_rx_page *sw_buf = &fp->rx_page_ring[index];
struct eth_rx_sge *sge = &fp->rx_sge_ring[index];
+ struct bnx2x_alloc_pool *pool = &fp->page_pool;
dma_addr_t mapping;
- if (unlikely(page == NULL)) {
- BNX2X_ERR("Can't alloc sge\n");
- return -ENOMEM;
- }
+ if (!pool->page || (PAGE_SIZE - pool->offset) < SGE_PAGE_SIZE) {
- mapping = dma_map_page(&bp->pdev->dev, page, 0,
- SGE_PAGES, DMA_FROM_DEVICE);
- if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
- __free_pages(page, PAGES_PER_SGE_SHIFT);
- BNX2X_ERR("Can't map sge\n");
- return -ENOMEM;
+ /* put page reference used by the memory pool, since we
+ * won't be using this page as the mempool anymore.
+ */
+ if (pool->page)
+ put_page(pool->page);
+
+ pool->page = alloc_pages(gfp_mask, PAGES_PER_SGE_SHIFT);
+ if (unlikely(!pool->page)) {
+ BNX2X_ERR("Can't alloc sge\n");
+ return -ENOMEM;
+ }
+
+ pool->dma = dma_map_page(&bp->pdev->dev, pool->page, 0,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(&bp->pdev->dev,
+ pool->dma))) {
+ __free_pages(pool->page, PAGES_PER_SGE_SHIFT);
+ pool->page = NULL;
+ BNX2X_ERR("Can't map sge\n");
+ return -ENOMEM;
+ }
+ pool->offset = 0;
}
- sw_buf->page = page;
+ get_page(pool->page);
+ sw_buf->page = pool->page;
+ sw_buf->offset = pool->offset;
+
+ mapping = pool->dma + sw_buf->offset;
dma_unmap_addr_set(sw_buf, mapping, mapping);
sge->addr_hi = cpu_to_le32(U64_HI(mapping));
sge->addr_lo = cpu_to_le32(U64_LO(mapping));
+ pool->offset += SGE_PAGE_SIZE;
+
return 0;
}
@@ -629,20 +648,22 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
return err;
}
- /* Unmap the page as we're going to pass it to the stack */
- dma_unmap_page(&bp->pdev->dev,
- dma_unmap_addr(&old_rx_pg, mapping),
- SGE_PAGES, DMA_FROM_DEVICE);
+ dma_unmap_single(&bp->pdev->dev,
+ dma_unmap_addr(&old_rx_pg, mapping),
+ SGE_PAGE_SIZE, DMA_FROM_DEVICE);
/* Add one frag and update the appropriate fields in the skb */
if (fp->mode == TPA_MODE_LRO)
- skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len);
+ skb_fill_page_desc(skb, j, old_rx_pg.page,
+ old_rx_pg.offset, frag_len);
else { /* GRO */
int rem;
int offset = 0;
for (rem = frag_len; rem > 0; rem -= gro_size) {
int len = rem > gro_size ? gro_size : rem;
skb_fill_page_desc(skb, frag_id++,
- old_rx_pg.page, offset, len);
+ old_rx_pg.page,
+ old_rx_pg.offset + offset,
+ len);
if (offset)
get_page(old_rx_pg.page);
offset += len;
@@ -662,7 +683,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
static void bnx2x_frag_free(const struct bnx2x_fastpath *fp, void *data)
{
if (fp->rx_frag_size)
- put_page(virt_to_head_page(data));
+ skb_free_frag(data);
else
kfree(data);
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index d7a71758e876..2b30081ec26d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -804,9 +804,13 @@ static inline void bnx2x_free_rx_sge(struct bnx2x *bp,
if (!page)
return;
- dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(sw_buf, mapping),
- SGE_PAGES, DMA_FROM_DEVICE);
- __free_pages(page, PAGES_PER_SGE_SHIFT);
+ /* Since many fragments can share the same page, make sure to
+ * only unmap and free the page once.
+ */
+ dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(sw_buf, mapping),
+ SGE_PAGE_SIZE, DMA_FROM_DEVICE);
+
+ put_page(page);
sw_buf->page = NULL;
sge->addr_hi = 0;
@@ -964,6 +968,25 @@ static inline void bnx2x_set_fw_mac_addr(__le16 *fw_hi, __le16 *fw_mid,
((u8 *)fw_lo)[1] = mac[4];
}
+static inline void bnx2x_free_rx_mem_pool(struct bnx2x *bp,
+ struct bnx2x_alloc_pool *pool)
+{
+ if (!pool->page)
+ return;
+
+ /* Page was not fully fragmented. Unmap unused space */
+ if (pool->offset < PAGE_SIZE) {
+ dma_addr_t dma = pool->dma + pool->offset;
+ int size = PAGE_SIZE - pool->offset;
+
+ dma_unmap_single(&bp->pdev->dev, dma, size, DMA_FROM_DEVICE);
+ }
+
+ put_page(pool->page);
+
+ pool->page = NULL;
+}
+
static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp,
struct bnx2x_fastpath *fp, int last)
{
@@ -974,6 +997,8 @@ static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp,
for (i = 0; i < last; i++)
bnx2x_free_rx_sge(bp, fp, i);
+
+ bnx2x_free_rx_mem_pool(bp, &fp->page_pool);
}
static inline void bnx2x_set_next_page_rx_bd(struct bnx2x_fastpath *fp)
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 6043734ea613..b43b2cb9b830 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2770,12 +2770,79 @@ static int bcmgenet_close(struct net_device *dev)
return ret;
}
+static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring)
+{
+ struct bcmgenet_priv *priv = ring->priv;
+ u32 p_index, c_index, intsts, intmsk;
+ struct netdev_queue *txq;
+ unsigned int free_bds;
+ unsigned long flags;
+ bool txq_stopped;
+
+ if (!netif_msg_tx_err(priv))
+ return;
+
+ txq = netdev_get_tx_queue(priv->dev, ring->queue);
+
+ spin_lock_irqsave(&ring->lock, flags);
+ if (ring->index == DESC_INDEX) {
+ intsts = ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS);
+ intmsk = UMAC_IRQ_TXDMA_DONE | UMAC_IRQ_TXDMA_MBDONE;
+ } else {
+ intsts = ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS);
+ intmsk = 1 << ring->index;
+ }
+ c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX);
+ p_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_PROD_INDEX);
+ txq_stopped = netif_tx_queue_stopped(txq);
+ free_bds = ring->free_bds;
+ spin_unlock_irqrestore(&ring->lock, flags);
+
+ netif_err(priv, tx_err, priv->dev, "Ring %d queue %d status summary\n"
+ "TX queue status: %s, interrupts: %s\n"
+ "(sw)free_bds: %d (sw)size: %d\n"
+ "(sw)p_index: %d (hw)p_index: %d\n"
+ "(sw)c_index: %d (hw)c_index: %d\n"
+ "(sw)clean_p: %d (sw)write_p: %d\n"
+ "(sw)cb_ptr: %d (sw)end_ptr: %d\n",
+ ring->index, ring->queue,
+ txq_stopped ? "stopped" : "active",
+ intsts & intmsk ? "enabled" : "disabled",
+ free_bds, ring->size,
+ ring->prod_index, p_index & DMA_P_INDEX_MASK,
+ ring->c_index, c_index & DMA_C_INDEX_MASK,
+ ring->clean_ptr, ring->write_ptr,
+ ring->cb_ptr, ring->end_ptr);
+}
+
static void bcmgenet_timeout(struct net_device *dev)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
+ u32 int0_enable = 0;
+ u32 int1_enable = 0;
+ unsigned int q;
netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n");
+ bcmgenet_disable_tx_napi(priv);
+
+ for (q = 0; q < priv->hw_params->tx_queues; q++)
+ bcmgenet_dump_tx_queue(&priv->tx_rings[q]);
+ bcmgenet_dump_tx_queue(&priv->tx_rings[DESC_INDEX]);
+
+ bcmgenet_tx_reclaim_all(dev);
+
+ for (q = 0; q < priv->hw_params->tx_queues; q++)
+ int1_enable |= (1 << q);
+
+ int0_enable = UMAC_IRQ_TXDMA_DONE;
+
+ /* Re-enable TX interrupts if disabled */
+ bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
+ bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR);
+
+ bcmgenet_enable_tx_napi(priv);
+
dev->trans_start = jiffies;
dev->stats.tx_errors++;
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index 420949cc55aa..6bef04e2f735 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -47,7 +47,12 @@ static int bcmgenet_mii_read(struct mii_bus *bus, int phy_id, int location)
HZ / 100);
ret = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD);
- if (ret & MDIO_READ_FAIL)
+ /* Some broken devices are known not to release the line during
+ * turn-around, e.g: Broadcom BCM53125 external switches, so check for
+ * that condition here and ignore the MDIO controller read failure
+ * indication.
+ */
+ if (!(bus->phy_ignore_ta_mask & 1 << phy_id) && (ret & MDIO_READ_FAIL))
return -EIO;
return ret & 0xffff;
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 069952fa5d64..73c934cf6c61 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -6618,7 +6618,7 @@ static void tg3_tx(struct tg3_napi *tnapi)
static void tg3_frag_free(bool is_frag, void *data)
{
if (is_frag)
- put_page(virt_to_head_page(data));
+ skb_free_frag(data);
else
kfree(data);
}
diff --git a/drivers/net/ethernet/brocade/Kconfig b/drivers/net/ethernet/brocade/Kconfig
index 4e8c0b6c57d0..c4bbe54e2cad 100644
--- a/drivers/net/ethernet/brocade/Kconfig
+++ b/drivers/net/ethernet/brocade/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_BROCADE
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/brocade/bna/Makefile b/drivers/net/ethernet/brocade/bna/Makefile
index 6e10b99733a2..8584abcf5366 100644
--- a/drivers/net/ethernet/brocade/bna/Makefile
+++ b/drivers/net/ethernet/brocade/bna/Makefile
@@ -9,5 +9,3 @@ obj-$(CONFIG_BNA) += bna.o
bna-objs := bnad.o bnad_ethtool.o bnad_debugfs.o bna_enet.o bna_tx_rx.o
bna-objs += bfa_msgq.o bfa_ioc.o bfa_ioc_ct.o bfa_cee.o
bna-objs += cna_fwimg.o
-
-EXTRA_CFLAGS := -Idrivers/net/bna
diff --git a/drivers/net/ethernet/brocade/bna/bfa_cee.c b/drivers/net/ethernet/brocade/bna/bfa_cee.c
index cf9f3956f198..95bc8b644a5d 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_cee.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_cee.c
@@ -282,7 +282,6 @@ bfa_nw_cee_attach(struct bfa_cee *cee, struct bfa_ioc *ioc,
cee->ioc = ioc;
bfa_nw_ioc_mbox_regisr(cee->ioc, BFI_MC_CEE, bfa_cee_isr, cee);
- bfa_q_qe_init(&cee->ioc_notify);
bfa_ioc_notify_init(&cee->ioc_notify, bfa_cee_notify, cee);
bfa_nw_ioc_notify_register(cee->ioc, &cee->ioc_notify);
}
diff --git a/drivers/net/ethernet/brocade/bna/bfa_cs.h b/drivers/net/ethernet/brocade/bna/bfa_cs.h
index af25d8e8fae0..1d11d666d408 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_cs.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_cs.h
@@ -28,19 +28,6 @@
typedef void (*bfa_sm_t)(void *sm, int event);
-/* oc - object class eg. bfa_ioc
- * st - state, eg. reset
- * otype - object type, eg. struct bfa_ioc
- * etype - object type, eg. enum ioc_event
- */
-#define bfa_sm_state_decl(oc, st, otype, etype) \
- static void oc ## _sm_ ## st(otype * fsm, etype event)
-
-#define bfa_sm_set_state(_sm, _state) ((_sm)->sm = (bfa_sm_t)(_state))
-#define bfa_sm_send_event(_sm, _event) ((_sm)->sm((_sm), (_event)))
-#define bfa_sm_get_state(_sm) ((_sm)->sm)
-#define bfa_sm_cmp_state(_sm, _state) ((_sm)->sm == (bfa_sm_t)(_state))
-
/* For converting from state machine function to state encoding. */
struct bfa_sm_table {
bfa_sm_t sm; /*!< state machine function */
@@ -67,7 +54,6 @@ typedef void (*bfa_fsm_t)(void *fsm, int event);
} while (0)
#define bfa_fsm_send_event(_fsm, _event) ((_fsm)->fsm((_fsm), (_event)))
-#define bfa_fsm_get_state(_fsm) ((_fsm)->fsm)
#define bfa_fsm_cmp_state(_fsm, _state) \
((_fsm)->fsm == (bfa_fsm_t)(_state))
diff --git a/drivers/net/ethernet/brocade/bna/bfa_defs.h b/drivers/net/ethernet/brocade/bna/bfa_defs.h
index 3bfd9da92630..d152b3fa6c54 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_defs.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_defs.h
@@ -24,7 +24,6 @@
#include "bfa_defs_status.h"
#include "bfa_defs_mfg_comm.h"
-#define BFA_STRING_32 32
#define BFA_VERSION_LEN 64
/* ---------------------- adapter definitions ------------ */
@@ -55,7 +54,7 @@ struct bfa_adapter_attr {
char optrom_ver[BFA_VERSION_LEN];
char os_type[BFA_ADAPTER_OS_TYPE_LEN];
struct bfa_mfg_vpd vpd;
- struct mac mac;
+ u8 mac[ETH_ALEN];
u8 nports;
u8 max_speed;
@@ -187,8 +186,6 @@ enum {
#define BFA_MFG_SUPPLIER_SERIALNUM_SIZE 20
#define BFA_MFG_SUPPLIER_REVISION_SIZE 4
-#pragma pack(1)
-
/* BFA adapter manufacturing block definition.
*
* All numerical fields are in big-endian format.
@@ -211,7 +208,7 @@ struct bfa_mfg_block {
char supplier_partnum[STRSZ(BFA_MFG_SUPPLIER_PARTNUM_SIZE)];
char supplier_serialnum[STRSZ(BFA_MFG_SUPPLIER_SERIALNUM_SIZE)];
char supplier_revision[STRSZ(BFA_MFG_SUPPLIER_REVISION_SIZE)];
- mac_t mfg_mac; /* base mac address */
+ u8 mfg_mac[ETH_ALEN]; /* base mac address */
u8 num_mac; /* number of mac addresses */
u8 rsv2;
u32 card_type; /* card type */
@@ -227,9 +224,7 @@ struct bfa_mfg_block {
char initial_mode[8]; /* initial mode: hba/cna/nic */
u8 rsv4[84];
u8 md5_chksum[BFA_MFG_CHKSUM_SIZE]; /* md5 checksum */
-};
-
-#pragma pack()
+} __packed;
/* ---------------------- pci definitions ------------ */
diff --git a/drivers/net/ethernet/brocade/bna/bfa_defs_cna.h b/drivers/net/ethernet/brocade/bna/bfa_defs_cna.h
index a37326d44fbb..f048887cbb81 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_defs_cna.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_defs_cna.h
@@ -109,8 +109,6 @@ union bfa_port_stats_u {
struct bfa_port_eth_stats eth;
};
-#pragma pack(1)
-
#define BFA_CEE_LLDP_MAX_STRING_LEN (128)
#define BFA_CEE_DCBX_MAX_PRIORITY (8)
#define BFA_CEE_DCBX_MAX_PGID (8)
@@ -133,7 +131,7 @@ struct bfa_cee_lldp_str {
u8 len;
u8 rsvd[2];
u8 value[BFA_CEE_LLDP_MAX_STRING_LEN];
-};
+} __packed;
/* LLDP parameters */
struct bfa_cee_lldp_cfg {
@@ -145,7 +143,7 @@ struct bfa_cee_lldp_cfg {
struct bfa_cee_lldp_str mgmt_addr;
u16 time_to_live;
u16 enabled_system_cap;
-};
+} __packed;
enum bfa_cee_dcbx_version {
DCBX_PROTOCOL_PRECEE = 1,
@@ -171,7 +169,7 @@ struct bfa_cee_dcbx_cfg {
u8 lls_fcoe; /* FCoE Logical Link Status */
u8 lls_lan; /* LAN Logical Link Status */
u8 rsvd[2];
-};
+} __packed;
/* CEE status */
/* Making this to tri-state for the benefit of port list command */
@@ -188,11 +186,11 @@ struct bfa_cee_attr {
u8 error_reason;
struct bfa_cee_lldp_cfg lldp_remote;
struct bfa_cee_dcbx_cfg dcbx_remote;
- mac_t src_mac;
+ u8 src_mac[ETH_ALEN];
u8 link_speed;
u8 nw_priority;
u8 filler[2];
-};
+} __packed;
/* LLDP/DCBX/CEE Statistics */
struct bfa_cee_stats {
@@ -214,8 +212,6 @@ struct bfa_cee_stats {
u32 cee_status_up; /*!< CEE status up */
u32 cee_hw_cfg_changed; /*!< CEE hw cfg changed */
u32 cee_rx_invalid_cfg; /*!< CEE invalid cfg */
-};
-
-#pragma pack()
+} __packed;
#endif /* __BFA_DEFS_CNA_H__ */
diff --git a/drivers/net/ethernet/brocade/bna/bfa_defs_mfg_comm.h b/drivers/net/ethernet/brocade/bna/bfa_defs_mfg_comm.h
index 7a45cd0b594d..7e17451c94d1 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_defs_mfg_comm.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_defs_mfg_comm.h
@@ -59,8 +59,6 @@ enum {
BFA_MFG_TYPE_INVALID = 0, /*!< Invalid card type */
};
-#pragma pack(1)
-
/* Check if Mezz card */
#define bfa_mfg_is_mezz(type) (( \
(type) == BFA_MFG_TYPE_JAYHAWK || \
@@ -77,7 +75,7 @@ enum {
CB_GPIO_FC4P2 = (4), /*!< 4G 2port FC card */
CB_GPIO_FC4P1 = (5), /*!< 4G 1port FC card */
CB_GPIO_DFLY = (6), /*!< 8G 2port FC mezzanine card */
- CB_GPIO_PROTO = (1 << 7) /*!< 8G 2port FC prototypes */
+ CB_GPIO_PROTO = BIT(7) /*!< 8G 2port FC prototypes */
};
#define bfa_mfg_adapter_prop_init_gpio(gpio, card_type, prop) \
@@ -86,7 +84,7 @@ do { \
(prop) |= BFI_ADAPTER_PROTO; \
(gpio) &= ~CB_GPIO_PROTO; \
} \
- switch ((gpio)) { \
+ switch (gpio) { \
case CB_GPIO_TTV: \
(prop) |= BFI_ADAPTER_TTV; \
case CB_GPIO_DFLY: \
@@ -148,8 +146,6 @@ struct bfa_mfg_vpd {
u8 len; /*!< vpd data length excluding header */
u8 rsv;
u8 data[BFA_MFG_VPD_LEN]; /*!< vpd data */
-};
-
-#pragma pack()
+} __packed;
#endif /* __BFA_DEFS_MFG_H__ */
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
index 68f3c13c9ef6..b7a0f7879de2 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
@@ -23,14 +23,6 @@
/* IOC local definitions */
-#define bfa_ioc_state_disabled(__sm) \
- (((__sm) == BFI_IOC_UNINIT) || \
- ((__sm) == BFI_IOC_INITING) || \
- ((__sm) == BFI_IOC_HWINIT) || \
- ((__sm) == BFI_IOC_DISABLED) || \
- ((__sm) == BFI_IOC_FAIL) || \
- ((__sm) == BFI_IOC_CFG_DISABLED))
-
/* Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details. */
#define bfa_ioc_firmware_lock(__ioc) \
@@ -57,12 +49,6 @@
((__ioc)->ioc_hwif->ioc_get_fwstate(__ioc))
#define bfa_ioc_set_alt_ioc_fwstate(__ioc, __fwstate) \
((__ioc)->ioc_hwif->ioc_set_alt_fwstate(__ioc, __fwstate))
-#define bfa_ioc_get_alt_ioc_fwstate(__ioc) \
- ((__ioc)->ioc_hwif->ioc_get_alt_fwstate(__ioc))
-
-#define bfa_ioc_mbox_cmd_pending(__ioc) \
- (!list_empty(&((__ioc)->mbox_mod.cmd_q)) || \
- readl((__ioc)->ioc_regs.hfn_mbox_cmd))
static bool bfa_nw_auto_recover = true;
@@ -1105,12 +1091,9 @@ static void
bfa_ioc_event_notify(struct bfa_ioc *ioc, enum bfa_ioc_event event)
{
struct bfa_ioc_notify *notify;
- struct list_head *qe;
- list_for_each(qe, &ioc->notify_q) {
- notify = (struct bfa_ioc_notify *)qe;
+ list_for_each_entry(notify, &ioc->notify_q, qe)
notify->cbfn(notify->cbarg, event);
- }
}
static void
@@ -1321,7 +1304,7 @@ bfa_nw_ioc_fwver_get(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr) / sizeof(u32));
i++) {
fwsig[i] =
- swab32(readl((loff) + (ioc->ioc_regs.smem_page_start)));
+ swab32(readl(loff + ioc->ioc_regs.smem_page_start));
loff += sizeof(u32);
}
}
@@ -1387,7 +1370,7 @@ static enum bfi_ioc_img_ver_cmp
bfa_ioc_fw_ver_patch_cmp(struct bfi_ioc_image_hdr *base_fwhdr,
struct bfi_ioc_image_hdr *fwhdr_to_cmp)
{
- if (bfa_ioc_fw_ver_compatible(base_fwhdr, fwhdr_to_cmp) == false)
+ if (!bfa_ioc_fw_ver_compatible(base_fwhdr, fwhdr_to_cmp))
return BFI_IOC_IMG_VER_INCOMP;
if (fwhdr_to_cmp->fwver.patch > base_fwhdr->fwver.patch)
@@ -1398,7 +1381,7 @@ bfa_ioc_fw_ver_patch_cmp(struct bfi_ioc_image_hdr *base_fwhdr,
/* GA takes priority over internal builds of the same patch stream.
* At this point major minor maint and patch numbers are same.
*/
- if (fwhdr_is_ga(base_fwhdr) == true)
+ if (fwhdr_is_ga(base_fwhdr))
if (fwhdr_is_ga(fwhdr_to_cmp))
return BFI_IOC_IMG_VER_SAME;
else
@@ -1692,7 +1675,7 @@ bfa_raw_sem_get(void __iomem *bar)
{
int locked;
- locked = readl((bar + FLASH_SEM_LOCK_REG));
+ locked = readl(bar + FLASH_SEM_LOCK_REG);
return !locked;
}
@@ -1912,10 +1895,8 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
}
void
-bfa_nw_ioc_timeout(void *ioc_arg)
+bfa_nw_ioc_timeout(struct bfa_ioc *ioc)
{
- struct bfa_ioc *ioc = (struct bfa_ioc *) ioc_arg;
-
bfa_fsm_send_event(ioc, IOC_E_TIMEOUT);
}
@@ -1980,10 +1961,9 @@ bfa_ioc_send_getattr(struct bfa_ioc *ioc)
}
void
-bfa_nw_ioc_hb_check(void *cbarg)
+bfa_nw_ioc_hb_check(struct bfa_ioc *ioc)
{
- struct bfa_ioc *ioc = cbarg;
- u32 hb_count;
+ u32 hb_count;
hb_count = readl(ioc->ioc_regs.heartbeat);
if (ioc->hb_count == hb_count) {
@@ -2069,8 +2049,8 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
/**
* write smem
*/
- writel((swab32(fwimg[BFA_IOC_FLASH_OFFSET_IN_CHUNK(i)])),
- ((ioc->ioc_regs.smem_page_start) + (loff)));
+ writel(swab32(fwimg[BFA_IOC_FLASH_OFFSET_IN_CHUNK(i)]),
+ ioc->ioc_regs.smem_page_start + loff);
loff += sizeof(u32);
@@ -2177,7 +2157,8 @@ bfa_ioc_mbox_poll(struct bfa_ioc *ioc)
/**
* Enqueue command to firmware.
*/
- bfa_q_deq(&mod->cmd_q, &cmd);
+ cmd = list_first_entry(&mod->cmd_q, struct bfa_mbox_cmd, qe);
+ list_del(&cmd->qe);
bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
/**
@@ -2198,8 +2179,10 @@ bfa_ioc_mbox_flush(struct bfa_ioc *ioc)
struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
struct bfa_mbox_cmd *cmd;
- while (!list_empty(&mod->cmd_q))
- bfa_q_deq(&mod->cmd_q, &cmd);
+ while (!list_empty(&mod->cmd_q)) {
+ cmd = list_first_entry(&mod->cmd_q, struct bfa_mbox_cmd, qe);
+ list_del(&cmd->qe);
+ }
}
/**
@@ -2223,14 +2206,14 @@ bfa_nw_ioc_smem_read(struct bfa_ioc *ioc, void *tbuf, u32 soff, u32 sz)
/*
* Hold semaphore to serialize pll init and fwtrc.
*/
- if (bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg) == 0)
+ if (!bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg))
return 1;
writel(pgnum, ioc->ioc_regs.host_page_num_fn);
len = sz/sizeof(u32);
for (i = 0; i < len; i++) {
- r32 = swab32(readl((loff) + (ioc->ioc_regs.smem_page_start)));
+ r32 = swab32(readl(loff + ioc->ioc_regs.smem_page_start));
buf[i] = be32_to_cpu(r32);
loff += sizeof(u32);
@@ -2278,7 +2261,7 @@ bfa_nw_ioc_debug_save_ftrc(struct bfa_ioc *ioc)
int tlen;
if (ioc->dbg_fwsave_once) {
- ioc->dbg_fwsave_once = 0;
+ ioc->dbg_fwsave_once = false;
if (ioc->dbg_fwsave_len) {
tlen = ioc->dbg_fwsave_len;
bfa_nw_ioc_debug_fwtrc(ioc, ioc->dbg_fwsave, &tlen);
@@ -2796,7 +2779,7 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc *ioc,
ad_attr->prototype = 0;
ad_attr->pwwn = bfa_ioc_get_pwwn(ioc);
- ad_attr->mac = bfa_nw_ioc_get_mac(ioc);
+ bfa_nw_ioc_get_mac(ioc, ad_attr->mac);
ad_attr->pcie_gen = ioc_attr->pcie_gen;
ad_attr->pcie_lanes = ioc_attr->pcie_lanes;
@@ -2942,10 +2925,10 @@ bfa_ioc_get_pwwn(struct bfa_ioc *ioc)
return ioc->attr->pwwn;
}
-mac_t
-bfa_nw_ioc_get_mac(struct bfa_ioc *ioc)
+void
+bfa_nw_ioc_get_mac(struct bfa_ioc *ioc, u8 *mac)
{
- return ioc->attr->mac;
+ ether_addr_copy(mac, ioc->attr->mac);
}
/* Firmware failure detected. Start recovery actions. */
@@ -2997,9 +2980,8 @@ bfa_iocpf_stop(struct bfa_ioc *ioc)
}
void
-bfa_nw_iocpf_timeout(void *ioc_arg)
+bfa_nw_iocpf_timeout(struct bfa_ioc *ioc)
{
- struct bfa_ioc *ioc = (struct bfa_ioc *) ioc_arg;
enum bfa_iocpf_state iocpf_st;
iocpf_st = bfa_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm);
@@ -3011,10 +2993,8 @@ bfa_nw_iocpf_timeout(void *ioc_arg)
}
void
-bfa_nw_iocpf_sem_timeout(void *ioc_arg)
+bfa_nw_iocpf_sem_timeout(struct bfa_ioc *ioc)
{
- struct bfa_ioc *ioc = (struct bfa_ioc *) ioc_arg;
-
bfa_ioc_hw_sem_get(ioc);
}
@@ -3245,7 +3225,6 @@ bfa_nw_flash_attach(struct bfa_flash *flash, struct bfa_ioc *ioc, void *dev)
flash->op_busy = 0;
bfa_nw_ioc_mbox_regisr(flash->ioc, BFI_MC_FLASH, bfa_flash_intr, flash);
- bfa_q_qe_init(&flash->ioc_notify);
bfa_ioc_notify_init(&flash->ioc_notify, bfa_flash_notify, flash);
list_add_tail(&flash->ioc_notify.qe, &flash->ioc->notify_q);
}
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.h b/drivers/net/ethernet/brocade/bna/bfa_ioc.h
index effb7156e7a4..2c0b4c076355 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.h
@@ -232,12 +232,6 @@ struct bfa_ioc_hwif {
#define bfa_ioc_asic_gen(__ioc) ((__ioc)->asic_gen)
#define bfa_ioc_is_default(__ioc) \
(bfa_ioc_pcifn(__ioc) == bfa_ioc_portid(__ioc))
-#define bfa_ioc_fetch_stats(__ioc, __stats) \
- (((__stats)->drv_stats) = (__ioc)->stats)
-#define bfa_ioc_clr_stats(__ioc) \
- memset(&(__ioc)->stats, 0, sizeof((__ioc)->stats))
-#define bfa_ioc_maxfrsize(__ioc) ((__ioc)->attr->maxfrsize)
-#define bfa_ioc_rx_bbcredit(__ioc) ((__ioc)->attr->rx_bbcredit)
#define bfa_ioc_speed_sup(__ioc) \
BFI_ADAPTER_GETP(SPEED, (__ioc)->attr->adapter_prop)
#define bfa_ioc_get_nports(__ioc) \
@@ -268,13 +262,6 @@ void bfa_nw_ioc_mbox_regisr(struct bfa_ioc *ioc, enum bfi_mclass mc,
((__ioc)->ioc_hwif->ioc_pll_init((__ioc)->pcidev.pci_bar_kva, \
(__ioc)->asic_mode))
-#define bfa_ioc_isr_mode_set(__ioc, __msix) do { \
- if ((__ioc)->ioc_hwif->ioc_isr_mode_set) \
- ((__ioc)->ioc_hwif->ioc_isr_mode_set(__ioc, __msix)); \
-} while (0)
-#define bfa_ioc_ownership_reset(__ioc) \
- ((__ioc)->ioc_hwif->ioc_ownership_reset(__ioc))
-
#define bfa_ioc_lpu_read_stat(__ioc) do { \
if ((__ioc)->ioc_hwif->ioc_lpu_read_stat) \
((__ioc)->ioc_hwif->ioc_lpu_read_stat(__ioc)); \
@@ -309,7 +296,7 @@ void bfa_nw_ioc_fwver_get(struct bfa_ioc *ioc,
struct bfi_ioc_image_hdr *fwhdr);
bool bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc,
struct bfi_ioc_image_hdr *fwhdr);
-mac_t bfa_nw_ioc_get_mac(struct bfa_ioc *ioc);
+void bfa_nw_ioc_get_mac(struct bfa_ioc *ioc, u8 *mac);
void bfa_nw_ioc_debug_memclaim(struct bfa_ioc *ioc, void *dbg_fwsave);
int bfa_nw_ioc_debug_fwtrc(struct bfa_ioc *ioc, void *trcdata, int *trclen);
int bfa_nw_ioc_debug_fwsave(struct bfa_ioc *ioc, void *trcdata, int *trclen);
@@ -317,10 +304,10 @@ int bfa_nw_ioc_debug_fwsave(struct bfa_ioc *ioc, void *trcdata, int *trclen);
/*
* Timeout APIs
*/
-void bfa_nw_ioc_timeout(void *ioc);
-void bfa_nw_ioc_hb_check(void *ioc);
-void bfa_nw_iocpf_timeout(void *ioc);
-void bfa_nw_iocpf_sem_timeout(void *ioc);
+void bfa_nw_ioc_timeout(struct bfa_ioc *ioc);
+void bfa_nw_ioc_hb_check(struct bfa_ioc *ioc);
+void bfa_nw_iocpf_timeout(struct bfa_ioc *ioc);
+void bfa_nw_iocpf_sem_timeout(struct bfa_ioc *ioc);
/*
* F/W Image Size & Chunk
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c b/drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c
index 2e72445dbb4f..74e5ed55ac01 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c
@@ -23,8 +23,7 @@
#include "bfi_reg.h"
#include "bfa_defs.h"
-#define bfa_ioc_ct_sync_pos(__ioc) \
- ((u32) (1 << bfa_ioc_pcifn(__ioc)))
+#define bfa_ioc_ct_sync_pos(__ioc) BIT(bfa_ioc_pcifn(__ioc))
#define BFA_IOC_SYNC_REQD_SH 16
#define bfa_ioc_ct_get_sync_ackd(__val) (__val & 0x0000ffff)
#define bfa_ioc_ct_clear_sync_ackd(__val) (__val & 0xffff0000)
@@ -536,7 +535,7 @@ bfa_ioc_ct_sync_ack(struct bfa_ioc *ioc)
{
u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
- writel((r32 | bfa_ioc_ct_sync_pos(ioc)), ioc->ioc_regs.ioc_fail_sync);
+ writel(r32 | bfa_ioc_ct_sync_pos(ioc), ioc->ioc_regs.ioc_fail_sync);
}
static bool
@@ -667,7 +666,7 @@ bfa_ioc_ct_pll_init(void __iomem *rb, enum bfi_asic_mode asic_mode)
writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P0));
writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P1));
}
- r32 = readl((rb + PSS_CTL_REG));
+ r32 = readl(rb + PSS_CTL_REG);
r32 &= ~__PSS_LMEM_RESET;
writel(r32, (rb + PSS_CTL_REG));
udelay(1000);
@@ -678,7 +677,7 @@ bfa_ioc_ct_pll_init(void __iomem *rb, enum bfi_asic_mode asic_mode)
writel(__EDRAM_BISTR_START, (rb + MBIST_CTL_REG));
udelay(1000);
- r32 = readl((rb + MBIST_STAT_REG));
+ r32 = readl(rb + MBIST_STAT_REG);
writel(0, (rb + MBIST_CTL_REG));
return BFA_STATUS_OK;
}
@@ -691,7 +690,7 @@ bfa_ioc_ct2_sclk_init(void __iomem *rb)
/*
* put s_clk PLL and PLL FSM in reset
*/
- r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG));
+ r32 = readl(rb + CT2_APP_PLL_SCLK_CTL_REG);
r32 &= ~(__APP_PLL_SCLK_ENABLE | __APP_PLL_SCLK_LRESETN);
r32 |= (__APP_PLL_SCLK_ENARST | __APP_PLL_SCLK_BYPASS |
__APP_PLL_SCLK_LOGIC_SOFT_RESET);
@@ -701,28 +700,28 @@ bfa_ioc_ct2_sclk_init(void __iomem *rb)
* Ignore mode and program for the max clock (which is FC16)
* Firmware/NFC will do the PLL init appropriately
*/
- r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG));
+ r32 = readl(rb + CT2_APP_PLL_SCLK_CTL_REG);
r32 &= ~(__APP_PLL_SCLK_REFCLK_SEL | __APP_PLL_SCLK_CLK_DIV2);
writel(r32, (rb + CT2_APP_PLL_SCLK_CTL_REG));
/*
* while doing PLL init dont clock gate ethernet subsystem
*/
- r32 = readl((rb + CT2_CHIP_MISC_PRG));
- writel((r32 | __ETH_CLK_ENABLE_PORT0),
- (rb + CT2_CHIP_MISC_PRG));
+ r32 = readl(rb + CT2_CHIP_MISC_PRG);
+ writel(r32 | __ETH_CLK_ENABLE_PORT0,
+ rb + CT2_CHIP_MISC_PRG);
- r32 = readl((rb + CT2_PCIE_MISC_REG));
- writel((r32 | __ETH_CLK_ENABLE_PORT1),
- (rb + CT2_PCIE_MISC_REG));
+ r32 = readl(rb + CT2_PCIE_MISC_REG);
+ writel(r32 | __ETH_CLK_ENABLE_PORT1,
+ rb + CT2_PCIE_MISC_REG);
/*
* set sclk value
*/
- r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG));
+ r32 = readl(rb + CT2_APP_PLL_SCLK_CTL_REG);
r32 &= (__P_SCLK_PLL_LOCK | __APP_PLL_SCLK_REFCLK_SEL |
__APP_PLL_SCLK_CLK_DIV2);
- writel(r32 | 0x1061731b, (rb + CT2_APP_PLL_SCLK_CTL_REG));
+ writel(r32 | 0x1061731b, rb + CT2_APP_PLL_SCLK_CTL_REG);
/*
* poll for s_clk lock or delay 1ms
@@ -743,28 +742,28 @@ bfa_ioc_ct2_lclk_init(void __iomem *rb)
/*
* put l_clk PLL and PLL FSM in reset
*/
- r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG));
+ r32 = readl(rb + CT2_APP_PLL_LCLK_CTL_REG);
r32 &= ~(__APP_PLL_LCLK_ENABLE | __APP_PLL_LCLK_LRESETN);
r32 |= (__APP_PLL_LCLK_ENARST | __APP_PLL_LCLK_BYPASS |
__APP_PLL_LCLK_LOGIC_SOFT_RESET);
- writel(r32, (rb + CT2_APP_PLL_LCLK_CTL_REG));
+ writel(r32, rb + CT2_APP_PLL_LCLK_CTL_REG);
/*
* set LPU speed (set for FC16 which will work for other modes)
*/
- r32 = readl((rb + CT2_CHIP_MISC_PRG));
+ r32 = readl(rb + CT2_CHIP_MISC_PRG);
writel(r32, (rb + CT2_CHIP_MISC_PRG));
/*
* set LPU half speed (set for FC16 which will work for other modes)
*/
- r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG));
- writel(r32, (rb + CT2_APP_PLL_LCLK_CTL_REG));
+ r32 = readl(rb + CT2_APP_PLL_LCLK_CTL_REG);
+ writel(r32, rb + CT2_APP_PLL_LCLK_CTL_REG);
/*
* set lclk for mode (set for FC16)
*/
- r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG));
+ r32 = readl(rb + CT2_APP_PLL_LCLK_CTL_REG);
r32 &= (__P_LCLK_PLL_LOCK | __APP_LPUCLK_HALFSPEED);
r32 |= 0x20c1731b;
writel(r32, (rb + CT2_APP_PLL_LCLK_CTL_REG));
@@ -780,14 +779,14 @@ bfa_ioc_ct2_mem_init(void __iomem *rb)
{
u32 r32;
- r32 = readl((rb + PSS_CTL_REG));
+ r32 = readl(rb + PSS_CTL_REG);
r32 &= ~__PSS_LMEM_RESET;
- writel(r32, (rb + PSS_CTL_REG));
+ writel(r32, rb + PSS_CTL_REG);
udelay(1000);
- writel(__EDRAM_BISTR_START, (rb + CT2_MBIST_CTL_REG));
+ writel(__EDRAM_BISTR_START, rb + CT2_MBIST_CTL_REG);
udelay(1000);
- writel(0, (rb + CT2_MBIST_CTL_REG));
+ writel(0, rb + CT2_MBIST_CTL_REG);
}
static void
@@ -801,22 +800,22 @@ bfa_ioc_ct2_mac_reset(void __iomem *rb)
/*
* release soft reset on s_clk & l_clk
*/
- r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG));
- writel((r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET),
- (rb + CT2_APP_PLL_SCLK_CTL_REG));
+ r32 = readl(rb + CT2_APP_PLL_SCLK_CTL_REG);
+ writel(r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET,
+ rb + CT2_APP_PLL_SCLK_CTL_REG);
/*
* release soft reset on s_clk & l_clk
*/
- r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG));
- writel((r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET),
- (rb + CT2_APP_PLL_LCLK_CTL_REG));
+ r32 = readl(rb + CT2_APP_PLL_LCLK_CTL_REG);
+ writel(r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET,
+ rb + CT2_APP_PLL_LCLK_CTL_REG);
/* put port0, port1 MAC & AHB in reset */
- writel((__CSI_MAC_RESET | __CSI_MAC_AHB_RESET),
- (rb + CT2_CSI_MAC_CONTROL_REG(0)));
- writel((__CSI_MAC_RESET | __CSI_MAC_AHB_RESET),
- (rb + CT2_CSI_MAC_CONTROL_REG(1)));
+ writel(__CSI_MAC_RESET | __CSI_MAC_AHB_RESET,
+ rb + CT2_CSI_MAC_CONTROL_REG(0));
+ writel(__CSI_MAC_RESET | __CSI_MAC_AHB_RESET,
+ rb + CT2_CSI_MAC_CONTROL_REG(1));
}
#define CT2_NFC_MAX_DELAY 1000
@@ -861,8 +860,8 @@ bfa_ioc_ct2_pll_init(void __iomem *rb, enum bfi_asic_mode asic_mode)
nfc_ver = readl(rb + CT2_RSC_GPR15_REG);
- if ((wgn == (__A2T_AHB_LOAD | __WGN_READY)) &&
- (nfc_ver >= CT2_NFC_VER_VALID)) {
+ if (wgn == (__A2T_AHB_LOAD | __WGN_READY) &&
+ nfc_ver >= CT2_NFC_VER_VALID) {
if (bfa_ioc_ct2_nfc_halted(rb))
bfa_ioc_ct2_nfc_resume(rb);
writel(__RESET_AND_START_SCLK_LCLK_PLLS,
@@ -899,19 +898,19 @@ bfa_ioc_ct2_pll_init(void __iomem *rb, enum bfi_asic_mode asic_mode)
bfa_ioc_ct2_lclk_init(rb);
/* release soft reset on s_clk & l_clk */
- r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG));
+ r32 = readl(rb + CT2_APP_PLL_SCLK_CTL_REG);
writel(r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET,
rb + CT2_APP_PLL_SCLK_CTL_REG);
- r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG));
+ r32 = readl(rb + CT2_APP_PLL_LCLK_CTL_REG);
writel(r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET,
rb + CT2_APP_PLL_LCLK_CTL_REG);
}
/* Announce flash device presence, if flash was corrupted. */
if (wgn == (__WGN_READY | __GLBL_PF_VF_CFG_RDY)) {
- r32 = readl((rb + PSS_GPIO_OUT_REG));
+ r32 = readl(rb + PSS_GPIO_OUT_REG);
writel(r32 & ~1, rb + PSS_GPIO_OUT_REG);
- r32 = readl((rb + PSS_GPIO_OE_REG));
+ r32 = readl(rb + PSS_GPIO_OE_REG);
writel(r32 | 1, rb + PSS_GPIO_OE_REG);
}
@@ -919,27 +918,27 @@ bfa_ioc_ct2_pll_init(void __iomem *rb, enum bfi_asic_mode asic_mode)
* Mask the interrupts and clear any
* pending interrupts left by BIOS/EFI
*/
- writel(1, (rb + CT2_LPU0_HOSTFN_MBOX0_MSK));
- writel(1, (rb + CT2_LPU1_HOSTFN_MBOX0_MSK));
+ writel(1, rb + CT2_LPU0_HOSTFN_MBOX0_MSK);
+ writel(1, rb + CT2_LPU1_HOSTFN_MBOX0_MSK);
/* For first time initialization, no need to clear interrupts */
r32 = readl(rb + HOST_SEM5_REG);
if (r32 & 0x1) {
- r32 = readl((rb + CT2_LPU0_HOSTFN_CMD_STAT));
+ r32 = readl(rb + CT2_LPU0_HOSTFN_CMD_STAT);
if (r32 == 1) {
- writel(1, (rb + CT2_LPU0_HOSTFN_CMD_STAT));
- readl((rb + CT2_LPU0_HOSTFN_CMD_STAT));
+ writel(1, rb + CT2_LPU0_HOSTFN_CMD_STAT);
+ readl(rb + CT2_LPU0_HOSTFN_CMD_STAT);
}
- r32 = readl((rb + CT2_LPU1_HOSTFN_CMD_STAT));
+ r32 = readl(rb + CT2_LPU1_HOSTFN_CMD_STAT);
if (r32 == 1) {
- writel(1, (rb + CT2_LPU1_HOSTFN_CMD_STAT));
- readl((rb + CT2_LPU1_HOSTFN_CMD_STAT));
+ writel(1, rb + CT2_LPU1_HOSTFN_CMD_STAT);
+ readl(rb + CT2_LPU1_HOSTFN_CMD_STAT);
}
}
bfa_ioc_ct2_mem_init(rb);
- writel(BFI_IOC_UNINIT, (rb + CT2_BFA_IOC0_STATE_REG));
- writel(BFI_IOC_UNINIT, (rb + CT2_BFA_IOC1_STATE_REG));
+ writel(BFI_IOC_UNINIT, rb + CT2_BFA_IOC0_STATE_REG);
+ writel(BFI_IOC_UNINIT, rb + CT2_BFA_IOC1_STATE_REG);
return BFA_STATUS_OK;
}
diff --git a/drivers/net/ethernet/brocade/bna/bfa_msgq.c b/drivers/net/ethernet/brocade/bna/bfa_msgq.c
index c07d5b9372f4..9c5bb24e8abb 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_msgq.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_msgq.c
@@ -66,8 +66,9 @@ cmdq_sm_stopped_entry(struct bfa_msgq_cmdq *cmdq)
cmdq->offset = 0;
cmdq->bytes_to_copy = 0;
while (!list_empty(&cmdq->pending_q)) {
- bfa_q_deq(&cmdq->pending_q, &cmdq_ent);
- bfa_q_qe_init(&cmdq_ent->qe);
+ cmdq_ent = list_first_entry(&cmdq->pending_q,
+ struct bfa_msgq_cmd_entry, qe);
+ list_del(&cmdq_ent->qe);
call_cmdq_ent_cbfn(cmdq_ent, BFA_STATUS_FAILED);
}
}
@@ -242,8 +243,8 @@ bfa_msgq_cmdq_ci_update(struct bfa_msgq_cmdq *cmdq, struct bfi_mbmsg *mb)
/* Walk through pending list to see if the command can be posted */
while (!list_empty(&cmdq->pending_q)) {
- cmd =
- (struct bfa_msgq_cmd_entry *)bfa_q_first(&cmdq->pending_q);
+ cmd = list_first_entry(&cmdq->pending_q,
+ struct bfa_msgq_cmd_entry, qe);
if (ntohs(cmd->msg_hdr->num_entries) <=
BFA_MSGQ_FREE_CNT(cmdq)) {
list_del(&cmd->qe);
@@ -615,7 +616,6 @@ bfa_msgq_attach(struct bfa_msgq *msgq, struct bfa_ioc *ioc)
bfa_msgq_rspq_attach(&msgq->rspq, msgq);
bfa_nw_ioc_mbox_regisr(msgq->ioc, BFI_MC_MSGQ, bfa_msgq_isr, msgq);
- bfa_q_qe_init(&msgq->ioc_notify);
bfa_ioc_notify_init(&msgq->ioc_notify, bfa_msgq_notify, msgq);
bfa_nw_ioc_notify_register(msgq->ioc, &msgq->ioc_notify);
}
diff --git a/drivers/net/ethernet/brocade/bna/bfi.h b/drivers/net/ethernet/brocade/bna/bfi.h
index 2bcde4042268..81e59ea8b4f2 100644
--- a/drivers/net/ethernet/brocade/bna/bfi.h
+++ b/drivers/net/ethernet/brocade/bna/bfi.h
@@ -21,8 +21,6 @@
#include "bfa_defs.h"
-#pragma pack(1)
-
/* BFI FW image type */
#define BFI_FLASH_CHUNK_SZ 256 /*!< Flash chunk size */
#define BFI_FLASH_CHUNK_SZ_WORDS (BFI_FLASH_CHUNK_SZ/sizeof(u32))
@@ -36,10 +34,10 @@ struct bfi_mhdr {
struct {
u8 qid;
u8 fn_lpu; /*!< msg destination */
- } h2i;
+ } __packed h2i;
u16 i2htok; /*!< token in msgs to host */
- } mtag;
-};
+ } __packed mtag;
+} __packed;
#define bfi_fn_lpu(__fn, __lpu) ((__fn) << 1 | (__lpu))
#define bfi_mhdr_2_fn(_mh) ((_mh)->mtag.h2i.fn_lpu >> 1)
@@ -75,14 +73,14 @@ union bfi_addr_u {
struct {
u32 addr_lo;
u32 addr_hi;
- } a32;
-};
+ } __packed a32;
+} __packed;
/* Generic DMA addr-len pair. */
struct bfi_alen {
union bfi_addr_u al_addr; /* DMA addr of buffer */
u32 al_len; /* length of buffer */
-};
+} __packed;
/*
* Large Message structure - 128 Bytes size Msgs
@@ -96,7 +94,7 @@ struct bfi_alen {
struct bfi_mbmsg {
struct bfi_mhdr mh;
u32 pl[BFI_MBMSG_SZ];
-};
+} __packed;
/* Supported PCI function class codes (personality) */
enum bfi_pcifn_class {
@@ -184,19 +182,19 @@ enum bfi_ioc_i2h_msgs {
struct bfi_ioc_getattr_req {
struct bfi_mhdr mh;
union bfi_addr_u attr_addr;
-};
+} __packed;
struct bfi_ioc_attr {
u64 mfg_pwwn; /*!< Mfg port wwn */
u64 mfg_nwwn; /*!< Mfg node wwn */
- mac_t mfg_mac; /*!< Mfg mac */
+ u8 mfg_mac[ETH_ALEN]; /*!< Mfg mac */
u8 port_mode; /* enum bfi_port_mode */
u8 rsvd_a;
u64 pwwn;
u64 nwwn;
- mac_t mac; /*!< PBC or Mfg mac */
+ u8 mac[ETH_ALEN]; /*!< PBC or Mfg mac */
u16 rsvd_b;
- mac_t fcoe_mac;
+ u8 fcoe_mac[ETH_ALEN];
u16 rsvd_c;
char brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)];
u8 pcie_gen;
@@ -211,14 +209,14 @@ struct bfi_ioc_attr {
char optrom_version[BFA_VERSION_LEN];
struct bfa_mfg_vpd vpd;
u32 card_type; /*!< card type */
-};
+} __packed;
/* BFI_IOC_I2H_GETATTR_REPLY message */
struct bfi_ioc_getattr_reply {
struct bfi_mhdr mh; /*!< Common msg header */
u8 status; /*!< cfg reply status */
u8 rsvd[3];
-};
+} __packed;
/* Firmware memory page offsets */
#define BFI_IOC_SMEM_PG0_CB (0x40)
@@ -256,7 +254,7 @@ struct bfi_ioc_fwver {
u8 build;
u8 rsvd[2];
#endif
-};
+} __packed;
struct bfi_ioc_image_hdr {
u32 signature; /*!< constant signature */
@@ -269,7 +267,7 @@ struct bfi_ioc_image_hdr {
u32 rsvd_b[2];
struct bfi_ioc_fwver fwver;
u32 md5sum[BFI_IOC_MD5SUM_SZ];
-};
+} __packed;
enum bfi_ioc_img_ver_cmp {
BFI_IOC_IMG_VER_INCOMP,
@@ -301,7 +299,7 @@ enum bfi_port_mode {
struct bfi_ioc_hbeat {
struct bfi_mhdr mh; /*!< common msg header */
u32 hb_count; /*!< current heart beat count */
-};
+} __packed;
/* IOC hardware/firmware state */
enum bfi_ioc_state {
@@ -317,8 +315,6 @@ enum bfi_ioc_state {
BFI_IOC_MEMTEST = 9, /*!< IOC is doing memtest */
};
-#define BFI_IOC_ENDIAN_SIG 0x12345678
-
enum {
BFI_ADAPTER_TYPE_FC = 0x01, /*!< FC adapters */
BFI_ADAPTER_TYPE_MK = 0x0f0000, /*!< adapter type mask */
@@ -337,12 +333,6 @@ enum {
BFI_ADAPTER_ ## __prop ## _SH)
#define BFI_ADAPTER_SETP(__prop, __val) \
((__val) << BFI_ADAPTER_ ## __prop ## _SH)
-#define BFI_ADAPTER_IS_PROTO(__adap_type) \
- ((__adap_type) & BFI_ADAPTER_PROTO)
-#define BFI_ADAPTER_IS_TTV(__adap_type) \
- ((__adap_type) & BFI_ADAPTER_TTV)
-#define BFI_ADAPTER_IS_UNSUPP(__adap_type) \
- ((__adap_type) & BFI_ADAPTER_UNSUPP)
#define BFI_ADAPTER_IS_SPECIAL(__adap_type) \
((__adap_type) & (BFI_ADAPTER_TTV | BFI_ADAPTER_PROTO | \
BFI_ADAPTER_UNSUPP))
@@ -353,7 +343,7 @@ struct bfi_ioc_ctrl_req {
u16 clscode;
u16 rsvd;
u32 tv_sec;
-};
+} __packed;
/* BFI_IOC_I2H_ENABLE_REPLY & BFI_IOC_I2H_DISABLE_REPLY messages */
struct bfi_ioc_ctrl_reply {
@@ -362,7 +352,7 @@ struct bfi_ioc_ctrl_reply {
u8 port_mode; /*!< enum bfa_mode */
u8 cap_bm; /*!< capability bit mask */
u8 rsvd;
-};
+} __packed;
#define BFI_IOC_MSGSZ 8
/* H2I Messages */
@@ -372,14 +362,14 @@ union bfi_ioc_h2i_msg_u {
struct bfi_ioc_ctrl_req disable_req;
struct bfi_ioc_getattr_req getattr_req;
u32 mboxmsg[BFI_IOC_MSGSZ];
-};
+} __packed;
/* I2H Messages */
union bfi_ioc_i2h_msg_u {
struct bfi_mhdr mh;
struct bfi_ioc_ctrl_reply fw_event;
u32 mboxmsg[BFI_IOC_MSGSZ];
-};
+} __packed;
/*----------------------------------------------------------------------
* MSGQ
@@ -408,7 +398,7 @@ struct bfi_msgq_mhdr {
u16 num_entries;
u8 enet_id;
u8 rsvd[1];
-};
+} __packed;
#define bfi_msgq_mhdr_set(_mh, _mc, _mid, _tok, _enet_id) do { \
(_mh).msg_class = (_mc); \
@@ -430,21 +420,21 @@ struct bfi_msgq {
union bfi_addr_u addr;
u16 q_depth; /* Total num of entries in the queue */
u8 rsvd[2];
-};
+} __packed;
/* BFI_ENET_MSGQ_CFG_REQ TBD init or cfg? */
struct bfi_msgq_cfg_req {
struct bfi_mhdr mh;
struct bfi_msgq cmdq;
struct bfi_msgq rspq;
-};
+} __packed;
/* BFI_ENET_MSGQ_CFG_RSP */
struct bfi_msgq_cfg_rsp {
struct bfi_mhdr mh;
u8 cmd_status;
u8 rsvd[3];
-};
+} __packed;
/* BFI_MSGQ_H2I_DOORBELL */
struct bfi_msgq_h2i_db {
@@ -452,8 +442,8 @@ struct bfi_msgq_h2i_db {
union {
u16 cmdq_pi;
u16 rspq_ci;
- } idx;
-};
+ } __packed idx;
+} __packed;
/* BFI_MSGQ_I2H_DOORBELL */
struct bfi_msgq_i2h_db {
@@ -461,8 +451,8 @@ struct bfi_msgq_i2h_db {
union {
u16 rspq_pi;
u16 cmdq_ci;
- } idx;
-};
+ } __packed idx;
+} __packed;
#define BFI_CMD_COPY_SZ 28
@@ -470,14 +460,14 @@ struct bfi_msgq_i2h_db {
struct bfi_msgq_h2i_cmdq_copy_rsp {
struct bfi_mhdr mh;
u8 data[BFI_CMD_COPY_SZ];
-};
+} __packed;
/* BFI_MSGQ_I2H_CMD_COPY_REQ */
struct bfi_msgq_i2h_cmdq_copy_req {
struct bfi_mhdr mh;
u16 offset;
u16 len;
-};
+} __packed;
/*
* FLASH module specific
@@ -505,7 +495,7 @@ enum bfi_flash_i2h_msgs {
struct bfi_flash_query_req {
struct bfi_mhdr mh; /* Common msg header */
struct bfi_alen alen;
-};
+} __packed;
/*
* Flash write request
@@ -519,7 +509,7 @@ struct bfi_flash_write_req {
u8 rsv[2];
u32 offset;
u32 length;
-};
+} __packed;
/*
* Flash read request
@@ -532,7 +522,7 @@ struct bfi_flash_read_req {
u32 offset;
u32 length;
struct bfi_alen alen;
-};
+} __packed;
/*
* Flash query response
@@ -540,7 +530,7 @@ struct bfi_flash_read_req {
struct bfi_flash_query_rsp {
struct bfi_mhdr mh; /* Common msg header */
u32 status;
-};
+} __packed;
/*
* Flash read response
@@ -552,7 +542,7 @@ struct bfi_flash_read_rsp {
u8 rsv[3];
u32 status;
u32 length;
-};
+} __packed;
/*
* Flash write response
@@ -564,8 +554,6 @@ struct bfi_flash_write_rsp {
u8 rsv[3];
u32 status;
u32 length;
-};
-
-#pragma pack()
+} __packed;
#endif /* __BFI_H__ */
diff --git a/drivers/net/ethernet/brocade/bna/bfi_cna.h b/drivers/net/ethernet/brocade/bna/bfi_cna.h
index bd605bee72ee..fad651101c48 100644
--- a/drivers/net/ethernet/brocade/bna/bfi_cna.h
+++ b/drivers/net/ethernet/brocade/bna/bfi_cna.h
@@ -22,8 +22,6 @@
#include "bfi.h"
#include "bfa_defs_cna.h"
-#pragma pack(1)
-
enum bfi_port_h2i {
BFI_PORT_H2I_ENABLE_REQ = (1),
BFI_PORT_H2I_DISABLE_REQ = (2),
@@ -43,7 +41,7 @@ struct bfi_port_generic_req {
struct bfi_mhdr mh; /*!< msg header */
u32 msgtag; /*!< msgtag for reply */
u32 rsvd;
-};
+} __packed;
/* Generic RSP type */
struct bfi_port_generic_rsp {
@@ -51,13 +49,13 @@ struct bfi_port_generic_rsp {
u8 status; /*!< port enable status */
u8 rsvd[3];
u32 msgtag; /*!< msgtag for reply */
-};
+} __packed;
/* BFI_PORT_H2I_GET_STATS_REQ */
struct bfi_port_get_stats_req {
struct bfi_mhdr mh; /*!< common msg header */
union bfi_addr_u dma_addr;
-};
+} __packed;
union bfi_port_h2i_msg_u {
struct bfi_mhdr mh;
@@ -65,7 +63,7 @@ union bfi_port_h2i_msg_u {
struct bfi_port_generic_req disable_req;
struct bfi_port_get_stats_req getstats_req;
struct bfi_port_generic_req clearstats_req;
-};
+} __packed;
union bfi_port_i2h_msg_u {
struct bfi_mhdr mh;
@@ -73,7 +71,7 @@ union bfi_port_i2h_msg_u {
struct bfi_port_generic_rsp disable_rsp;
struct bfi_port_generic_rsp getstats_rsp;
struct bfi_port_generic_rsp clearstats_rsp;
-};
+} __packed;
/* @brief Mailbox commands from host to (DCBX/LLDP) firmware */
enum bfi_cee_h2i_msgs {
@@ -97,7 +95,7 @@ enum bfi_cee_i2h_msgs {
*/
struct bfi_lldp_reset_stats {
struct bfi_mhdr mh;
-};
+} __packed;
/*
* @brief H2I command structure for resetting the stats.
@@ -105,7 +103,7 @@ struct bfi_lldp_reset_stats {
*/
struct bfi_cee_reset_stats {
struct bfi_mhdr mh;
-};
+} __packed;
/*
* @brief get configuration command from host
@@ -114,7 +112,7 @@ struct bfi_cee_reset_stats {
struct bfi_cee_get_req {
struct bfi_mhdr mh;
union bfi_addr_u dma_addr;
-};
+} __packed;
/*
* @brief reply message from firmware
@@ -124,7 +122,7 @@ struct bfi_cee_get_rsp {
struct bfi_mhdr mh;
u8 cmd_status;
u8 rsvd[3];
-};
+} __packed;
/*
* @brief get configuration command from host
@@ -133,7 +131,7 @@ struct bfi_cee_get_rsp {
struct bfi_cee_stats_req {
struct bfi_mhdr mh;
union bfi_addr_u dma_addr;
-};
+} __packed;
/*
* @brief reply message from firmware
@@ -143,22 +141,20 @@ struct bfi_cee_stats_rsp {
struct bfi_mhdr mh;
u8 cmd_status;
u8 rsvd[3];
-};
+} __packed;
/* @brief mailbox command structures from host to firmware */
union bfi_cee_h2i_msg_u {
struct bfi_mhdr mh;
struct bfi_cee_get_req get_req;
struct bfi_cee_stats_req stats_req;
-};
+} __packed;
/* @brief mailbox message structures from firmware to host */
union bfi_cee_i2h_msg_u {
struct bfi_mhdr mh;
struct bfi_cee_get_rsp get_rsp;
struct bfi_cee_stats_rsp stats_rsp;
-};
-
-#pragma pack()
+} __packed;
#endif /* __BFI_CNA_H__ */
diff --git a/drivers/net/ethernet/brocade/bna/bfi_enet.h b/drivers/net/ethernet/brocade/bna/bfi_enet.h
index bccca3bbadb8..d7be7ea8c7f5 100644
--- a/drivers/net/ethernet/brocade/bna/bfi_enet.h
+++ b/drivers/net/ethernet/brocade/bna/bfi_enet.h
@@ -36,8 +36,6 @@
#include "bfa_defs.h"
#include "bfi.h"
-#pragma pack(1)
-
#define BFI_ENET_CFG_MAX 32 /* Max resources per PF */
#define BFI_ENET_TXQ_PRIO_MAX 8
@@ -59,8 +57,8 @@ union bfi_addr_be_u {
struct {
u32 addr_hi; /* Most Significant 32-bits */
u32 addr_lo; /* Least Significant 32-Bits */
- } a32;
-};
+ } __packed a32;
+} __packed;
/* T X Q U E U E D E F I N E S */
/* TxQ Vector (a.k.a. Tx-Buffer Descriptor) */
@@ -70,13 +68,13 @@ union bfi_addr_be_u {
#define BFI_ENET_TXQ_WI_EXTENSION (0x104) /* Extension WI */
/* TxQ Entry Control Flags */
-#define BFI_ENET_TXQ_WI_CF_FCOE_CRC (1 << 8)
-#define BFI_ENET_TXQ_WI_CF_IPID_MODE (1 << 5)
-#define BFI_ENET_TXQ_WI_CF_INS_PRIO (1 << 4)
-#define BFI_ENET_TXQ_WI_CF_INS_VLAN (1 << 3)
-#define BFI_ENET_TXQ_WI_CF_UDP_CKSUM (1 << 2)
-#define BFI_ENET_TXQ_WI_CF_TCP_CKSUM (1 << 1)
-#define BFI_ENET_TXQ_WI_CF_IP_CKSUM (1 << 0)
+#define BFI_ENET_TXQ_WI_CF_FCOE_CRC BIT(8)
+#define BFI_ENET_TXQ_WI_CF_IPID_MODE BIT(5)
+#define BFI_ENET_TXQ_WI_CF_INS_PRIO BIT(4)
+#define BFI_ENET_TXQ_WI_CF_INS_VLAN BIT(3)
+#define BFI_ENET_TXQ_WI_CF_UDP_CKSUM BIT(2)
+#define BFI_ENET_TXQ_WI_CF_TCP_CKSUM BIT(1)
+#define BFI_ENET_TXQ_WI_CF_IP_CKSUM BIT(0)
struct bfi_enet_txq_wi_base {
u8 reserved;
@@ -88,28 +86,28 @@ struct bfi_enet_txq_wi_base {
u16 vlan_tag;
u16 lso_mss; /* Only 14 LSB are valid */
u32 frame_length; /* Only 24 LSB are valid */
-};
+} __packed;
struct bfi_enet_txq_wi_ext {
u16 reserved;
u16 opcode; /* BFI_ENET_TXQ_WI_EXTENSION */
u32 reserved2[3];
-};
+} __packed;
struct bfi_enet_txq_wi_vector { /* Tx Buffer Descriptor */
u16 reserved;
u16 length; /* Only 14 LSB are valid */
union bfi_addr_be_u addr;
-};
+} __packed;
/* TxQ Entry Structure */
struct bfi_enet_txq_entry {
union {
struct bfi_enet_txq_wi_base base;
struct bfi_enet_txq_wi_ext ext;
- } wi;
+ } __packed wi;
struct bfi_enet_txq_wi_vector vector[BFI_ENET_TXQ_WI_VECT_MAX];
-};
+} __packed;
#define wi_hdr wi.base
#define wi_ext_hdr wi.ext
@@ -120,36 +118,36 @@ struct bfi_enet_txq_entry {
/* R X Q U E U E D E F I N E S */
struct bfi_enet_rxq_entry {
union bfi_addr_be_u rx_buffer;
-};
+} __packed;
/* R X C O M P L E T I O N Q U E U E D E F I N E S */
/* CQ Entry Flags */
-#define BFI_ENET_CQ_EF_MAC_ERROR (1 << 0)
-#define BFI_ENET_CQ_EF_FCS_ERROR (1 << 1)
-#define BFI_ENET_CQ_EF_TOO_LONG (1 << 2)
-#define BFI_ENET_CQ_EF_FC_CRC_OK (1 << 3)
+#define BFI_ENET_CQ_EF_MAC_ERROR BIT(0)
+#define BFI_ENET_CQ_EF_FCS_ERROR BIT(1)
+#define BFI_ENET_CQ_EF_TOO_LONG BIT(2)
+#define BFI_ENET_CQ_EF_FC_CRC_OK BIT(3)
-#define BFI_ENET_CQ_EF_RSVD1 (1 << 4)
-#define BFI_ENET_CQ_EF_L4_CKSUM_OK (1 << 5)
-#define BFI_ENET_CQ_EF_L3_CKSUM_OK (1 << 6)
-#define BFI_ENET_CQ_EF_HDS_HEADER (1 << 7)
+#define BFI_ENET_CQ_EF_RSVD1 BIT(4)
+#define BFI_ENET_CQ_EF_L4_CKSUM_OK BIT(5)
+#define BFI_ENET_CQ_EF_L3_CKSUM_OK BIT(6)
+#define BFI_ENET_CQ_EF_HDS_HEADER BIT(7)
-#define BFI_ENET_CQ_EF_UDP (1 << 8)
-#define BFI_ENET_CQ_EF_TCP (1 << 9)
-#define BFI_ENET_CQ_EF_IP_OPTIONS (1 << 10)
-#define BFI_ENET_CQ_EF_IPV6 (1 << 11)
+#define BFI_ENET_CQ_EF_UDP BIT(8)
+#define BFI_ENET_CQ_EF_TCP BIT(9)
+#define BFI_ENET_CQ_EF_IP_OPTIONS BIT(10)
+#define BFI_ENET_CQ_EF_IPV6 BIT(11)
-#define BFI_ENET_CQ_EF_IPV4 (1 << 12)
-#define BFI_ENET_CQ_EF_VLAN (1 << 13)
-#define BFI_ENET_CQ_EF_RSS (1 << 14)
-#define BFI_ENET_CQ_EF_RSVD2 (1 << 15)
+#define BFI_ENET_CQ_EF_IPV4 BIT(12)
+#define BFI_ENET_CQ_EF_VLAN BIT(13)
+#define BFI_ENET_CQ_EF_RSS BIT(14)
+#define BFI_ENET_CQ_EF_RSVD2 BIT(15)
-#define BFI_ENET_CQ_EF_MCAST_MATCH (1 << 16)
-#define BFI_ENET_CQ_EF_MCAST (1 << 17)
-#define BFI_ENET_CQ_EF_BCAST (1 << 18)
-#define BFI_ENET_CQ_EF_REMOTE (1 << 19)
+#define BFI_ENET_CQ_EF_MCAST_MATCH BIT(16)
+#define BFI_ENET_CQ_EF_MCAST BIT(17)
+#define BFI_ENET_CQ_EF_BCAST BIT(18)
+#define BFI_ENET_CQ_EF_REMOTE BIT(19)
-#define BFI_ENET_CQ_EF_LOCAL (1 << 20)
+#define BFI_ENET_CQ_EF_LOCAL BIT(20)
/* CQ Entry Structure */
struct bfi_enet_cq_entry {
@@ -161,7 +159,7 @@ struct bfi_enet_cq_entry {
u8 reserved1;
u8 reserved2;
u8 rxq_id;
-};
+} __packed;
/* E N E T C O N T R O L P A T H C O M M A N D S */
struct bfi_enet_q {
@@ -169,23 +167,23 @@ struct bfi_enet_q {
union bfi_addr_u first_entry;
u16 pages; /* # of pages */
u16 page_sz;
-};
+} __packed;
struct bfi_enet_txq {
struct bfi_enet_q q;
u8 priority;
u8 rsvd[3];
-};
+} __packed;
struct bfi_enet_rxq {
struct bfi_enet_q q;
u16 rx_buffer_size;
u16 rsvd;
-};
+} __packed;
struct bfi_enet_cq {
struct bfi_enet_q q;
-};
+} __packed;
struct bfi_enet_ib_cfg {
u8 int_pkt_dma;
@@ -198,16 +196,16 @@ struct bfi_enet_ib_cfg {
u32 inter_pkt_timeout;
u8 inter_pkt_count;
u8 rsvd1[3];
-};
+} __packed;
struct bfi_enet_ib {
union bfi_addr_u index_addr;
union {
u16 msix_index;
u16 intx_bitmask;
- } intr;
+ } __packed intr;
u16 rsvd;
-};
+} __packed;
/* ENET command messages */
enum bfi_enet_h2i_msgs {
@@ -355,7 +353,7 @@ enum bfi_enet_err {
*/
struct bfi_enet_req {
struct bfi_msgq_mhdr mh;
-};
+} __packed;
/* Enable/Disable Request
*
@@ -370,7 +368,7 @@ struct bfi_enet_enable_req {
struct bfi_msgq_mhdr mh;
u8 enable; /* 1 = enable; 0 = disable */
u8 rsvd[3];
-};
+} __packed;
/* Generic Response */
struct bfi_enet_rsp {
@@ -378,7 +376,7 @@ struct bfi_enet_rsp {
u8 error; /*!< if error see cmd_offset */
u8 rsvd;
u16 cmd_offset; /*!< offset to invalid parameter */
-};
+} __packed;
/* GLOBAL CONFIGURATION */
@@ -387,7 +385,7 @@ struct bfi_enet_rsp {
*/
struct bfi_enet_attr_req {
struct bfi_msgq_mhdr mh;
-};
+} __packed;
/* bfi_enet_attr_rsp is used by:
* BFI_ENET_I2H_GET_ATTR_RSP
@@ -400,7 +398,7 @@ struct bfi_enet_attr_rsp {
u32 max_cfg;
u32 max_ucmac;
u32 rit_size;
-};
+} __packed;
/* Tx Configuration
*
@@ -421,7 +419,7 @@ struct bfi_enet_tx_cfg {
u8 apply_vlan_filter;
u8 add_to_vswitch;
u8 rsvd1[1];
-};
+} __packed;
struct bfi_enet_tx_cfg_req {
struct bfi_msgq_mhdr mh;
@@ -431,7 +429,7 @@ struct bfi_enet_tx_cfg_req {
struct {
struct bfi_enet_txq q;
struct bfi_enet_ib ib;
- } q_cfg[BFI_ENET_TXQ_PRIO_MAX];
+ } __packed q_cfg[BFI_ENET_TXQ_PRIO_MAX];
struct bfi_enet_ib_cfg ib_cfg;
@@ -448,7 +446,7 @@ struct bfi_enet_tx_cfg_rsp {
u32 i_dbell; /* PCI base address offset */
u8 hw_qid; /* For debugging */
u8 rsvd[3];
- } q_handles[BFI_ENET_TXQ_PRIO_MAX];
+ } __packed q_handles[BFI_ENET_TXQ_PRIO_MAX];
};
/* Rx Configuration
@@ -481,13 +479,13 @@ struct bfi_enet_rx_cfg {
u8 force_offset;
u8 type;
u8 rsvd1;
- } hds;
+ } __packed hds;
u8 multi_buffer;
u8 strip_vlan;
u8 drop_untagged;
u8 rsvd2;
-};
+} __packed;
/*
* Multicast frames are received on the ql of q-set index zero.
@@ -504,12 +502,12 @@ struct bfi_enet_rx_cfg_req {
struct bfi_enet_rxq qs; /* small/header buffers */
struct bfi_enet_cq cq;
struct bfi_enet_ib ib;
- } q_cfg[BFI_ENET_RX_QSET_MAX];
+ } __packed q_cfg[BFI_ENET_RX_QSET_MAX];
struct bfi_enet_ib_cfg ib_cfg;
struct bfi_enet_rx_cfg rx_cfg;
-};
+} __packed;
struct bfi_enet_rx_cfg_rsp {
struct bfi_msgq_mhdr mh;
@@ -524,8 +522,8 @@ struct bfi_enet_rx_cfg_rsp {
u8 hw_sqid; /* For debugging */
u8 hw_cqid; /* For debugging */
u8 rsvd;
- } q_handles[BFI_ENET_RX_QSET_MAX];
-};
+ } __packed q_handles[BFI_ENET_RX_QSET_MAX];
+} __packed;
/* RIT
*
@@ -537,7 +535,7 @@ struct bfi_enet_rit_req {
u16 size; /* number of table-entries used */
u8 rsvd[2];
u8 table[BFI_ENET_RSS_RIT_MAX];
-};
+} __packed;
/* RSS
*
@@ -556,12 +554,12 @@ struct bfi_enet_rss_cfg {
u8 mask;
u8 rsvd[2];
u32 key[BFI_ENET_RSS_KEY_LEN];
-};
+} __packed;
struct bfi_enet_rss_cfg_req {
struct bfi_msgq_mhdr mh;
struct bfi_enet_rss_cfg cfg;
-};
+} __packed;
/* MAC Unicast
*
@@ -573,16 +571,16 @@ struct bfi_enet_rss_cfg_req {
*/
struct bfi_enet_ucast_req {
struct bfi_msgq_mhdr mh;
- mac_t mac_addr;
+ u8 mac_addr[ETH_ALEN];
u8 rsvd[2];
-};
+} __packed;
/* MAC Unicast + VLAN */
struct bfi_enet_mac_n_vlan_req {
struct bfi_msgq_mhdr mh;
u16 vlan_id;
- mac_t mac_addr;
-};
+ u8 mac_addr[ETH_ALEN];
+} __packed;
/* MAC Multicast
*
@@ -591,9 +589,9 @@ struct bfi_enet_mac_n_vlan_req {
*/
struct bfi_enet_mcast_add_req {
struct bfi_msgq_mhdr mh;
- mac_t mac_addr;
+ u8 mac_addr[ETH_ALEN];
u8 rsvd[2];
-};
+} __packed;
/* bfi_enet_mac_mfilter_add_rsp is used by:
* BFI_ENET_I2H_MAC_MCAST_ADD_RSP
@@ -605,7 +603,7 @@ struct bfi_enet_mcast_add_rsp {
u16 cmd_offset;
u16 handle;
u8 rsvd1[2];
-};
+} __packed;
/* bfi_enet_mac_mfilter_del_req is used by:
* BFI_ENET_H2I_MAC_MCAST_DEL_REQ
@@ -614,7 +612,7 @@ struct bfi_enet_mcast_del_req {
struct bfi_msgq_mhdr mh;
u16 handle;
u8 rsvd[2];
-};
+} __packed;
/* VLAN
*
@@ -626,7 +624,7 @@ struct bfi_enet_rx_vlan_req {
u8 block_idx;
u8 rsvd[3];
u32 bit_mask[BFI_ENET_VLAN_WORDS_MAX];
-};
+} __packed;
/* PAUSE
*
@@ -638,7 +636,7 @@ struct bfi_enet_set_pause_req {
u8 rsvd[2];
u8 tx_pause; /* 1 = enable; 0 = disable */
u8 rx_pause; /* 1 = enable; 0 = disable */
-};
+} __packed;
/* DIAGNOSTICS
*
@@ -650,7 +648,7 @@ struct bfi_enet_diag_lb_req {
u8 rsvd[2];
u8 mode; /* cable or Serdes */
u8 enable; /* 1 = enable; 0 = disable */
-};
+} __packed;
/* enum for Loopback opmodes */
enum {
@@ -671,14 +669,14 @@ struct bfi_enet_stats_req {
u32 rx_enet_mask;
u32 tx_enet_mask;
union bfi_addr_u host_buffer;
-};
+} __packed;
/* defines for "stats_mask" above. */
-#define BFI_ENET_STATS_MAC (1 << 0) /* !< MAC Statistics */
-#define BFI_ENET_STATS_BPC (1 << 1) /* !< Pause Stats from BPC */
-#define BFI_ENET_STATS_RAD (1 << 2) /* !< Rx Admission Statistics */
-#define BFI_ENET_STATS_RX_FC (1 << 3) /* !< Rx FC Stats from RxA */
-#define BFI_ENET_STATS_TX_FC (1 << 4) /* !< Tx FC Stats from TxA */
+#define BFI_ENET_STATS_MAC BIT(0) /* !< MAC Statistics */
+#define BFI_ENET_STATS_BPC BIT(1) /* !< Pause Stats from BPC */
+#define BFI_ENET_STATS_RAD BIT(2) /* !< Rx Admission Statistics */
+#define BFI_ENET_STATS_RX_FC BIT(3) /* !< Rx FC Stats from RxA */
+#define BFI_ENET_STATS_TX_FC BIT(4) /* !< Tx FC Stats from TxA */
#define BFI_ENET_STATS_ALL 0x1f
@@ -699,7 +697,7 @@ struct bfi_enet_stats_txf {
u64 errors;
u64 filter_vlan; /* frames filtered due to VLAN */
u64 filter_mac_sa; /* frames filtered due to SA check */
-};
+} __packed;
/* RxF Frame Statistics */
struct bfi_enet_stats_rxf {
@@ -715,7 +713,7 @@ struct bfi_enet_stats_rxf {
u64 bcast;
u64 bcast_vlan;
u64 frame_drops;
-};
+} __packed;
/* FC Tx Frame Statistics */
struct bfi_enet_stats_fc_tx {
@@ -734,7 +732,7 @@ struct bfi_enet_stats_fc_tx {
u64 txf_parity_errors;
u64 txf_timeout;
u64 txf_fid_parity_errors;
-};
+} __packed;
/* FC Rx Frame Statistics */
struct bfi_enet_stats_fc_rx {
@@ -749,7 +747,7 @@ struct bfi_enet_stats_fc_rx {
u64 rxf_bcast_octets;
u64 rxf_bcast;
u64 rxf_bcast_vlan;
-};
+} __packed;
/* RAD Frame Statistics */
struct bfi_enet_stats_rad {
@@ -770,7 +768,7 @@ struct bfi_enet_stats_rad {
u64 rx_bcast_vlan;
u64 rx_drops;
-};
+} __packed;
/* BPC Tx Registers */
struct bfi_enet_stats_bpc {
@@ -785,7 +783,7 @@ struct bfi_enet_stats_bpc {
u64 rx_zero_pause[8]; /*!< Pause cancellation */
/*!<Pause initiation rather than retention */
u64 rx_first_pause[8];
-};
+} __packed;
/* MAC Rx Statistics */
struct bfi_enet_stats_mac {
@@ -838,7 +836,7 @@ struct bfi_enet_stats_mac {
u64 tx_oversize;
u64 tx_undersize;
u64 tx_fragments;
-};
+} __packed;
/* Complete statistics, DMAed from fw to host followed by
* BFI_ENET_I2H_STATS_GET_RSP
@@ -852,8 +850,6 @@ struct bfi_enet_stats {
struct bfi_enet_stats_fc_tx fc_tx_stats;
struct bfi_enet_stats_rxf rxf_stats[BFI_ENET_CFG_MAX];
struct bfi_enet_stats_txf txf_stats[BFI_ENET_CFG_MAX];
-};
-
-#pragma pack()
+} __packed;
#endif /* __BFI_ENET_H__ */
diff --git a/drivers/net/ethernet/brocade/bna/bna.h b/drivers/net/ethernet/brocade/bna/bna.h
index 8ba72b1f36d9..006dcad9a260 100644
--- a/drivers/net/ethernet/brocade/bna/bna.h
+++ b/drivers/net/ethernet/brocade/bna/bna.h
@@ -28,36 +28,8 @@ extern const u32 bna_napi_dim_vector[][BNA_BIAS_T_MAX];
/* Macros and constants */
-#define BNA_IOC_TIMER_FREQ 200
-
-/* Log string size */
-#define BNA_MESSAGE_SIZE 256
-
#define bna_is_small_rxq(_id) ((_id) & 0x1)
-#define BNA_MAC_IS_EQUAL(_mac1, _mac2) \
- (!memcmp((_mac1), (_mac2), sizeof(mac_t)))
-
-#define BNA_POWER_OF_2(x) (((x) & ((x) - 1)) == 0)
-
-#define BNA_TO_POWER_OF_2(x) \
-do { \
- int _shift = 0; \
- while ((x) && (x) != 1) { \
- (x) >>= 1; \
- _shift++; \
- } \
- (x) <<= _shift; \
-} while (0)
-
-#define BNA_TO_POWER_OF_2_HIGH(x) \
-do { \
- int n = 1; \
- while (n < (x)) \
- n <<= 1; \
- (x) = n; \
-} while (0)
-
/*
* input : _addr-> os dma addr in host endian format,
* output : _bna_dma_addr-> pointer to hw dma addr
@@ -80,62 +52,8 @@ do { \
| ((ntohl((_bna_dma_addr)->lsb) & 0xffffffff)); \
} while (0)
-#define containing_rec(addr, type, field) \
- ((type *)((unsigned char *)(addr) - \
- (unsigned char *)(&((type *)0)->field)))
-
#define BNA_TXQ_WI_NEEDED(_vectors) (((_vectors) + 3) >> 2)
-/* TxQ element is 64 bytes */
-#define BNA_TXQ_PAGE_INDEX_MAX (PAGE_SIZE >> 6)
-#define BNA_TXQ_PAGE_INDEX_MAX_SHIFT (PAGE_SHIFT - 6)
-
-#define BNA_TXQ_QPGE_PTR_GET(_qe_idx, _qpt_ptr, _qe_ptr, _qe_ptr_range) \
-{ \
- unsigned int page_index; /* index within a page */ \
- void *page_addr; \
- page_index = (_qe_idx) & (BNA_TXQ_PAGE_INDEX_MAX - 1); \
- (_qe_ptr_range) = (BNA_TXQ_PAGE_INDEX_MAX - page_index); \
- page_addr = (_qpt_ptr)[((_qe_idx) >> BNA_TXQ_PAGE_INDEX_MAX_SHIFT)];\
- (_qe_ptr) = &((struct bna_txq_entry *)(page_addr))[page_index]; \
-}
-
-/* RxQ element is 8 bytes */
-#define BNA_RXQ_PAGE_INDEX_MAX (PAGE_SIZE >> 3)
-#define BNA_RXQ_PAGE_INDEX_MAX_SHIFT (PAGE_SHIFT - 3)
-
-#define BNA_RXQ_QPGE_PTR_GET(_qe_idx, _qpt_ptr, _qe_ptr, _qe_ptr_range) \
-{ \
- unsigned int page_index; /* index within a page */ \
- void *page_addr; \
- page_index = (_qe_idx) & (BNA_RXQ_PAGE_INDEX_MAX - 1); \
- (_qe_ptr_range) = (BNA_RXQ_PAGE_INDEX_MAX - page_index); \
- page_addr = (_qpt_ptr)[((_qe_idx) >> \
- BNA_RXQ_PAGE_INDEX_MAX_SHIFT)]; \
- (_qe_ptr) = &((struct bna_rxq_entry *)(page_addr))[page_index]; \
-}
-
-/* CQ element is 16 bytes */
-#define BNA_CQ_PAGE_INDEX_MAX (PAGE_SIZE >> 4)
-#define BNA_CQ_PAGE_INDEX_MAX_SHIFT (PAGE_SHIFT - 4)
-
-#define BNA_CQ_QPGE_PTR_GET(_qe_idx, _qpt_ptr, _qe_ptr, _qe_ptr_range) \
-{ \
- unsigned int page_index; /* index within a page */ \
- void *page_addr; \
- \
- page_index = (_qe_idx) & (BNA_CQ_PAGE_INDEX_MAX - 1); \
- (_qe_ptr_range) = (BNA_CQ_PAGE_INDEX_MAX - page_index); \
- page_addr = (_qpt_ptr)[((_qe_idx) >> \
- BNA_CQ_PAGE_INDEX_MAX_SHIFT)]; \
- (_qe_ptr) = &((struct bna_cq_entry *)(page_addr))[page_index];\
-}
-
-#define BNA_QE_INDX_2_PTR(_cast, _qe_idx, _q_base) \
- (&((_cast *)(_q_base))[(_qe_idx)])
-
-#define BNA_QE_INDX_RANGE(_qe_idx, _q_depth) ((_q_depth) - (_qe_idx))
-
#define BNA_QE_INDX_ADD(_qe_idx, _qe_num, _q_depth) \
((_qe_idx) = ((_qe_idx) + (_qe_num)) & ((_q_depth) - 1))
@@ -147,31 +65,10 @@ do { \
#define BNA_QE_FREE_CNT(_q_ptr, _q_depth) \
(((_q_ptr)->consumer_index - (_q_ptr)->producer_index - 1) & \
((_q_depth) - 1))
-
#define BNA_QE_IN_USE_CNT(_q_ptr, _q_depth) \
((((_q_ptr)->producer_index - (_q_ptr)->consumer_index)) & \
(_q_depth - 1))
-#define BNA_Q_GET_CI(_q_ptr) ((_q_ptr)->q.consumer_index)
-
-#define BNA_Q_GET_PI(_q_ptr) ((_q_ptr)->q.producer_index)
-
-#define BNA_Q_PI_ADD(_q_ptr, _num) \
- (_q_ptr)->q.producer_index = \
- (((_q_ptr)->q.producer_index + (_num)) & \
- ((_q_ptr)->q.q_depth - 1))
-
-#define BNA_Q_CI_ADD(_q_ptr, _num) \
- (_q_ptr)->q.consumer_index = \
- (((_q_ptr)->q.consumer_index + (_num)) \
- & ((_q_ptr)->q.q_depth - 1))
-
-#define BNA_Q_FREE_COUNT(_q_ptr) \
- (BNA_QE_FREE_CNT(&((_q_ptr)->q), (_q_ptr)->q.q_depth))
-
-#define BNA_Q_IN_USE_COUNT(_q_ptr) \
- (BNA_QE_IN_USE_CNT(&(_q_ptr)->q, (_q_ptr)->q.q_depth))
-
#define BNA_LARGE_PKT_SIZE 1000
#define BNA_UPDATE_PKT_CNT(_pkt, _len) \
@@ -222,21 +119,6 @@ do { \
} \
} while (0)
-#define call_rxf_pause_cbfn(rxf) \
-do { \
- if ((rxf)->oper_state_cbfn) { \
- void (*cbfn)(struct bnad *, struct bna_rx *); \
- struct bnad *cbarg; \
- cbfn = (rxf)->oper_state_cbfn; \
- cbarg = (rxf)->oper_state_cbarg; \
- (rxf)->oper_state_cbfn = NULL; \
- (rxf)->oper_state_cbarg = NULL; \
- cbfn(cbarg, rxf->rx); \
- } \
-} while (0)
-
-#define call_rxf_resume_cbfn(rxf) call_rxf_pause_cbfn(rxf)
-
#define is_xxx_enable(mode, bitmask, xxx) ((bitmask & xxx) && (mode & xxx))
#define is_xxx_disable(mode, bitmask, xxx) ((bitmask & xxx) && !(mode & xxx))
@@ -326,28 +208,24 @@ do { \
#define bna_rx_rid_mask(_bna) ((_bna)->rx_mod.rid_mask)
#define bna_tx_from_rid(_bna, _rid, _tx) \
-do { \
- struct bna_tx_mod *__tx_mod = &(_bna)->tx_mod; \
- struct bna_tx *__tx; \
- struct list_head *qe; \
- _tx = NULL; \
- list_for_each(qe, &__tx_mod->tx_active_q) { \
- __tx = (struct bna_tx *)qe; \
- if (__tx->rid == (_rid)) { \
- (_tx) = __tx; \
- break; \
- } \
- } \
+do { \
+ struct bna_tx_mod *__tx_mod = &(_bna)->tx_mod; \
+ struct bna_tx *__tx; \
+ _tx = NULL; \
+ list_for_each_entry(__tx, &__tx_mod->tx_active_q, qe) { \
+ if (__tx->rid == (_rid)) { \
+ (_tx) = __tx; \
+ break; \
+ } \
+ } \
} while (0)
#define bna_rx_from_rid(_bna, _rid, _rx) \
do { \
struct bna_rx_mod *__rx_mod = &(_bna)->rx_mod; \
struct bna_rx *__rx; \
- struct list_head *qe; \
_rx = NULL; \
- list_for_each(qe, &__rx_mod->rx_active_q) { \
- __rx = (struct bna_rx *)qe; \
+ list_for_each_entry(__rx, &__rx_mod->rx_active_q, qe) { \
if (__rx->rid == (_rid)) { \
(_rx) = __rx; \
break; \
@@ -365,17 +243,14 @@ do { \
/* Inline functions */
-static inline struct bna_mac *bna_mac_find(struct list_head *q, u8 *addr)
+static inline struct bna_mac *bna_mac_find(struct list_head *q, const u8 *addr)
{
- struct bna_mac *mac = NULL;
- struct list_head *qe;
- list_for_each(qe, q) {
- if (BNA_MAC_IS_EQUAL(((struct bna_mac *)qe)->addr, addr)) {
- mac = (struct bna_mac *)qe;
- break;
- }
- }
- return mac;
+ struct bna_mac *mac;
+
+ list_for_each_entry(mac, q, qe)
+ if (ether_addr_equal(mac->addr, addr))
+ return mac;
+ return NULL;
}
#define bna_attr(_bna) (&(_bna)->ioceth.attr)
@@ -401,7 +276,6 @@ void bna_hw_stats_get(struct bna *bna);
/* APIs for RxF */
struct bna_mac *bna_cam_mod_mac_get(struct list_head *head);
-void bna_cam_mod_mac_put(struct list_head *tail, struct bna_mac *mac);
struct bna_mcam_handle *bna_mcam_mod_handle_get(struct bna_mcam_mod *mod);
void bna_mcam_mod_handle_put(struct bna_mcam_mod *mcam_mod,
struct bna_mcam_handle *handle);
@@ -488,31 +362,19 @@ void bna_rx_cleanup_complete(struct bna_rx *rx);
void bna_rx_coalescing_timeo_set(struct bna_rx *rx, int coalescing_timeo);
void bna_rx_dim_reconfig(struct bna *bna, const u32 vector[][BNA_BIAS_T_MAX]);
void bna_rx_dim_update(struct bna_ccb *ccb);
-enum bna_cb_status
-bna_rx_ucast_set(struct bna_rx *rx, u8 *ucmac,
- void (*cbfn)(struct bnad *, struct bna_rx *));
-enum bna_cb_status
-bna_rx_ucast_add(struct bna_rx *rx, u8* ucmac,
- void (*cbfn)(struct bnad *, struct bna_rx *));
-enum bna_cb_status
-bna_rx_ucast_del(struct bna_rx *rx, u8 *ucmac,
- void (*cbfn)(struct bnad *, struct bna_rx *));
-enum bna_cb_status
-bna_rx_ucast_listset(struct bna_rx *rx, int count, u8 *uclist,
- void (*cbfn)(struct bnad *, struct bna_rx *));
-enum bna_cb_status
-bna_rx_mcast_add(struct bna_rx *rx, u8 *mcmac,
- void (*cbfn)(struct bnad *, struct bna_rx *));
-enum bna_cb_status
-bna_rx_mcast_listset(struct bna_rx *rx, int count, u8 *mcmac,
- void (*cbfn)(struct bnad *, struct bna_rx *));
+enum bna_cb_status bna_rx_ucast_set(struct bna_rx *rx, const u8 *ucmac);
+enum bna_cb_status bna_rx_ucast_listset(struct bna_rx *rx, int count,
+ const u8 *uclist);
+enum bna_cb_status bna_rx_mcast_add(struct bna_rx *rx, const u8 *mcmac,
+ void (*cbfn)(struct bnad *,
+ struct bna_rx *));
+enum bna_cb_status bna_rx_mcast_listset(struct bna_rx *rx, int count,
+ const u8 *mcmac);
void
-bna_rx_mcast_delall(struct bna_rx *rx,
- void (*cbfn)(struct bnad *, struct bna_rx *));
+bna_rx_mcast_delall(struct bna_rx *rx);
enum bna_cb_status
bna_rx_mode_set(struct bna_rx *rx, enum bna_rxmode rxmode,
- enum bna_rxmode bitmask,
- void (*cbfn)(struct bnad *, struct bna_rx *));
+ enum bna_rxmode bitmask);
void bna_rx_vlan_add(struct bna_rx *rx, int vlan_id);
void bna_rx_vlan_del(struct bna_rx *rx, int vlan_id);
void bna_rx_vlanfilter_enable(struct bna_rx *rx);
@@ -532,11 +394,10 @@ void bna_enet_enable(struct bna_enet *enet);
void bna_enet_disable(struct bna_enet *enet, enum bna_cleanup_type type,
void (*cbfn)(void *));
void bna_enet_pause_config(struct bna_enet *enet,
- struct bna_pause_config *pause_config,
- void (*cbfn)(struct bnad *));
+ struct bna_pause_config *pause_config);
void bna_enet_mtu_set(struct bna_enet *enet, int mtu,
void (*cbfn)(struct bnad *));
-void bna_enet_perm_mac_get(struct bna_enet *enet, mac_t *mac);
+void bna_enet_perm_mac_get(struct bna_enet *enet, u8 *mac);
/* IOCETH */
diff --git a/drivers/net/ethernet/brocade/bna/bna_enet.c b/drivers/net/ethernet/brocade/bna/bna_enet.c
index deb8da6ab9cc..4e5c3874a50f 100644
--- a/drivers/net/ethernet/brocade/bna/bna_enet.c
+++ b/drivers/net/ethernet/brocade/bna/bna_enet.c
@@ -207,7 +207,7 @@ bna_bfi_stats_get_rsp(struct bna *bna, struct bfi_msgq_mhdr *msghdr)
for (i = 0; i < BFI_ENET_CFG_MAX; i++) {
stats_dst = (u64 *)&(bna->stats.hw_stats.rxf_stats[i]);
memset(stats_dst, 0, sizeof(struct bfi_enet_stats_rxf));
- if (rx_enet_mask & ((u32)(1 << i))) {
+ if (rx_enet_mask & BIT(i)) {
int k;
count = sizeof(struct bfi_enet_stats_rxf) /
sizeof(u64);
@@ -222,7 +222,7 @@ bna_bfi_stats_get_rsp(struct bna *bna, struct bfi_msgq_mhdr *msghdr)
for (i = 0; i < BFI_ENET_CFG_MAX; i++) {
stats_dst = (u64 *)&(bna->stats.hw_stats.txf_stats[i]);
memset(stats_dst, 0, sizeof(struct bfi_enet_stats_txf));
- if (tx_enet_mask & ((u32)(1 << i))) {
+ if (tx_enet_mask & BIT(i)) {
int k;
count = sizeof(struct bfi_enet_stats_txf) /
sizeof(u64);
@@ -884,16 +884,6 @@ do { \
} \
} while (0)
-#define call_enet_pause_cbfn(enet) \
-do { \
- if ((enet)->pause_cbfn) { \
- void (*cbfn)(struct bnad *); \
- cbfn = (enet)->pause_cbfn; \
- (enet)->pause_cbfn = NULL; \
- cbfn((enet)->bna->bnad); \
- } \
-} while (0)
-
#define call_enet_mtu_cbfn(enet) \
do { \
if ((enet)->mtu_cbfn) { \
@@ -925,7 +915,6 @@ bfa_fsm_state_decl(bna_enet, chld_stop_wait, struct bna_enet,
static void
bna_enet_sm_stopped_entry(struct bna_enet *enet)
{
- call_enet_pause_cbfn(enet);
call_enet_mtu_cbfn(enet);
call_enet_stop_cbfn(enet);
}
@@ -947,7 +936,6 @@ bna_enet_sm_stopped(struct bna_enet *enet, enum bna_enet_event event)
break;
case ENET_E_PAUSE_CFG:
- call_enet_pause_cbfn(enet);
break;
case ENET_E_MTU_CFG:
@@ -1039,7 +1027,6 @@ bna_enet_sm_started_entry(struct bna_enet *enet)
* NOTE: Do not call bna_enet_chld_start() here, since it will be
* inadvertently called during cfg_wait->started transition as well
*/
- call_enet_pause_cbfn(enet);
call_enet_mtu_cbfn(enet);
}
@@ -1211,8 +1198,6 @@ bna_enet_init(struct bna_enet *enet, struct bna *bna)
enet->stop_cbfn = NULL;
enet->stop_cbarg = NULL;
- enet->pause_cbfn = NULL;
-
enet->mtu_cbfn = NULL;
bfa_fsm_set_state(enet, bna_enet_sm_stopped);
@@ -1308,13 +1293,10 @@ bna_enet_disable(struct bna_enet *enet, enum bna_cleanup_type type,
void
bna_enet_pause_config(struct bna_enet *enet,
- struct bna_pause_config *pause_config,
- void (*cbfn)(struct bnad *))
+ struct bna_pause_config *pause_config)
{
enet->pause_config = *pause_config;
- enet->pause_cbfn = cbfn;
-
bfa_fsm_send_event(enet, ENET_E_PAUSE_CFG);
}
@@ -1330,9 +1312,9 @@ bna_enet_mtu_set(struct bna_enet *enet, int mtu,
}
void
-bna_enet_perm_mac_get(struct bna_enet *enet, mac_t *mac)
+bna_enet_perm_mac_get(struct bna_enet *enet, u8 *mac)
{
- *mac = bfa_nw_ioc_get_mac(&enet->bna->ioceth.ioc);
+ bfa_nw_ioc_get_mac(&enet->bna->ioceth.ioc, mac);
}
/* IOCETH */
@@ -1810,17 +1792,13 @@ bna_ucam_mod_init(struct bna_ucam_mod *ucam_mod, struct bna *bna,
res_info[BNA_MOD_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.mdl[0].kva;
INIT_LIST_HEAD(&ucam_mod->free_q);
- for (i = 0; i < bna->ioceth.attr.num_ucmac; i++) {
- bfa_q_qe_init(&ucam_mod->ucmac[i].qe);
+ for (i = 0; i < bna->ioceth.attr.num_ucmac; i++)
list_add_tail(&ucam_mod->ucmac[i].qe, &ucam_mod->free_q);
- }
/* A separate queue to allow synchronous setting of a list of MACs */
INIT_LIST_HEAD(&ucam_mod->del_q);
- for (i = i; i < (bna->ioceth.attr.num_ucmac * 2); i++) {
- bfa_q_qe_init(&ucam_mod->ucmac[i].qe);
+ for (i = i; i < (bna->ioceth.attr.num_ucmac * 2); i++)
list_add_tail(&ucam_mod->ucmac[i].qe, &ucam_mod->del_q);
- }
ucam_mod->bna = bna;
}
@@ -1828,17 +1806,6 @@ bna_ucam_mod_init(struct bna_ucam_mod *ucam_mod, struct bna *bna,
static void
bna_ucam_mod_uninit(struct bna_ucam_mod *ucam_mod)
{
- struct list_head *qe;
- int i;
-
- i = 0;
- list_for_each(qe, &ucam_mod->free_q)
- i++;
-
- i = 0;
- list_for_each(qe, &ucam_mod->del_q)
- i++;
-
ucam_mod->bna = NULL;
}
@@ -1852,27 +1819,21 @@ bna_mcam_mod_init(struct bna_mcam_mod *mcam_mod, struct bna *bna,
res_info[BNA_MOD_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.mdl[0].kva;
INIT_LIST_HEAD(&mcam_mod->free_q);
- for (i = 0; i < bna->ioceth.attr.num_mcmac; i++) {
- bfa_q_qe_init(&mcam_mod->mcmac[i].qe);
+ for (i = 0; i < bna->ioceth.attr.num_mcmac; i++)
list_add_tail(&mcam_mod->mcmac[i].qe, &mcam_mod->free_q);
- }
mcam_mod->mchandle = (struct bna_mcam_handle *)
res_info[BNA_MOD_RES_MEM_T_MCHANDLE_ARRAY].res_u.mem_info.mdl[0].kva;
INIT_LIST_HEAD(&mcam_mod->free_handle_q);
- for (i = 0; i < bna->ioceth.attr.num_mcmac; i++) {
- bfa_q_qe_init(&mcam_mod->mchandle[i].qe);
+ for (i = 0; i < bna->ioceth.attr.num_mcmac; i++)
list_add_tail(&mcam_mod->mchandle[i].qe,
- &mcam_mod->free_handle_q);
- }
+ &mcam_mod->free_handle_q);
/* A separate queue to allow synchronous setting of a list of MACs */
INIT_LIST_HEAD(&mcam_mod->del_q);
- for (i = i; i < (bna->ioceth.attr.num_mcmac * 2); i++) {
- bfa_q_qe_init(&mcam_mod->mcmac[i].qe);
+ for (i = i; i < (bna->ioceth.attr.num_mcmac * 2); i++)
list_add_tail(&mcam_mod->mcmac[i].qe, &mcam_mod->del_q);
- }
mcam_mod->bna = bna;
}
@@ -1880,18 +1841,6 @@ bna_mcam_mod_init(struct bna_mcam_mod *mcam_mod, struct bna *bna,
static void
bna_mcam_mod_uninit(struct bna_mcam_mod *mcam_mod)
{
- struct list_head *qe;
- int i;
-
- i = 0;
- list_for_each(qe, &mcam_mod->free_q) i++;
-
- i = 0;
- list_for_each(qe, &mcam_mod->del_q) i++;
-
- i = 0;
- list_for_each(qe, &mcam_mod->free_handle_q) i++;
-
mcam_mod->bna = NULL;
}
@@ -2108,32 +2057,26 @@ bna_num_rxp_set(struct bna *bna, int num_rxp)
struct bna_mac *
bna_cam_mod_mac_get(struct list_head *head)
{
- struct list_head *qe;
-
- if (list_empty(head))
- return NULL;
+ struct bna_mac *mac;
- bfa_q_deq(head, &qe);
- return (struct bna_mac *)qe;
-}
+ mac = list_first_entry_or_null(head, struct bna_mac, qe);
+ if (mac)
+ list_del(&mac->qe);
-void
-bna_cam_mod_mac_put(struct list_head *tail, struct bna_mac *mac)
-{
- list_add_tail(&mac->qe, tail);
+ return mac;
}
struct bna_mcam_handle *
bna_mcam_mod_handle_get(struct bna_mcam_mod *mcam_mod)
{
- struct list_head *qe;
-
- if (list_empty(&mcam_mod->free_handle_q))
- return NULL;
+ struct bna_mcam_handle *handle;
- bfa_q_deq(&mcam_mod->free_handle_q, &qe);
+ handle = list_first_entry_or_null(&mcam_mod->free_handle_q,
+ struct bna_mcam_handle, qe);
+ if (handle)
+ list_del(&handle->qe);
- return (struct bna_mcam_handle *)qe;
+ return handle;
}
void
diff --git a/drivers/net/ethernet/brocade/bna/bna_hw_defs.h b/drivers/net/ethernet/brocade/bna/bna_hw_defs.h
index 174af0e9d056..52b45c9935aa 100644
--- a/drivers/net/ethernet/brocade/bna/bna_hw_defs.h
+++ b/drivers/net/ethernet/brocade/bna/bna_hw_defs.h
@@ -213,7 +213,7 @@ do { \
* 15 bits (32K) should be large enough to accumulate, anyways, and the max.
* acked events to h/w can be (32K + max poll weight) (currently 64).
*/
-#define BNA_IB_MAX_ACK_EVENTS (1 << 15)
+#define BNA_IB_MAX_ACK_EVENTS BIT(15)
/* These macros build the data portion of the TxQ/RxQ doorbell */
#define BNA_DOORBELL_Q_PRD_IDX(_pi) (0x80000000 | (_pi))
@@ -282,13 +282,13 @@ do { \
#define BNA_TXQ_WI_EXTENSION (0x104) /* Extension WI */
/* TxQ Entry Control Flags */
-#define BNA_TXQ_WI_CF_FCOE_CRC (1 << 8)
-#define BNA_TXQ_WI_CF_IPID_MODE (1 << 5)
-#define BNA_TXQ_WI_CF_INS_PRIO (1 << 4)
-#define BNA_TXQ_WI_CF_INS_VLAN (1 << 3)
-#define BNA_TXQ_WI_CF_UDP_CKSUM (1 << 2)
-#define BNA_TXQ_WI_CF_TCP_CKSUM (1 << 1)
-#define BNA_TXQ_WI_CF_IP_CKSUM (1 << 0)
+#define BNA_TXQ_WI_CF_FCOE_CRC BIT(8)
+#define BNA_TXQ_WI_CF_IPID_MODE BIT(5)
+#define BNA_TXQ_WI_CF_INS_PRIO BIT(4)
+#define BNA_TXQ_WI_CF_INS_VLAN BIT(3)
+#define BNA_TXQ_WI_CF_UDP_CKSUM BIT(2)
+#define BNA_TXQ_WI_CF_TCP_CKSUM BIT(1)
+#define BNA_TXQ_WI_CF_IP_CKSUM BIT(0)
#define BNA_TXQ_WI_L4_HDR_N_OFFSET(_hdr_size, _offset) \
(((_hdr_size) << 10) | ((_offset) & 0x3FF))
@@ -297,36 +297,36 @@ do { \
* Completion Q defines
*/
/* CQ Entry Flags */
-#define BNA_CQ_EF_MAC_ERROR (1 << 0)
-#define BNA_CQ_EF_FCS_ERROR (1 << 1)
-#define BNA_CQ_EF_TOO_LONG (1 << 2)
-#define BNA_CQ_EF_FC_CRC_OK (1 << 3)
-
-#define BNA_CQ_EF_RSVD1 (1 << 4)
-#define BNA_CQ_EF_L4_CKSUM_OK (1 << 5)
-#define BNA_CQ_EF_L3_CKSUM_OK (1 << 6)
-#define BNA_CQ_EF_HDS_HEADER (1 << 7)
-
-#define BNA_CQ_EF_UDP (1 << 8)
-#define BNA_CQ_EF_TCP (1 << 9)
-#define BNA_CQ_EF_IP_OPTIONS (1 << 10)
-#define BNA_CQ_EF_IPV6 (1 << 11)
-
-#define BNA_CQ_EF_IPV4 (1 << 12)
-#define BNA_CQ_EF_VLAN (1 << 13)
-#define BNA_CQ_EF_RSS (1 << 14)
-#define BNA_CQ_EF_RSVD2 (1 << 15)
-
-#define BNA_CQ_EF_MCAST_MATCH (1 << 16)
-#define BNA_CQ_EF_MCAST (1 << 17)
-#define BNA_CQ_EF_BCAST (1 << 18)
-#define BNA_CQ_EF_REMOTE (1 << 19)
-
-#define BNA_CQ_EF_LOCAL (1 << 20)
+#define BNA_CQ_EF_MAC_ERROR BIT(0)
+#define BNA_CQ_EF_FCS_ERROR BIT(1)
+#define BNA_CQ_EF_TOO_LONG BIT(2)
+#define BNA_CQ_EF_FC_CRC_OK BIT(3)
+
+#define BNA_CQ_EF_RSVD1 BIT(4)
+#define BNA_CQ_EF_L4_CKSUM_OK BIT(5)
+#define BNA_CQ_EF_L3_CKSUM_OK BIT(6)
+#define BNA_CQ_EF_HDS_HEADER BIT(7)
+
+#define BNA_CQ_EF_UDP BIT(8)
+#define BNA_CQ_EF_TCP BIT(9)
+#define BNA_CQ_EF_IP_OPTIONS BIT(10)
+#define BNA_CQ_EF_IPV6 BIT(11)
+
+#define BNA_CQ_EF_IPV4 BIT(12)
+#define BNA_CQ_EF_VLAN BIT(13)
+#define BNA_CQ_EF_RSS BIT(14)
+#define BNA_CQ_EF_RSVD2 BIT(15)
+
+#define BNA_CQ_EF_MCAST_MATCH BIT(16)
+#define BNA_CQ_EF_MCAST BIT(17)
+#define BNA_CQ_EF_BCAST BIT(18)
+#define BNA_CQ_EF_REMOTE BIT(19)
+
+#define BNA_CQ_EF_LOCAL BIT(20)
/* CAT2 ASIC does not use bit 21 as per the SPEC.
* Bit 31 is set in every end of frame completion
*/
-#define BNA_CQ_EF_EOP (1 << 31)
+#define BNA_CQ_EF_EOP BIT(31)
/* Data structures */
diff --git a/drivers/net/ethernet/brocade/bna/bna_tx_rx.c b/drivers/net/ethernet/brocade/bna/bna_tx_rx.c
index 8ab3a5f62706..5d0753cc7e73 100644
--- a/drivers/net/ethernet/brocade/bna/bna_tx_rx.c
+++ b/drivers/net/ethernet/brocade/bna/bna_tx_rx.c
@@ -46,7 +46,6 @@ do { \
static int bna_rxf_cfg_apply(struct bna_rxf *rxf);
static void bna_rxf_cfg_reset(struct bna_rxf *rxf);
-static int bna_rxf_fltr_clear(struct bna_rxf *rxf);
static int bna_rxf_ucast_cfg_apply(struct bna_rxf *rxf);
static int bna_rxf_promisc_cfg_apply(struct bna_rxf *rxf);
static int bna_rxf_allmulti_cfg_apply(struct bna_rxf *rxf);
@@ -60,14 +59,10 @@ static int bna_rxf_allmulti_cfg_reset(struct bna_rxf *rxf,
bfa_fsm_state_decl(bna_rxf, stopped, struct bna_rxf,
enum bna_rxf_event);
-bfa_fsm_state_decl(bna_rxf, paused, struct bna_rxf,
- enum bna_rxf_event);
bfa_fsm_state_decl(bna_rxf, cfg_wait, struct bna_rxf,
enum bna_rxf_event);
bfa_fsm_state_decl(bna_rxf, started, struct bna_rxf,
enum bna_rxf_event);
-bfa_fsm_state_decl(bna_rxf, fltr_clr_wait, struct bna_rxf,
- enum bna_rxf_event);
bfa_fsm_state_decl(bna_rxf, last_resp_wait, struct bna_rxf,
enum bna_rxf_event);
@@ -82,11 +77,7 @@ bna_rxf_sm_stopped(struct bna_rxf *rxf, enum bna_rxf_event event)
{
switch (event) {
case RXF_E_START:
- if (rxf->flags & BNA_RXF_F_PAUSED) {
- bfa_fsm_set_state(rxf, bna_rxf_sm_paused);
- call_rxf_start_cbfn(rxf);
- } else
- bfa_fsm_set_state(rxf, bna_rxf_sm_cfg_wait);
+ bfa_fsm_set_state(rxf, bna_rxf_sm_cfg_wait);
break;
case RXF_E_STOP:
@@ -101,45 +92,6 @@ bna_rxf_sm_stopped(struct bna_rxf *rxf, enum bna_rxf_event event)
call_rxf_cam_fltr_cbfn(rxf);
break;
- case RXF_E_PAUSE:
- rxf->flags |= BNA_RXF_F_PAUSED;
- call_rxf_pause_cbfn(rxf);
- break;
-
- case RXF_E_RESUME:
- rxf->flags &= ~BNA_RXF_F_PAUSED;
- call_rxf_resume_cbfn(rxf);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_rxf_sm_paused_entry(struct bna_rxf *rxf)
-{
- call_rxf_pause_cbfn(rxf);
-}
-
-static void
-bna_rxf_sm_paused(struct bna_rxf *rxf, enum bna_rxf_event event)
-{
- switch (event) {
- case RXF_E_STOP:
- case RXF_E_FAIL:
- bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
- break;
-
- case RXF_E_CONFIG:
- call_rxf_cam_fltr_cbfn(rxf);
- break;
-
- case RXF_E_RESUME:
- rxf->flags &= ~BNA_RXF_F_PAUSED;
- bfa_fsm_set_state(rxf, bna_rxf_sm_cfg_wait);
- break;
-
default:
bfa_sm_fault(event);
}
@@ -166,7 +118,6 @@ bna_rxf_sm_cfg_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
bna_rxf_cfg_reset(rxf);
call_rxf_start_cbfn(rxf);
call_rxf_cam_fltr_cbfn(rxf);
- call_rxf_resume_cbfn(rxf);
bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
break;
@@ -174,12 +125,6 @@ bna_rxf_sm_cfg_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
/* No-op */
break;
- case RXF_E_PAUSE:
- rxf->flags |= BNA_RXF_F_PAUSED;
- call_rxf_start_cbfn(rxf);
- bfa_fsm_set_state(rxf, bna_rxf_sm_fltr_clr_wait);
- break;
-
case RXF_E_FW_RESP:
if (!bna_rxf_cfg_apply(rxf)) {
/* No more pending config updates */
@@ -197,7 +142,6 @@ bna_rxf_sm_started_entry(struct bna_rxf *rxf)
{
call_rxf_start_cbfn(rxf);
call_rxf_cam_fltr_cbfn(rxf);
- call_rxf_resume_cbfn(rxf);
}
static void
@@ -214,41 +158,6 @@ bna_rxf_sm_started(struct bna_rxf *rxf, enum bna_rxf_event event)
bfa_fsm_set_state(rxf, bna_rxf_sm_cfg_wait);
break;
- case RXF_E_PAUSE:
- rxf->flags |= BNA_RXF_F_PAUSED;
- if (!bna_rxf_fltr_clear(rxf))
- bfa_fsm_set_state(rxf, bna_rxf_sm_paused);
- else
- bfa_fsm_set_state(rxf, bna_rxf_sm_fltr_clr_wait);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_rxf_sm_fltr_clr_wait_entry(struct bna_rxf *rxf)
-{
-}
-
-static void
-bna_rxf_sm_fltr_clr_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
-{
- switch (event) {
- case RXF_E_FAIL:
- bna_rxf_cfg_reset(rxf);
- call_rxf_pause_cbfn(rxf);
- bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
- break;
-
- case RXF_E_FW_RESP:
- if (!bna_rxf_fltr_clear(rxf)) {
- /* No more pending CAM entries to clear */
- bfa_fsm_set_state(rxf, bna_rxf_sm_paused);
- }
- break;
-
default:
bfa_sm_fault(event);
}
@@ -283,7 +192,7 @@ bna_bfi_ucast_req(struct bna_rxf *rxf, struct bna_mac *mac,
bfi_msgq_mhdr_set(req->mh, BFI_MC_ENET, req_type, 0, rxf->rx->rid);
req->mh.num_entries = htons(
bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_ucast_req)));
- memcpy(&req->mac_addr, &mac->addr, sizeof(mac_t));
+ ether_addr_copy(req->mac_addr, mac->addr);
bfa_msgq_cmd_set(&rxf->msgq_cmd, NULL, NULL,
sizeof(struct bfi_enet_ucast_req), &req->mh);
bfa_msgq_cmd_post(&rxf->rx->bna->msgq, &rxf->msgq_cmd);
@@ -299,7 +208,7 @@ bna_bfi_mcast_add_req(struct bna_rxf *rxf, struct bna_mac *mac)
0, rxf->rx->rid);
req->mh.num_entries = htons(
bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_mcast_add_req)));
- memcpy(&req->mac_addr, &mac->addr, sizeof(mac_t));
+ ether_addr_copy(req->mac_addr, mac->addr);
bfa_msgq_cmd_set(&rxf->msgq_cmd, NULL, NULL,
sizeof(struct bfi_enet_mcast_add_req), &req->mh);
bfa_msgq_cmd_post(&rxf->rx->bna->msgq, &rxf->msgq_cmd);
@@ -444,22 +353,17 @@ bna_bfi_rss_enable(struct bna_rxf *rxf)
/* This function gets the multicast MAC that has already been added to CAM */
static struct bna_mac *
-bna_rxf_mcmac_get(struct bna_rxf *rxf, u8 *mac_addr)
+bna_rxf_mcmac_get(struct bna_rxf *rxf, const u8 *mac_addr)
{
struct bna_mac *mac;
- struct list_head *qe;
- list_for_each(qe, &rxf->mcast_active_q) {
- mac = (struct bna_mac *)qe;
- if (BNA_MAC_IS_EQUAL(&mac->addr, mac_addr))
+ list_for_each_entry(mac, &rxf->mcast_active_q, qe)
+ if (ether_addr_equal(mac->addr, mac_addr))
return mac;
- }
- list_for_each(qe, &rxf->mcast_pending_del_q) {
- mac = (struct bna_mac *)qe;
- if (BNA_MAC_IS_EQUAL(&mac->addr, mac_addr))
+ list_for_each_entry(mac, &rxf->mcast_pending_del_q, qe)
+ if (ether_addr_equal(mac->addr, mac_addr))
return mac;
- }
return NULL;
}
@@ -468,13 +372,10 @@ static struct bna_mcam_handle *
bna_rxf_mchandle_get(struct bna_rxf *rxf, int handle)
{
struct bna_mcam_handle *mchandle;
- struct list_head *qe;
- list_for_each(qe, &rxf->mcast_handle_q) {
- mchandle = (struct bna_mcam_handle *)qe;
+ list_for_each_entry(mchandle, &rxf->mcast_handle_q, qe)
if (mchandle->handle == handle)
return mchandle;
- }
return NULL;
}
@@ -515,7 +416,6 @@ bna_rxf_mcast_del(struct bna_rxf *rxf, struct bna_mac *mac,
ret = 1;
}
list_del(&mchandle->qe);
- bfa_q_qe_init(&mchandle->qe);
bna_mcam_mod_handle_put(&rxf->rx->bna->mcam_mod, mchandle);
}
mac->handle = NULL;
@@ -527,26 +427,23 @@ static int
bna_rxf_mcast_cfg_apply(struct bna_rxf *rxf)
{
struct bna_mac *mac = NULL;
- struct list_head *qe;
int ret;
/* First delete multicast entries to maintain the count */
while (!list_empty(&rxf->mcast_pending_del_q)) {
- bfa_q_deq(&rxf->mcast_pending_del_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
+ mac = list_first_entry(&rxf->mcast_pending_del_q,
+ struct bna_mac, qe);
ret = bna_rxf_mcast_del(rxf, mac, BNA_HARD_CLEANUP);
- bna_cam_mod_mac_put(bna_mcam_mod_del_q(rxf->rx->bna), mac);
+ list_move_tail(&mac->qe, bna_mcam_mod_del_q(rxf->rx->bna));
if (ret)
return ret;
}
/* Add multicast entries */
if (!list_empty(&rxf->mcast_pending_add_q)) {
- bfa_q_deq(&rxf->mcast_pending_add_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
- list_add_tail(&mac->qe, &rxf->mcast_active_q);
+ mac = list_first_entry(&rxf->mcast_pending_add_q,
+ struct bna_mac, qe);
+ list_move_tail(&mac->qe, &rxf->mcast_active_q);
bna_bfi_mcast_add_req(rxf, mac);
return 1;
}
@@ -566,7 +463,7 @@ bna_rxf_vlan_cfg_apply(struct bna_rxf *rxf)
block_idx++;
vlan_pending_bitmask >>= 1;
}
- rxf->vlan_pending_bitmask &= ~(1 << block_idx);
+ rxf->vlan_pending_bitmask &= ~BIT(block_idx);
bna_bfi_rx_vlan_filter_set(rxf, block_idx);
return 1;
}
@@ -577,27 +474,24 @@ bna_rxf_vlan_cfg_apply(struct bna_rxf *rxf)
static int
bna_rxf_mcast_cfg_reset(struct bna_rxf *rxf, enum bna_cleanup_type cleanup)
{
- struct list_head *qe;
struct bna_mac *mac;
int ret;
/* Throw away delete pending mcast entries */
while (!list_empty(&rxf->mcast_pending_del_q)) {
- bfa_q_deq(&rxf->mcast_pending_del_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
+ mac = list_first_entry(&rxf->mcast_pending_del_q,
+ struct bna_mac, qe);
ret = bna_rxf_mcast_del(rxf, mac, cleanup);
- bna_cam_mod_mac_put(bna_mcam_mod_del_q(rxf->rx->bna), mac);
+ list_move_tail(&mac->qe, bna_mcam_mod_del_q(rxf->rx->bna));
if (ret)
return ret;
}
/* Move active mcast entries to pending_add_q */
while (!list_empty(&rxf->mcast_active_q)) {
- bfa_q_deq(&rxf->mcast_active_q, &qe);
- bfa_q_qe_init(qe);
- list_add_tail(qe, &rxf->mcast_pending_add_q);
- mac = (struct bna_mac *)qe;
+ mac = list_first_entry(&rxf->mcast_active_q,
+ struct bna_mac, qe);
+ list_move_tail(&mac->qe, &rxf->mcast_pending_add_q);
if (bna_rxf_mcast_del(rxf, mac, cleanup))
return 1;
}
@@ -658,25 +552,6 @@ bna_rxf_cfg_apply(struct bna_rxf *rxf)
return 0;
}
-/* Only software reset */
-static int
-bna_rxf_fltr_clear(struct bna_rxf *rxf)
-{
- if (bna_rxf_ucast_cfg_reset(rxf, BNA_HARD_CLEANUP))
- return 1;
-
- if (bna_rxf_mcast_cfg_reset(rxf, BNA_HARD_CLEANUP))
- return 1;
-
- if (bna_rxf_promisc_cfg_reset(rxf, BNA_HARD_CLEANUP))
- return 1;
-
- if (bna_rxf_allmulti_cfg_reset(rxf, BNA_HARD_CLEANUP))
- return 1;
-
- return 0;
-}
-
static void
bna_rxf_cfg_reset(struct bna_rxf *rxf)
{
@@ -693,16 +568,13 @@ bna_rit_init(struct bna_rxf *rxf, int rit_size)
{
struct bna_rx *rx = rxf->rx;
struct bna_rxp *rxp;
- struct list_head *qe;
int offset = 0;
rxf->rit_size = rit_size;
- list_for_each(qe, &rx->rxp_q) {
- rxp = (struct bna_rxp *)qe;
+ list_for_each_entry(rxp, &rx->rxp_q, qe) {
rxf->rit[offset] = rxp->cq.ccb->id;
offset++;
}
-
}
void
@@ -760,9 +632,6 @@ bna_rxf_init(struct bna_rxf *rxf,
INIT_LIST_HEAD(&rxf->mcast_active_q);
INIT_LIST_HEAD(&rxf->mcast_handle_q);
- if (q_config->paused)
- rxf->flags |= BNA_RXF_F_PAUSED;
-
rxf->rit = (u8 *)
res_info[BNA_RX_RES_MEM_T_RIT].res_u.mem_info.mdl[0].kva;
bna_rit_init(rxf, q_config->num_paths);
@@ -795,22 +664,21 @@ bna_rxf_uninit(struct bna_rxf *rxf)
rxf->ucast_active_set = 0;
while (!list_empty(&rxf->ucast_pending_add_q)) {
- bfa_q_deq(&rxf->ucast_pending_add_q, &mac);
- bfa_q_qe_init(&mac->qe);
- bna_cam_mod_mac_put(bna_ucam_mod_free_q(rxf->rx->bna), mac);
+ mac = list_first_entry(&rxf->ucast_pending_add_q,
+ struct bna_mac, qe);
+ list_move_tail(&mac->qe, bna_ucam_mod_free_q(rxf->rx->bna));
}
if (rxf->ucast_pending_mac) {
- bfa_q_qe_init(&rxf->ucast_pending_mac->qe);
- bna_cam_mod_mac_put(bna_ucam_mod_free_q(rxf->rx->bna),
- rxf->ucast_pending_mac);
+ list_add_tail(&rxf->ucast_pending_mac->qe,
+ bna_ucam_mod_free_q(rxf->rx->bna));
rxf->ucast_pending_mac = NULL;
}
while (!list_empty(&rxf->mcast_pending_add_q)) {
- bfa_q_deq(&rxf->mcast_pending_add_q, &mac);
- bfa_q_qe_init(&mac->qe);
- bna_cam_mod_mac_put(bna_mcam_mod_free_q(rxf->rx->bna), mac);
+ mac = list_first_entry(&rxf->mcast_pending_add_q,
+ struct bna_mac, qe);
+ list_move_tail(&mac->qe, bna_mcam_mod_free_q(rxf->rx->bna));
}
rxf->rxmode_pending = 0;
@@ -823,8 +691,6 @@ bna_rxf_uninit(struct bna_rxf *rxf)
rxf->rss_pending = 0;
rxf->vlan_strip_pending = false;
- rxf->flags = 0;
-
rxf->rx = NULL;
}
@@ -863,8 +729,7 @@ bna_rxf_fail(struct bna_rxf *rxf)
}
enum bna_cb_status
-bna_rx_ucast_set(struct bna_rx *rx, u8 *ucmac,
- void (*cbfn)(struct bnad *, struct bna_rx *))
+bna_rx_ucast_set(struct bna_rx *rx, const u8 *ucmac)
{
struct bna_rxf *rxf = &rx->rxf;
@@ -873,12 +738,11 @@ bna_rx_ucast_set(struct bna_rx *rx, u8 *ucmac,
bna_cam_mod_mac_get(bna_ucam_mod_free_q(rxf->rx->bna));
if (rxf->ucast_pending_mac == NULL)
return BNA_CB_UCAST_CAM_FULL;
- bfa_q_qe_init(&rxf->ucast_pending_mac->qe);
}
- memcpy(rxf->ucast_pending_mac->addr, ucmac, ETH_ALEN);
+ ether_addr_copy(rxf->ucast_pending_mac->addr, ucmac);
rxf->ucast_pending_set = 1;
- rxf->cam_fltr_cbfn = cbfn;
+ rxf->cam_fltr_cbfn = NULL;
rxf->cam_fltr_cbarg = rx->bna->bnad;
bfa_fsm_send_event(rxf, RXF_E_CONFIG);
@@ -887,7 +751,7 @@ bna_rx_ucast_set(struct bna_rx *rx, u8 *ucmac,
}
enum bna_cb_status
-bna_rx_mcast_add(struct bna_rx *rx, u8 *addr,
+bna_rx_mcast_add(struct bna_rx *rx, const u8 *addr,
void (*cbfn)(struct bnad *, struct bna_rx *))
{
struct bna_rxf *rxf = &rx->rxf;
@@ -904,8 +768,7 @@ bna_rx_mcast_add(struct bna_rx *rx, u8 *addr,
mac = bna_cam_mod_mac_get(bna_mcam_mod_free_q(rxf->rx->bna));
if (mac == NULL)
return BNA_CB_MCAST_LIST_FULL;
- bfa_q_qe_init(&mac->qe);
- memcpy(mac->addr, addr, ETH_ALEN);
+ ether_addr_copy(mac->addr, addr);
list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
rxf->cam_fltr_cbfn = cbfn;
@@ -917,35 +780,31 @@ bna_rx_mcast_add(struct bna_rx *rx, u8 *addr,
}
enum bna_cb_status
-bna_rx_ucast_listset(struct bna_rx *rx, int count, u8 *uclist,
- void (*cbfn)(struct bnad *, struct bna_rx *))
+bna_rx_ucast_listset(struct bna_rx *rx, int count, const u8 *uclist)
{
struct bna_ucam_mod *ucam_mod = &rx->bna->ucam_mod;
struct bna_rxf *rxf = &rx->rxf;
struct list_head list_head;
- struct list_head *qe;
- u8 *mcaddr;
+ const u8 *mcaddr;
struct bna_mac *mac, *del_mac;
int i;
/* Purge the pending_add_q */
while (!list_empty(&rxf->ucast_pending_add_q)) {
- bfa_q_deq(&rxf->ucast_pending_add_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
- bna_cam_mod_mac_put(&ucam_mod->free_q, mac);
+ mac = list_first_entry(&rxf->ucast_pending_add_q,
+ struct bna_mac, qe);
+ list_move_tail(&mac->qe, &ucam_mod->free_q);
}
/* Schedule active_q entries for deletion */
while (!list_empty(&rxf->ucast_active_q)) {
- bfa_q_deq(&rxf->ucast_active_q, &qe);
- mac = (struct bna_mac *)qe;
- bfa_q_qe_init(&mac->qe);
-
+ mac = list_first_entry(&rxf->ucast_active_q,
+ struct bna_mac, qe);
del_mac = bna_cam_mod_mac_get(&ucam_mod->del_q);
- memcpy(del_mac, mac, sizeof(*del_mac));
+ ether_addr_copy(del_mac->addr, mac->addr);
+ del_mac->handle = mac->handle;
list_add_tail(&del_mac->qe, &rxf->ucast_pending_del_q);
- bna_cam_mod_mac_put(&ucam_mod->free_q, mac);
+ list_move_tail(&mac->qe, &ucam_mod->free_q);
}
/* Allocate nodes */
@@ -954,69 +813,57 @@ bna_rx_ucast_listset(struct bna_rx *rx, int count, u8 *uclist,
mac = bna_cam_mod_mac_get(&ucam_mod->free_q);
if (mac == NULL)
goto err_return;
- bfa_q_qe_init(&mac->qe);
- memcpy(mac->addr, mcaddr, ETH_ALEN);
+ ether_addr_copy(mac->addr, mcaddr);
list_add_tail(&mac->qe, &list_head);
mcaddr += ETH_ALEN;
}
/* Add the new entries */
while (!list_empty(&list_head)) {
- bfa_q_deq(&list_head, &qe);
- mac = (struct bna_mac *)qe;
- bfa_q_qe_init(&mac->qe);
- list_add_tail(&mac->qe, &rxf->ucast_pending_add_q);
+ mac = list_first_entry(&list_head, struct bna_mac, qe);
+ list_move_tail(&mac->qe, &rxf->ucast_pending_add_q);
}
- rxf->cam_fltr_cbfn = cbfn;
- rxf->cam_fltr_cbarg = rx->bna->bnad;
bfa_fsm_send_event(rxf, RXF_E_CONFIG);
return BNA_CB_SUCCESS;
err_return:
while (!list_empty(&list_head)) {
- bfa_q_deq(&list_head, &qe);
- mac = (struct bna_mac *)qe;
- bfa_q_qe_init(&mac->qe);
- bna_cam_mod_mac_put(&ucam_mod->free_q, mac);
+ mac = list_first_entry(&list_head, struct bna_mac, qe);
+ list_move_tail(&mac->qe, &ucam_mod->free_q);
}
return BNA_CB_UCAST_CAM_FULL;
}
enum bna_cb_status
-bna_rx_mcast_listset(struct bna_rx *rx, int count, u8 *mclist,
- void (*cbfn)(struct bnad *, struct bna_rx *))
+bna_rx_mcast_listset(struct bna_rx *rx, int count, const u8 *mclist)
{
struct bna_mcam_mod *mcam_mod = &rx->bna->mcam_mod;
struct bna_rxf *rxf = &rx->rxf;
struct list_head list_head;
- struct list_head *qe;
- u8 *mcaddr;
+ const u8 *mcaddr;
struct bna_mac *mac, *del_mac;
int i;
/* Purge the pending_add_q */
while (!list_empty(&rxf->mcast_pending_add_q)) {
- bfa_q_deq(&rxf->mcast_pending_add_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
- bna_cam_mod_mac_put(&mcam_mod->free_q, mac);
+ mac = list_first_entry(&rxf->mcast_pending_add_q,
+ struct bna_mac, qe);
+ list_move_tail(&mac->qe, &mcam_mod->free_q);
}
/* Schedule active_q entries for deletion */
while (!list_empty(&rxf->mcast_active_q)) {
- bfa_q_deq(&rxf->mcast_active_q, &qe);
- mac = (struct bna_mac *)qe;
- bfa_q_qe_init(&mac->qe);
-
+ mac = list_first_entry(&rxf->mcast_active_q,
+ struct bna_mac, qe);
del_mac = bna_cam_mod_mac_get(&mcam_mod->del_q);
-
- memcpy(del_mac, mac, sizeof(*del_mac));
+ ether_addr_copy(del_mac->addr, mac->addr);
+ del_mac->handle = mac->handle;
list_add_tail(&del_mac->qe, &rxf->mcast_pending_del_q);
mac->handle = NULL;
- bna_cam_mod_mac_put(&mcam_mod->free_q, mac);
+ list_move_tail(&mac->qe, &mcam_mod->free_q);
}
/* Allocate nodes */
@@ -1025,8 +872,7 @@ bna_rx_mcast_listset(struct bna_rx *rx, int count, u8 *mclist,
mac = bna_cam_mod_mac_get(&mcam_mod->free_q);
if (mac == NULL)
goto err_return;
- bfa_q_qe_init(&mac->qe);
- memcpy(mac->addr, mcaddr, ETH_ALEN);
+ ether_addr_copy(mac->addr, mcaddr);
list_add_tail(&mac->qe, &list_head);
mcaddr += ETH_ALEN;
@@ -1034,70 +880,52 @@ bna_rx_mcast_listset(struct bna_rx *rx, int count, u8 *mclist,
/* Add the new entries */
while (!list_empty(&list_head)) {
- bfa_q_deq(&list_head, &qe);
- mac = (struct bna_mac *)qe;
- bfa_q_qe_init(&mac->qe);
- list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
+ mac = list_first_entry(&list_head, struct bna_mac, qe);
+ list_move_tail(&mac->qe, &rxf->mcast_pending_add_q);
}
- rxf->cam_fltr_cbfn = cbfn;
- rxf->cam_fltr_cbarg = rx->bna->bnad;
bfa_fsm_send_event(rxf, RXF_E_CONFIG);
return BNA_CB_SUCCESS;
err_return:
while (!list_empty(&list_head)) {
- bfa_q_deq(&list_head, &qe);
- mac = (struct bna_mac *)qe;
- bfa_q_qe_init(&mac->qe);
- bna_cam_mod_mac_put(&mcam_mod->free_q, mac);
+ mac = list_first_entry(&list_head, struct bna_mac, qe);
+ list_move_tail(&mac->qe, &mcam_mod->free_q);
}
return BNA_CB_MCAST_LIST_FULL;
}
void
-bna_rx_mcast_delall(struct bna_rx *rx,
- void (*cbfn)(struct bnad *, struct bna_rx *))
+bna_rx_mcast_delall(struct bna_rx *rx)
{
struct bna_rxf *rxf = &rx->rxf;
- struct list_head *qe;
struct bna_mac *mac, *del_mac;
int need_hw_config = 0;
/* Purge all entries from pending_add_q */
while (!list_empty(&rxf->mcast_pending_add_q)) {
- bfa_q_deq(&rxf->mcast_pending_add_q, &qe);
- mac = (struct bna_mac *)qe;
- bfa_q_qe_init(&mac->qe);
- bna_cam_mod_mac_put(bna_mcam_mod_free_q(rxf->rx->bna), mac);
+ mac = list_first_entry(&rxf->mcast_pending_add_q,
+ struct bna_mac, qe);
+ list_move_tail(&mac->qe, bna_mcam_mod_free_q(rxf->rx->bna));
}
/* Schedule all entries in active_q for deletion */
while (!list_empty(&rxf->mcast_active_q)) {
- bfa_q_deq(&rxf->mcast_active_q, &qe);
- mac = (struct bna_mac *)qe;
- bfa_q_qe_init(&mac->qe);
-
+ mac = list_first_entry(&rxf->mcast_active_q,
+ struct bna_mac, qe);
+ list_del(&mac->qe);
del_mac = bna_cam_mod_mac_get(bna_mcam_mod_del_q(rxf->rx->bna));
-
memcpy(del_mac, mac, sizeof(*del_mac));
list_add_tail(&del_mac->qe, &rxf->mcast_pending_del_q);
mac->handle = NULL;
- bna_cam_mod_mac_put(bna_mcam_mod_free_q(rxf->rx->bna), mac);
+ list_add_tail(&mac->qe, bna_mcam_mod_free_q(rxf->rx->bna));
need_hw_config = 1;
}
- if (need_hw_config) {
- rxf->cam_fltr_cbfn = cbfn;
- rxf->cam_fltr_cbarg = rx->bna->bnad;
+ if (need_hw_config)
bfa_fsm_send_event(rxf, RXF_E_CONFIG);
- return;
- }
-
- if (cbfn)
- (*cbfn)(rx->bna->bnad, rx);
}
void
@@ -1105,12 +933,12 @@ bna_rx_vlan_add(struct bna_rx *rx, int vlan_id)
{
struct bna_rxf *rxf = &rx->rxf;
int index = (vlan_id >> BFI_VLAN_WORD_SHIFT);
- int bit = (1 << (vlan_id & BFI_VLAN_WORD_MASK));
+ int bit = BIT(vlan_id & BFI_VLAN_WORD_MASK);
int group_id = (vlan_id >> BFI_VLAN_BLOCK_SHIFT);
rxf->vlan_filter_table[index] |= bit;
if (rxf->vlan_filter_status == BNA_STATUS_T_ENABLED) {
- rxf->vlan_pending_bitmask |= (1 << group_id);
+ rxf->vlan_pending_bitmask |= BIT(group_id);
bfa_fsm_send_event(rxf, RXF_E_CONFIG);
}
}
@@ -1120,12 +948,12 @@ bna_rx_vlan_del(struct bna_rx *rx, int vlan_id)
{
struct bna_rxf *rxf = &rx->rxf;
int index = (vlan_id >> BFI_VLAN_WORD_SHIFT);
- int bit = (1 << (vlan_id & BFI_VLAN_WORD_MASK));
+ int bit = BIT(vlan_id & BFI_VLAN_WORD_MASK);
int group_id = (vlan_id >> BFI_VLAN_BLOCK_SHIFT);
rxf->vlan_filter_table[index] &= ~bit;
if (rxf->vlan_filter_status == BNA_STATUS_T_ENABLED) {
- rxf->vlan_pending_bitmask |= (1 << group_id);
+ rxf->vlan_pending_bitmask |= BIT(group_id);
bfa_fsm_send_event(rxf, RXF_E_CONFIG);
}
}
@@ -1134,23 +962,21 @@ static int
bna_rxf_ucast_cfg_apply(struct bna_rxf *rxf)
{
struct bna_mac *mac = NULL;
- struct list_head *qe;
/* Delete MAC addresses previousely added */
if (!list_empty(&rxf->ucast_pending_del_q)) {
- bfa_q_deq(&rxf->ucast_pending_del_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
+ mac = list_first_entry(&rxf->ucast_pending_del_q,
+ struct bna_mac, qe);
bna_bfi_ucast_req(rxf, mac, BFI_ENET_H2I_MAC_UCAST_DEL_REQ);
- bna_cam_mod_mac_put(bna_ucam_mod_del_q(rxf->rx->bna), mac);
+ list_move_tail(&mac->qe, bna_ucam_mod_del_q(rxf->rx->bna));
return 1;
}
/* Set default unicast MAC */
if (rxf->ucast_pending_set) {
rxf->ucast_pending_set = 0;
- memcpy(rxf->ucast_active_mac.addr,
- rxf->ucast_pending_mac->addr, ETH_ALEN);
+ ether_addr_copy(rxf->ucast_active_mac.addr,
+ rxf->ucast_pending_mac->addr);
rxf->ucast_active_set = 1;
bna_bfi_ucast_req(rxf, &rxf->ucast_active_mac,
BFI_ENET_H2I_MAC_UCAST_SET_REQ);
@@ -1159,9 +985,8 @@ bna_rxf_ucast_cfg_apply(struct bna_rxf *rxf)
/* Add additional MAC entries */
if (!list_empty(&rxf->ucast_pending_add_q)) {
- bfa_q_deq(&rxf->ucast_pending_add_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
+ mac = list_first_entry(&rxf->ucast_pending_add_q,
+ struct bna_mac, qe);
list_add_tail(&mac->qe, &rxf->ucast_active_q);
bna_bfi_ucast_req(rxf, mac, BFI_ENET_H2I_MAC_UCAST_ADD_REQ);
return 1;
@@ -1173,33 +998,30 @@ bna_rxf_ucast_cfg_apply(struct bna_rxf *rxf)
static int
bna_rxf_ucast_cfg_reset(struct bna_rxf *rxf, enum bna_cleanup_type cleanup)
{
- struct list_head *qe;
struct bna_mac *mac;
/* Throw away delete pending ucast entries */
while (!list_empty(&rxf->ucast_pending_del_q)) {
- bfa_q_deq(&rxf->ucast_pending_del_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
+ mac = list_first_entry(&rxf->ucast_pending_del_q,
+ struct bna_mac, qe);
if (cleanup == BNA_SOFT_CLEANUP)
- bna_cam_mod_mac_put(bna_ucam_mod_del_q(rxf->rx->bna),
- mac);
+ list_move_tail(&mac->qe,
+ bna_ucam_mod_del_q(rxf->rx->bna));
else {
bna_bfi_ucast_req(rxf, mac,
- BFI_ENET_H2I_MAC_UCAST_DEL_REQ);
- bna_cam_mod_mac_put(bna_ucam_mod_del_q(rxf->rx->bna),
- mac);
+ BFI_ENET_H2I_MAC_UCAST_DEL_REQ);
+ list_move_tail(&mac->qe,
+ bna_ucam_mod_del_q(rxf->rx->bna));
return 1;
}
}
/* Move active ucast entries to pending_add_q */
while (!list_empty(&rxf->ucast_active_q)) {
- bfa_q_deq(&rxf->ucast_active_q, &qe);
- bfa_q_qe_init(qe);
- list_add_tail(qe, &rxf->ucast_pending_add_q);
+ mac = list_first_entry(&rxf->ucast_active_q,
+ struct bna_mac, qe);
+ list_move_tail(&mac->qe, &rxf->ucast_pending_add_q);
if (cleanup == BNA_HARD_CLEANUP) {
- mac = (struct bna_mac *)qe;
bna_bfi_ucast_req(rxf, mac,
BFI_ENET_H2I_MAC_UCAST_DEL_REQ);
return 1;
@@ -1654,14 +1476,11 @@ static void
bna_rx_sm_started_entry(struct bna_rx *rx)
{
struct bna_rxp *rxp;
- struct list_head *qe_rxp;
int is_regular = (rx->type == BNA_RX_T_REGULAR);
/* Start IB */
- list_for_each(qe_rxp, &rx->rxp_q) {
- rxp = (struct bna_rxp *)qe_rxp;
+ list_for_each_entry(rxp, &rx->rxp_q, qe)
bna_ib_start(rx->bna, &rxp->cq.ib, is_regular);
- }
bna_ethport_cb_rx_started(&rx->bna->ethport);
}
@@ -1804,7 +1623,6 @@ bna_bfi_rx_enet_start(struct bna_rx *rx)
struct bfi_enet_rx_cfg_req *cfg_req = &rx->bfi_enet_cmd.cfg_req;
struct bna_rxp *rxp = NULL;
struct bna_rxq *q0 = NULL, *q1 = NULL;
- struct list_head *rxp_qe;
int i;
bfi_msgq_mhdr_set(cfg_req->mh, BFI_MC_ENET,
@@ -1814,11 +1632,9 @@ bna_bfi_rx_enet_start(struct bna_rx *rx)
cfg_req->rx_cfg.frame_size = bna_enet_mtu_get(&rx->bna->enet);
cfg_req->num_queue_sets = rx->num_paths;
- for (i = 0, rxp_qe = bfa_q_first(&rx->rxp_q);
- i < rx->num_paths;
- i++, rxp_qe = bfa_q_next(rxp_qe)) {
- rxp = (struct bna_rxp *)rxp_qe;
-
+ for (i = 0; i < rx->num_paths; i++) {
+ rxp = rxp ? list_next_entry(rxp, qe)
+ : list_first_entry(&rx->rxp_q, struct bna_rxp, qe);
GET_RXQS(rxp, q0, q1);
switch (rxp->type) {
case BNA_RXP_SLR:
@@ -1921,13 +1737,10 @@ static void
bna_rx_enet_stop(struct bna_rx *rx)
{
struct bna_rxp *rxp;
- struct list_head *qe_rxp;
/* Stop IB */
- list_for_each(qe_rxp, &rx->rxp_q) {
- rxp = (struct bna_rxp *)qe_rxp;
+ list_for_each_entry(rxp, &rx->rxp_q, qe)
bna_ib_stop(rx->bna, &rxp->cq.ib);
- }
bna_bfi_rx_enet_stop(rx);
}
@@ -1957,12 +1770,10 @@ static struct bna_rxq *
bna_rxq_get(struct bna_rx_mod *rx_mod)
{
struct bna_rxq *rxq = NULL;
- struct list_head *qe = NULL;
- bfa_q_deq(&rx_mod->rxq_free_q, &qe);
+ rxq = list_first_entry(&rx_mod->rxq_free_q, struct bna_rxq, qe);
+ list_del(&rxq->qe);
rx_mod->rxq_free_count--;
- rxq = (struct bna_rxq *)qe;
- bfa_q_qe_init(&rxq->qe);
return rxq;
}
@@ -1970,7 +1781,6 @@ bna_rxq_get(struct bna_rx_mod *rx_mod)
static void
bna_rxq_put(struct bna_rx_mod *rx_mod, struct bna_rxq *rxq)
{
- bfa_q_qe_init(&rxq->qe);
list_add_tail(&rxq->qe, &rx_mod->rxq_free_q);
rx_mod->rxq_free_count++;
}
@@ -1978,13 +1788,11 @@ bna_rxq_put(struct bna_rx_mod *rx_mod, struct bna_rxq *rxq)
static struct bna_rxp *
bna_rxp_get(struct bna_rx_mod *rx_mod)
{
- struct list_head *qe = NULL;
struct bna_rxp *rxp = NULL;
- bfa_q_deq(&rx_mod->rxp_free_q, &qe);
+ rxp = list_first_entry(&rx_mod->rxp_free_q, struct bna_rxp, qe);
+ list_del(&rxp->qe);
rx_mod->rxp_free_count--;
- rxp = (struct bna_rxp *)qe;
- bfa_q_qe_init(&rxp->qe);
return rxp;
}
@@ -1992,7 +1800,6 @@ bna_rxp_get(struct bna_rx_mod *rx_mod)
static void
bna_rxp_put(struct bna_rx_mod *rx_mod, struct bna_rxp *rxp)
{
- bfa_q_qe_init(&rxp->qe);
list_add_tail(&rxp->qe, &rx_mod->rxp_free_q);
rx_mod->rxp_free_count++;
}
@@ -2000,18 +1807,16 @@ bna_rxp_put(struct bna_rx_mod *rx_mod, struct bna_rxp *rxp)
static struct bna_rx *
bna_rx_get(struct bna_rx_mod *rx_mod, enum bna_rx_type type)
{
- struct list_head *qe = NULL;
struct bna_rx *rx = NULL;
- if (type == BNA_RX_T_REGULAR) {
- bfa_q_deq(&rx_mod->rx_free_q, &qe);
- } else
- bfa_q_deq_tail(&rx_mod->rx_free_q, &qe);
+ BUG_ON(list_empty(&rx_mod->rx_free_q));
+ if (type == BNA_RX_T_REGULAR)
+ rx = list_first_entry(&rx_mod->rx_free_q, struct bna_rx, qe);
+ else
+ rx = list_last_entry(&rx_mod->rx_free_q, struct bna_rx, qe);
rx_mod->rx_free_count--;
- rx = (struct bna_rx *)qe;
- bfa_q_qe_init(&rx->qe);
- list_add_tail(&rx->qe, &rx_mod->rx_active_q);
+ list_move_tail(&rx->qe, &rx_mod->rx_active_q);
rx->type = type;
return rx;
@@ -2020,32 +1825,13 @@ bna_rx_get(struct bna_rx_mod *rx_mod, enum bna_rx_type type)
static void
bna_rx_put(struct bna_rx_mod *rx_mod, struct bna_rx *rx)
{
- struct list_head *prev_qe = NULL;
struct list_head *qe;
- bfa_q_qe_init(&rx->qe);
-
- list_for_each(qe, &rx_mod->rx_free_q) {
+ list_for_each_prev(qe, &rx_mod->rx_free_q)
if (((struct bna_rx *)qe)->rid < rx->rid)
- prev_qe = qe;
- else
break;
- }
-
- if (prev_qe == NULL) {
- /* This is the first entry */
- bfa_q_enq_head(&rx_mod->rx_free_q, &rx->qe);
- } else if (bfa_q_next(prev_qe) == &rx_mod->rx_free_q) {
- /* This is the last entry */
- list_add_tail(&rx->qe, &rx_mod->rx_free_q);
- } else {
- /* Somewhere in the middle */
- bfa_q_next(&rx->qe) = bfa_q_next(prev_qe);
- bfa_q_prev(&rx->qe) = prev_qe;
- bfa_q_next(prev_qe) = &rx->qe;
- bfa_q_prev(bfa_q_next(&rx->qe)) = &rx->qe;
- }
+ list_add(&rx->qe, qe);
rx_mod->rx_free_count++;
}
@@ -2199,24 +1985,20 @@ void
bna_rx_mod_start(struct bna_rx_mod *rx_mod, enum bna_rx_type type)
{
struct bna_rx *rx;
- struct list_head *qe;
rx_mod->flags |= BNA_RX_MOD_F_ENET_STARTED;
if (type == BNA_RX_T_LOOPBACK)
rx_mod->flags |= BNA_RX_MOD_F_ENET_LOOPBACK;
- list_for_each(qe, &rx_mod->rx_active_q) {
- rx = (struct bna_rx *)qe;
+ list_for_each_entry(rx, &rx_mod->rx_active_q, qe)
if (rx->type == type)
bna_rx_start(rx);
- }
}
void
bna_rx_mod_stop(struct bna_rx_mod *rx_mod, enum bna_rx_type type)
{
struct bna_rx *rx;
- struct list_head *qe;
rx_mod->flags &= ~BNA_RX_MOD_F_ENET_STARTED;
rx_mod->flags &= ~BNA_RX_MOD_F_ENET_LOOPBACK;
@@ -2225,13 +2007,11 @@ bna_rx_mod_stop(struct bna_rx_mod *rx_mod, enum bna_rx_type type)
bfa_wc_init(&rx_mod->rx_stop_wc, bna_rx_mod_cb_rx_stopped_all, rx_mod);
- list_for_each(qe, &rx_mod->rx_active_q) {
- rx = (struct bna_rx *)qe;
+ list_for_each_entry(rx, &rx_mod->rx_active_q, qe)
if (rx->type == type) {
bfa_wc_up(&rx_mod->rx_stop_wc);
bna_rx_stop(rx);
}
- }
bfa_wc_wait(&rx_mod->rx_stop_wc);
}
@@ -2240,15 +2020,12 @@ void
bna_rx_mod_fail(struct bna_rx_mod *rx_mod)
{
struct bna_rx *rx;
- struct list_head *qe;
rx_mod->flags &= ~BNA_RX_MOD_F_ENET_STARTED;
rx_mod->flags &= ~BNA_RX_MOD_F_ENET_LOOPBACK;
- list_for_each(qe, &rx_mod->rx_active_q) {
- rx = (struct bna_rx *)qe;
+ list_for_each_entry(rx, &rx_mod->rx_active_q, qe)
bna_rx_fail(rx);
- }
}
void bna_rx_mod_init(struct bna_rx_mod *rx_mod, struct bna *bna,
@@ -2282,7 +2059,6 @@ void bna_rx_mod_init(struct bna_rx_mod *rx_mod, struct bna *bna,
for (index = 0; index < bna->ioceth.attr.num_rxp; index++) {
rx_ptr = &rx_mod->rx[index];
- bfa_q_qe_init(&rx_ptr->qe);
INIT_LIST_HEAD(&rx_ptr->rxp_q);
rx_ptr->bna = NULL;
rx_ptr->rid = index;
@@ -2296,7 +2072,6 @@ void bna_rx_mod_init(struct bna_rx_mod *rx_mod, struct bna *bna,
/* build RX-path queue */
for (index = 0; index < bna->ioceth.attr.num_rxp; index++) {
rxp_ptr = &rx_mod->rxp[index];
- bfa_q_qe_init(&rxp_ptr->qe);
list_add_tail(&rxp_ptr->qe, &rx_mod->rxp_free_q);
rx_mod->rxp_free_count++;
}
@@ -2304,7 +2079,6 @@ void bna_rx_mod_init(struct bna_rx_mod *rx_mod, struct bna *bna,
/* build RXQ queue */
for (index = 0; index < (bna->ioceth.attr.num_rxp * 2); index++) {
rxq_ptr = &rx_mod->rxq[index];
- bfa_q_qe_init(&rxq_ptr->qe);
list_add_tail(&rxq_ptr->qe, &rx_mod->rxq_free_q);
rx_mod->rxq_free_count++;
}
@@ -2313,21 +2087,6 @@ void bna_rx_mod_init(struct bna_rx_mod *rx_mod, struct bna *bna,
void
bna_rx_mod_uninit(struct bna_rx_mod *rx_mod)
{
- struct list_head *qe;
- int i;
-
- i = 0;
- list_for_each(qe, &rx_mod->rx_free_q)
- i++;
-
- i = 0;
- list_for_each(qe, &rx_mod->rxp_free_q)
- i++;
-
- i = 0;
- list_for_each(qe, &rx_mod->rxq_free_q)
- i++;
-
rx_mod->bna = NULL;
}
@@ -2337,7 +2096,6 @@ bna_bfi_rx_enet_start_rsp(struct bna_rx *rx, struct bfi_msgq_mhdr *msghdr)
struct bfi_enet_rx_cfg_rsp *cfg_rsp = &rx->bfi_enet_cmd.cfg_rsp;
struct bna_rxp *rxp = NULL;
struct bna_rxq *q0 = NULL, *q1 = NULL;
- struct list_head *rxp_qe;
int i;
bfa_msgq_rsp_copy(&rx->bna->msgq, (u8 *)cfg_rsp,
@@ -2345,10 +2103,8 @@ bna_bfi_rx_enet_start_rsp(struct bna_rx *rx, struct bfi_msgq_mhdr *msghdr)
rx->hw_id = cfg_rsp->hw_id;
- for (i = 0, rxp_qe = bfa_q_first(&rx->rxp_q);
- i < rx->num_paths;
- i++, rxp_qe = bfa_q_next(rxp_qe)) {
- rxp = (struct bna_rxp *)rxp_qe;
+ for (i = 0, rxp = list_first_entry(&rx->rxp_q, struct bna_rxp, qe);
+ i < rx->num_paths; i++, rxp = list_next_entry(rxp, qe)) {
GET_RXQS(rxp, q0, q1);
/* Setup doorbells */
@@ -2396,20 +2152,19 @@ bna_rx_res_req(struct bna_rx_config *q_cfg, struct bna_res_info *res_info)
dq_depth = q_cfg->q0_depth;
hq_depth = ((q_cfg->rxp_type == BNA_RXP_SINGLE) ? 0 : q_cfg->q1_depth);
- cq_depth = dq_depth + hq_depth;
+ cq_depth = roundup_pow_of_two(dq_depth + hq_depth);
- BNA_TO_POWER_OF_2_HIGH(cq_depth);
cq_size = cq_depth * BFI_CQ_WI_SIZE;
cq_size = ALIGN(cq_size, PAGE_SIZE);
cpage_count = SIZE_TO_PAGES(cq_size);
- BNA_TO_POWER_OF_2_HIGH(dq_depth);
+ dq_depth = roundup_pow_of_two(dq_depth);
dq_size = dq_depth * BFI_RXQ_WI_SIZE;
dq_size = ALIGN(dq_size, PAGE_SIZE);
dpage_count = SIZE_TO_PAGES(dq_size);
if (BNA_RXP_SINGLE != q_cfg->rxp_type) {
- BNA_TO_POWER_OF_2_HIGH(hq_depth);
+ hq_depth = roundup_pow_of_two(hq_depth);
hq_size = hq_depth * BFI_RXQ_WI_SIZE;
hq_size = ALIGN(hq_size, PAGE_SIZE);
hpage_count = SIZE_TO_PAGES(hq_size);
@@ -2620,7 +2375,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad,
if (intr_info->intr_type == BNA_INTR_T_MSIX)
rxp->cq.ib.intr_vector = rxp->vector;
else
- rxp->cq.ib.intr_vector = (1 << rxp->vector);
+ rxp->cq.ib.intr_vector = BIT(rxp->vector);
rxp->cq.ib.coalescing_timeo = rx_cfg->coalescing_timeo;
rxp->cq.ib.interpkt_count = BFI_RX_INTERPKT_COUNT;
rxp->cq.ib.interpkt_timeo = BFI_RX_INTERPKT_TIMEO;
@@ -2691,7 +2446,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad,
/* if multi-buffer is enabled sum of q0_depth
* and q1_depth need not be a power of 2
*/
- BNA_TO_POWER_OF_2_HIGH(cq_depth);
+ cq_depth = roundup_pow_of_two(cq_depth);
rxp->cq.ccb->q_depth = cq_depth;
rxp->cq.ccb->cq = &rxp->cq;
rxp->cq.ccb->rcb[0] = q0->rcb;
@@ -2725,7 +2480,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad,
bfa_fsm_set_state(rx, bna_rx_sm_stopped);
- rx_mod->rid_mask |= (1 << rx->rid);
+ rx_mod->rid_mask |= BIT(rx->rid);
return rx;
}
@@ -2742,7 +2497,8 @@ bna_rx_destroy(struct bna_rx *rx)
bna_rxf_uninit(&rx->rxf);
while (!list_empty(&rx->rxp_q)) {
- bfa_q_deq(&rx->rxp_q, &rxp);
+ rxp = list_first_entry(&rx->rxp_q, struct bna_rxp, qe);
+ list_del(&rxp->qe);
GET_RXQS(rxp, q0, q1);
if (rx->rcb_destroy_cbfn)
rx->rcb_destroy_cbfn(rx->bna->bnad, q0->rcb);
@@ -2769,15 +2525,13 @@ bna_rx_destroy(struct bna_rx *rx)
bna_rxp_put(rx_mod, rxp);
}
- list_for_each(qe, &rx_mod->rx_active_q) {
+ list_for_each(qe, &rx_mod->rx_active_q)
if (qe == &rx->qe) {
list_del(&rx->qe);
- bfa_q_qe_init(&rx->qe);
break;
}
- }
- rx_mod->rid_mask &= ~(1 << rx->rid);
+ rx_mod->rid_mask &= ~BIT(rx->rid);
rx->bna = NULL;
rx->priv = NULL;
@@ -2844,8 +2598,7 @@ bna_rx_vlan_strip_disable(struct bna_rx *rx)
enum bna_cb_status
bna_rx_mode_set(struct bna_rx *rx, enum bna_rxmode new_mode,
- enum bna_rxmode bitmask,
- void (*cbfn)(struct bnad *, struct bna_rx *))
+ enum bna_rxmode bitmask)
{
struct bna_rxf *rxf = &rx->rxf;
int need_hw_config = 0;
@@ -2900,11 +2653,10 @@ bna_rx_mode_set(struct bna_rx *rx, enum bna_rxmode new_mode,
/* Trigger h/w if needed */
if (need_hw_config) {
- rxf->cam_fltr_cbfn = cbfn;
+ rxf->cam_fltr_cbfn = NULL;
rxf->cam_fltr_cbarg = rx->bna->bnad;
bfa_fsm_send_event(rxf, RXF_E_CONFIG);
- } else if (cbfn)
- (*cbfn)(rx->bna->bnad, rx);
+ }
return BNA_CB_SUCCESS;
@@ -2928,10 +2680,8 @@ void
bna_rx_coalescing_timeo_set(struct bna_rx *rx, int coalescing_timeo)
{
struct bna_rxp *rxp;
- struct list_head *qe;
- list_for_each(qe, &rx->rxp_q) {
- rxp = (struct bna_rxp *)qe;
+ list_for_each_entry(rxp, &rx->rxp_q, qe) {
rxp->cq.ccb->rx_coalescing_timeo = coalescing_timeo;
bna_ib_coalescing_timeo_set(&rxp->cq.ib, coalescing_timeo);
}
@@ -3024,16 +2774,6 @@ do { \
} \
} while (0)
-#define call_tx_prio_change_cbfn(tx) \
-do { \
- if ((tx)->prio_change_cbfn) { \
- void (*cbfn)(struct bnad *, struct bna_tx *); \
- cbfn = (tx)->prio_change_cbfn; \
- (tx)->prio_change_cbfn = NULL; \
- cbfn((tx)->bna->bnad, (tx)); \
- } \
-} while (0)
-
static void bna_tx_mod_cb_tx_stopped(void *tx_mod, struct bna_tx *tx);
static void bna_bfi_tx_enet_start(struct bna_tx *tx);
static void bna_tx_enet_stop(struct bna_tx *tx);
@@ -3044,7 +2784,6 @@ enum bna_tx_event {
TX_E_FAIL = 3,
TX_E_STARTED = 4,
TX_E_STOPPED = 5,
- TX_E_PRIO_CHANGE = 6,
TX_E_CLEANUP_DONE = 7,
TX_E_BW_UPDATE = 8,
};
@@ -3085,10 +2824,6 @@ bna_tx_sm_stopped(struct bna_tx *tx, enum bna_tx_event event)
/* No-op */
break;
- case TX_E_PRIO_CHANGE:
- call_tx_prio_change_cbfn(tx);
- break;
-
case TX_E_BW_UPDATE:
/* No-op */
break;
@@ -3109,28 +2844,23 @@ bna_tx_sm_start_wait(struct bna_tx *tx, enum bna_tx_event event)
{
switch (event) {
case TX_E_STOP:
- tx->flags &= ~(BNA_TX_F_PRIO_CHANGED | BNA_TX_F_BW_UPDATED);
+ tx->flags &= ~BNA_TX_F_BW_UPDATED;
bfa_fsm_set_state(tx, bna_tx_sm_stop_wait);
break;
case TX_E_FAIL:
- tx->flags &= ~(BNA_TX_F_PRIO_CHANGED | BNA_TX_F_BW_UPDATED);
+ tx->flags &= ~BNA_TX_F_BW_UPDATED;
bfa_fsm_set_state(tx, bna_tx_sm_stopped);
break;
case TX_E_STARTED:
- if (tx->flags & (BNA_TX_F_PRIO_CHANGED | BNA_TX_F_BW_UPDATED)) {
- tx->flags &= ~(BNA_TX_F_PRIO_CHANGED |
- BNA_TX_F_BW_UPDATED);
+ if (tx->flags & BNA_TX_F_BW_UPDATED) {
+ tx->flags &= ~BNA_TX_F_BW_UPDATED;
bfa_fsm_set_state(tx, bna_tx_sm_prio_stop_wait);
} else
bfa_fsm_set_state(tx, bna_tx_sm_started);
break;
- case TX_E_PRIO_CHANGE:
- tx->flags |= BNA_TX_F_PRIO_CHANGED;
- break;
-
case TX_E_BW_UPDATE:
tx->flags |= BNA_TX_F_BW_UPDATED;
break;
@@ -3144,11 +2874,9 @@ static void
bna_tx_sm_started_entry(struct bna_tx *tx)
{
struct bna_txq *txq;
- struct list_head *qe;
int is_regular = (tx->type == BNA_TX_T_REGULAR);
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
+ list_for_each_entry(txq, &tx->txq_q, qe) {
txq->tcb->priority = txq->priority;
/* Start IB */
bna_ib_start(tx->bna, &txq->ib, is_regular);
@@ -3172,7 +2900,6 @@ bna_tx_sm_started(struct bna_tx *tx, enum bna_tx_event event)
tx->tx_cleanup_cbfn(tx->bna->bnad, tx);
break;
- case TX_E_PRIO_CHANGE:
case TX_E_BW_UPDATE:
bfa_fsm_set_state(tx, bna_tx_sm_prio_stop_wait);
break;
@@ -3205,7 +2932,6 @@ bna_tx_sm_stop_wait(struct bna_tx *tx, enum bna_tx_event event)
bna_tx_enet_stop(tx);
break;
- case TX_E_PRIO_CHANGE:
case TX_E_BW_UPDATE:
/* No-op */
break;
@@ -3225,7 +2951,6 @@ bna_tx_sm_cleanup_wait(struct bna_tx *tx, enum bna_tx_event event)
{
switch (event) {
case TX_E_FAIL:
- case TX_E_PRIO_CHANGE:
case TX_E_BW_UPDATE:
/* No-op */
break;
@@ -3256,7 +2981,6 @@ bna_tx_sm_prio_stop_wait(struct bna_tx *tx, enum bna_tx_event event)
case TX_E_FAIL:
bfa_fsm_set_state(tx, bna_tx_sm_failed);
- call_tx_prio_change_cbfn(tx);
tx->tx_cleanup_cbfn(tx->bna->bnad, tx);
break;
@@ -3264,7 +2988,6 @@ bna_tx_sm_prio_stop_wait(struct bna_tx *tx, enum bna_tx_event event)
bfa_fsm_set_state(tx, bna_tx_sm_prio_cleanup_wait);
break;
- case TX_E_PRIO_CHANGE:
case TX_E_BW_UPDATE:
/* No-op */
break;
@@ -3277,7 +3000,6 @@ bna_tx_sm_prio_stop_wait(struct bna_tx *tx, enum bna_tx_event event)
static void
bna_tx_sm_prio_cleanup_wait_entry(struct bna_tx *tx)
{
- call_tx_prio_change_cbfn(tx);
tx->tx_cleanup_cbfn(tx->bna->bnad, tx);
}
@@ -3293,7 +3015,6 @@ bna_tx_sm_prio_cleanup_wait(struct bna_tx *tx, enum bna_tx_event event)
bfa_fsm_set_state(tx, bna_tx_sm_failed);
break;
- case TX_E_PRIO_CHANGE:
case TX_E_BW_UPDATE:
/* No-op */
break;
@@ -3372,7 +3093,6 @@ bna_bfi_tx_enet_start(struct bna_tx *tx)
{
struct bfi_enet_tx_cfg_req *cfg_req = &tx->bfi_enet_cmd.cfg_req;
struct bna_txq *txq = NULL;
- struct list_head *qe;
int i;
bfi_msgq_mhdr_set(cfg_req->mh, BFI_MC_ENET,
@@ -3381,11 +3101,9 @@ bna_bfi_tx_enet_start(struct bna_tx *tx)
bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_tx_cfg_req)));
cfg_req->num_queues = tx->num_txq;
- for (i = 0, qe = bfa_q_first(&tx->txq_q);
- i < tx->num_txq;
- i++, qe = bfa_q_next(qe)) {
- txq = (struct bna_txq *)qe;
-
+ for (i = 0; i < tx->num_txq; i++) {
+ txq = txq ? list_next_entry(txq, qe)
+ : list_first_entry(&tx->txq_q, struct bna_txq, qe);
bfi_enet_datapath_q_init(&cfg_req->q_cfg[i].q.q, &txq->qpt);
cfg_req->q_cfg[i].q.priority = txq->priority;
@@ -3437,13 +3155,10 @@ static void
bna_tx_enet_stop(struct bna_tx *tx)
{
struct bna_txq *txq;
- struct list_head *qe;
/* Stop IB */
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
+ list_for_each_entry(txq, &tx->txq_q, qe)
bna_ib_stop(tx->bna, &txq->ib);
- }
bna_bfi_tx_enet_stop(tx);
}
@@ -3487,18 +3202,15 @@ bna_txq_qpt_setup(struct bna_txq *txq, int page_count, int page_size,
static struct bna_tx *
bna_tx_get(struct bna_tx_mod *tx_mod, enum bna_tx_type type)
{
- struct list_head *qe = NULL;
struct bna_tx *tx = NULL;
if (list_empty(&tx_mod->tx_free_q))
return NULL;
- if (type == BNA_TX_T_REGULAR) {
- bfa_q_deq(&tx_mod->tx_free_q, &qe);
- } else {
- bfa_q_deq_tail(&tx_mod->tx_free_q, &qe);
- }
- tx = (struct bna_tx *)qe;
- bfa_q_qe_init(&tx->qe);
+ if (type == BNA_TX_T_REGULAR)
+ tx = list_first_entry(&tx_mod->tx_free_q, struct bna_tx, qe);
+ else
+ tx = list_last_entry(&tx_mod->tx_free_q, struct bna_tx, qe);
+ list_del(&tx->qe);
tx->type = type;
return tx;
@@ -3509,21 +3221,18 @@ bna_tx_free(struct bna_tx *tx)
{
struct bna_tx_mod *tx_mod = &tx->bna->tx_mod;
struct bna_txq *txq;
- struct list_head *prev_qe;
struct list_head *qe;
while (!list_empty(&tx->txq_q)) {
- bfa_q_deq(&tx->txq_q, &txq);
- bfa_q_qe_init(&txq->qe);
+ txq = list_first_entry(&tx->txq_q, struct bna_txq, qe);
txq->tcb = NULL;
txq->tx = NULL;
- list_add_tail(&txq->qe, &tx_mod->txq_free_q);
+ list_move_tail(&txq->qe, &tx_mod->txq_free_q);
}
list_for_each(qe, &tx_mod->tx_active_q) {
if (qe == &tx->qe) {
list_del(&tx->qe);
- bfa_q_qe_init(&tx->qe);
break;
}
}
@@ -3531,28 +3240,11 @@ bna_tx_free(struct bna_tx *tx)
tx->bna = NULL;
tx->priv = NULL;
- prev_qe = NULL;
- list_for_each(qe, &tx_mod->tx_free_q) {
+ list_for_each_prev(qe, &tx_mod->tx_free_q)
if (((struct bna_tx *)qe)->rid < tx->rid)
- prev_qe = qe;
- else {
break;
- }
- }
- if (prev_qe == NULL) {
- /* This is the first entry */
- bfa_q_enq_head(&tx_mod->tx_free_q, &tx->qe);
- } else if (bfa_q_next(prev_qe) == &tx_mod->tx_free_q) {
- /* This is the last entry */
- list_add_tail(&tx->qe, &tx_mod->tx_free_q);
- } else {
- /* Somewhere in the middle */
- bfa_q_next(&tx->qe) = bfa_q_next(prev_qe);
- bfa_q_prev(&tx->qe) = prev_qe;
- bfa_q_next(prev_qe) = &tx->qe;
- bfa_q_prev(bfa_q_next(&tx->qe)) = &tx->qe;
- }
+ list_add(&tx->qe, qe);
}
static void
@@ -3585,7 +3277,6 @@ bna_bfi_tx_enet_start_rsp(struct bna_tx *tx, struct bfi_msgq_mhdr *msghdr)
{
struct bfi_enet_tx_cfg_rsp *cfg_rsp = &tx->bfi_enet_cmd.cfg_rsp;
struct bna_txq *txq = NULL;
- struct list_head *qe;
int i;
bfa_msgq_rsp_copy(&tx->bna->msgq, (u8 *)cfg_rsp,
@@ -3593,10 +3284,8 @@ bna_bfi_tx_enet_start_rsp(struct bna_tx *tx, struct bfi_msgq_mhdr *msghdr)
tx->hw_id = cfg_rsp->hw_id;
- for (i = 0, qe = bfa_q_first(&tx->txq_q);
- i < tx->num_txq; i++, qe = bfa_q_next(qe)) {
- txq = (struct bna_txq *)qe;
-
+ for (i = 0, txq = list_first_entry(&tx->txq_q, struct bna_txq, qe);
+ i < tx->num_txq; i++, txq = list_next_entry(txq, qe)) {
/* Setup doorbells */
txq->tcb->i_dbell->doorbell_addr =
tx->bna->pcidev.pci_bar_kva
@@ -3624,12 +3313,9 @@ void
bna_bfi_bw_update_aen(struct bna_tx_mod *tx_mod)
{
struct bna_tx *tx;
- struct list_head *qe;
- list_for_each(qe, &tx_mod->tx_active_q) {
- tx = (struct bna_tx *)qe;
+ list_for_each_entry(tx, &tx_mod->tx_active_q, qe)
bfa_fsm_send_event(tx, TX_E_BW_UPDATE);
- }
}
void
@@ -3689,7 +3375,6 @@ bna_tx_create(struct bna *bna, struct bnad *bnad,
struct bna_tx_mod *tx_mod = &bna->tx_mod;
struct bna_tx *tx;
struct bna_txq *txq;
- struct list_head *qe;
int page_count;
int i;
@@ -3719,9 +3404,8 @@ bna_tx_create(struct bna *bna, struct bnad *bnad,
if (list_empty(&tx_mod->txq_free_q))
goto err_return;
- bfa_q_deq(&tx_mod->txq_free_q, &txq);
- bfa_q_qe_init(&txq->qe);
- list_add_tail(&txq->qe, &tx->txq_q);
+ txq = list_first_entry(&tx_mod->txq_free_q, struct bna_txq, qe);
+ list_move_tail(&txq->qe, &tx->txq_q);
txq->tx = tx;
}
@@ -3760,8 +3444,7 @@ bna_tx_create(struct bna *bna, struct bnad *bnad,
/* TxQ */
i = 0;
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
+ list_for_each_entry(txq, &tx->txq_q, qe) {
txq->tcb = (struct bna_tcb *)
res_info[BNA_TX_RES_MEM_T_TCB].res_u.mem_info.mdl[i].kva;
txq->tx_packets = 0;
@@ -3779,7 +3462,7 @@ bna_tx_create(struct bna *bna, struct bnad *bnad,
intr_info->idl[0].vector :
intr_info->idl[i].vector;
if (intr_info->intr_type == BNA_INTR_T_INTX)
- txq->ib.intr_vector = (1 << txq->ib.intr_vector);
+ txq->ib.intr_vector = BIT(txq->ib.intr_vector);
txq->ib.coalescing_timeo = tx_cfg->coalescing_timeo;
txq->ib.interpkt_timeo = BFI_TX_INTERPKT_TIMEO;
txq->ib.interpkt_count = BFI_TX_INTERPKT_COUNT;
@@ -3821,7 +3504,7 @@ bna_tx_create(struct bna *bna, struct bnad *bnad,
bfa_fsm_set_state(tx, bna_tx_sm_stopped);
- tx_mod->rid_mask |= (1 << tx->rid);
+ tx_mod->rid_mask |= BIT(tx->rid);
return tx;
@@ -3834,15 +3517,12 @@ void
bna_tx_destroy(struct bna_tx *tx)
{
struct bna_txq *txq;
- struct list_head *qe;
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
+ list_for_each_entry(txq, &tx->txq_q, qe)
if (tx->tcb_destroy_cbfn)
(tx->tcb_destroy_cbfn)(tx->bna->bnad, txq->tcb);
- }
- tx->bna->tx_mod.rid_mask &= ~(1 << tx->rid);
+ tx->bna->tx_mod.rid_mask &= ~BIT(tx->rid);
bna_tx_free(tx);
}
@@ -3920,9 +3600,7 @@ bna_tx_mod_init(struct bna_tx_mod *tx_mod, struct bna *bna,
for (i = 0; i < bna->ioceth.attr.num_txq; i++) {
tx_mod->tx[i].rid = i;
- bfa_q_qe_init(&tx_mod->tx[i].qe);
list_add_tail(&tx_mod->tx[i].qe, &tx_mod->tx_free_q);
- bfa_q_qe_init(&tx_mod->txq[i].qe);
list_add_tail(&tx_mod->txq[i].qe, &tx_mod->txq_free_q);
}
@@ -3935,17 +3613,6 @@ bna_tx_mod_init(struct bna_tx_mod *tx_mod, struct bna *bna,
void
bna_tx_mod_uninit(struct bna_tx_mod *tx_mod)
{
- struct list_head *qe;
- int i;
-
- i = 0;
- list_for_each(qe, &tx_mod->tx_free_q)
- i++;
-
- i = 0;
- list_for_each(qe, &tx_mod->txq_free_q)
- i++;
-
tx_mod->bna = NULL;
}
@@ -3953,24 +3620,20 @@ void
bna_tx_mod_start(struct bna_tx_mod *tx_mod, enum bna_tx_type type)
{
struct bna_tx *tx;
- struct list_head *qe;
tx_mod->flags |= BNA_TX_MOD_F_ENET_STARTED;
if (type == BNA_TX_T_LOOPBACK)
tx_mod->flags |= BNA_TX_MOD_F_ENET_LOOPBACK;
- list_for_each(qe, &tx_mod->tx_active_q) {
- tx = (struct bna_tx *)qe;
+ list_for_each_entry(tx, &tx_mod->tx_active_q, qe)
if (tx->type == type)
bna_tx_start(tx);
- }
}
void
bna_tx_mod_stop(struct bna_tx_mod *tx_mod, enum bna_tx_type type)
{
struct bna_tx *tx;
- struct list_head *qe;
tx_mod->flags &= ~BNA_TX_MOD_F_ENET_STARTED;
tx_mod->flags &= ~BNA_TX_MOD_F_ENET_LOOPBACK;
@@ -3979,13 +3642,11 @@ bna_tx_mod_stop(struct bna_tx_mod *tx_mod, enum bna_tx_type type)
bfa_wc_init(&tx_mod->tx_stop_wc, bna_tx_mod_cb_tx_stopped_all, tx_mod);
- list_for_each(qe, &tx_mod->tx_active_q) {
- tx = (struct bna_tx *)qe;
+ list_for_each_entry(tx, &tx_mod->tx_active_q, qe)
if (tx->type == type) {
bfa_wc_up(&tx_mod->tx_stop_wc);
bna_tx_stop(tx);
}
- }
bfa_wc_wait(&tx_mod->tx_stop_wc);
}
@@ -3994,25 +3655,19 @@ void
bna_tx_mod_fail(struct bna_tx_mod *tx_mod)
{
struct bna_tx *tx;
- struct list_head *qe;
tx_mod->flags &= ~BNA_TX_MOD_F_ENET_STARTED;
tx_mod->flags &= ~BNA_TX_MOD_F_ENET_LOOPBACK;
- list_for_each(qe, &tx_mod->tx_active_q) {
- tx = (struct bna_tx *)qe;
+ list_for_each_entry(tx, &tx_mod->tx_active_q, qe)
bna_tx_fail(tx);
- }
}
void
bna_tx_coalescing_timeo_set(struct bna_tx *tx, int coalescing_timeo)
{
struct bna_txq *txq;
- struct list_head *qe;
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
+ list_for_each_entry(txq, &tx->txq_q, qe)
bna_ib_coalescing_timeo_set(&txq->ib, coalescing_timeo);
- }
}
diff --git a/drivers/net/ethernet/brocade/bna/bna_types.h b/drivers/net/ethernet/brocade/bna/bna_types.h
index d0a7a566f5d6..e0e797f2ea14 100644
--- a/drivers/net/ethernet/brocade/bna/bna_types.h
+++ b/drivers/net/ethernet/brocade/bna/bna_types.h
@@ -135,7 +135,6 @@ enum bna_tx_type {
enum bna_tx_flags {
BNA_TX_F_ENET_STARTED = 1,
BNA_TX_F_ENABLED = 2,
- BNA_TX_F_PRIO_CHANGED = 4,
BNA_TX_F_BW_UPDATED = 8,
};
@@ -182,17 +181,11 @@ enum bna_rx_mod_flags {
BNA_RX_MOD_F_ENET_LOOPBACK = 2,
};
-enum bna_rxf_flags {
- BNA_RXF_F_PAUSED = 1,
-};
-
enum bna_rxf_event {
RXF_E_START = 1,
RXF_E_STOP = 2,
RXF_E_FAIL = 3,
RXF_E_CONFIG = 4,
- RXF_E_PAUSE = 5,
- RXF_E_RESUME = 6,
RXF_E_FW_RESP = 7,
};
@@ -362,9 +355,6 @@ struct bna_enet {
void (*stop_cbfn)(void *);
void *stop_cbarg;
- /* Callback for bna_enet_pause_config() */
- void (*pause_cbfn)(struct bnad *);
-
/* Callback for bna_enet_mtu_set() */
void (*mtu_cbfn)(struct bnad *);
@@ -498,9 +488,6 @@ struct bna_tx {
void (*stop_cbfn)(void *arg, struct bna_tx *tx);
void *stop_cbarg;
- /* callback for bna_tx_prio_set() */
- void (*prio_change_cbfn)(struct bnad *bnad, struct bna_tx *tx);
-
struct bfa_msgq_cmd_entry msgq_cmd;
union {
struct bfi_enet_tx_cfg_req cfg_req;
@@ -676,7 +663,6 @@ struct bna_rx_config {
enum bna_rx_type rx_type;
int num_paths;
enum bna_rxp_type rxp_type;
- int paused;
int coalescing_timeo;
/*
* Small/Large (or Header/Data) buffer size to be configured
@@ -721,7 +707,6 @@ struct bna_rxp {
/* RxF structure (hardware Rx Function) */
struct bna_rxf {
bfa_fsm_t fsm;
- enum bna_rxf_flags flags;
struct bfa_msgq_cmd_entry msgq_cmd;
union {
@@ -742,10 +727,6 @@ struct bna_rxf {
void (*stop_cbfn) (struct bna_rx *rx);
struct bna_rx *stop_cbarg;
- /* callback for bna_rx_receive_pause() / bna_rx_receive_resume() */
- void (*oper_state_cbfn) (struct bnad *bnad, struct bna_rx *rx);
- struct bnad *oper_state_cbarg;
-
/**
* callback for:
* bna_rxf_ucast_set()
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index caae6cb2bc1a..0612b19f6313 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -57,7 +57,8 @@ static u32 bnad_rxqs_per_cq = 2;
static u32 bna_id;
static struct mutex bnad_list_mutex;
static LIST_HEAD(bnad_list);
-static const u8 bnad_bcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+static const u8 bnad_bcast_addr[] __aligned(2) =
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
/*
* Local MACROS
@@ -308,7 +309,7 @@ bnad_rxq_alloc_init(struct bnad *bnad, struct bna_rcb *rcb)
}
}
- BUG_ON(((PAGE_SIZE << order) % unmap_q->map_size));
+ BUG_ON((PAGE_SIZE << order) % unmap_q->map_size);
return 0;
}
@@ -724,7 +725,6 @@ next:
cmpl->valid = 0;
BNA_QE_INDX_INC(ccb->producer_index, ccb->q_depth);
}
- cmpl = &cq[ccb->producer_index];
}
napi_gro_flush(&rx_ctrl->napi, false);
@@ -757,7 +757,7 @@ bnad_msix_rx(int irq, void *data)
struct bna_ccb *ccb = (struct bna_ccb *)data;
if (ccb) {
- ((struct bnad_rx_ctrl *)(ccb->ctrl))->rx_intr_ctr++;
+ ((struct bnad_rx_ctrl *)ccb->ctrl)->rx_intr_ctr++;
bnad_netif_rx_schedule_poll(ccb->bnad, ccb);
}
@@ -875,9 +875,9 @@ bnad_set_netdev_perm_addr(struct bnad *bnad)
{
struct net_device *netdev = bnad->netdev;
- memcpy(netdev->perm_addr, &bnad->perm_addr, netdev->addr_len);
+ ether_addr_copy(netdev->perm_addr, bnad->perm_addr);
if (is_zero_ether_addr(netdev->dev_addr))
- memcpy(netdev->dev_addr, &bnad->perm_addr, netdev->addr_len);
+ ether_addr_copy(netdev->dev_addr, bnad->perm_addr);
}
/* Control Path Handlers */
@@ -946,8 +946,7 @@ bnad_cb_ethport_link_status(struct bnad *bnad,
if (link_up) {
if (!netif_carrier_ok(bnad->netdev)) {
uint tx_id, tcb_id;
- printk(KERN_WARNING "bna: %s link up\n",
- bnad->netdev->name);
+ netdev_info(bnad->netdev, "link up\n");
netif_carrier_on(bnad->netdev);
BNAD_UPDATE_CTR(bnad, link_toggle);
for (tx_id = 0; tx_id < bnad->num_tx; tx_id++) {
@@ -966,10 +965,6 @@ bnad_cb_ethport_link_status(struct bnad *bnad,
/*
* Force an immediate
* Transmit Schedule */
- printk(KERN_INFO "bna: %s %d "
- "TXQ_STARTED\n",
- bnad->netdev->name,
- txq_id);
netif_wake_subqueue(
bnad->netdev,
txq_id);
@@ -987,8 +982,7 @@ bnad_cb_ethport_link_status(struct bnad *bnad,
}
} else {
if (netif_carrier_ok(bnad->netdev)) {
- printk(KERN_WARNING "bna: %s link down\n",
- bnad->netdev->name);
+ netdev_info(bnad->netdev, "link down\n");
netif_carrier_off(bnad->netdev);
BNAD_UPDATE_CTR(bnad, link_toggle);
}
@@ -1058,8 +1052,6 @@ bnad_cb_tx_stall(struct bnad *bnad, struct bna_tx *tx)
txq_id = tcb->id;
clear_bit(BNAD_TXQ_TX_STARTED, &tcb->flags);
netif_stop_subqueue(bnad->netdev, txq_id);
- printk(KERN_INFO "bna: %s %d TXQ_STOPPED\n",
- bnad->netdev->name, txq_id);
}
}
@@ -1082,8 +1074,6 @@ bnad_cb_tx_resume(struct bnad *bnad, struct bna_tx *tx)
BUG_ON(*(tcb->hw_consumer_index) != 0);
if (netif_carrier_ok(bnad->netdev)) {
- printk(KERN_INFO "bna: %s %d TXQ_STARTED\n",
- bnad->netdev->name, txq_id);
netif_wake_subqueue(bnad->netdev, txq_id);
BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
}
@@ -1094,8 +1084,8 @@ bnad_cb_tx_resume(struct bnad *bnad, struct bna_tx *tx)
* get a 0 MAC address. We try to get the MAC address
* again here.
*/
- if (is_zero_ether_addr(&bnad->perm_addr.mac[0])) {
- bna_enet_perm_mac_get(&bnad->bna.enet, &bnad->perm_addr);
+ if (is_zero_ether_addr(bnad->perm_addr)) {
+ bna_enet_perm_mac_get(&bnad->bna.enet, bnad->perm_addr);
bnad_set_netdev_perm_addr(bnad);
}
}
@@ -1703,7 +1693,7 @@ bnad_ioc_timeout(unsigned long data)
unsigned long flags;
spin_lock_irqsave(&bnad->bna_lock, flags);
- bfa_nw_ioc_timeout((void *) &bnad->bna.ioceth.ioc);
+ bfa_nw_ioc_timeout(&bnad->bna.ioceth.ioc);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
@@ -1714,7 +1704,7 @@ bnad_ioc_hb_check(unsigned long data)
unsigned long flags;
spin_lock_irqsave(&bnad->bna_lock, flags);
- bfa_nw_ioc_hb_check((void *) &bnad->bna.ioceth.ioc);
+ bfa_nw_ioc_hb_check(&bnad->bna.ioceth.ioc);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
@@ -1725,7 +1715,7 @@ bnad_iocpf_timeout(unsigned long data)
unsigned long flags;
spin_lock_irqsave(&bnad->bna_lock, flags);
- bfa_nw_iocpf_timeout((void *) &bnad->bna.ioceth.ioc);
+ bfa_nw_iocpf_timeout(&bnad->bna.ioceth.ioc);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
@@ -1736,7 +1726,7 @@ bnad_iocpf_sem_timeout(unsigned long data)
unsigned long flags;
spin_lock_irqsave(&bnad->bna_lock, flags);
- bfa_nw_iocpf_sem_timeout((void *) &bnad->bna.ioceth.ioc);
+ bfa_nw_iocpf_sem_timeout(&bnad->bna.ioceth.ioc);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
@@ -1862,8 +1852,7 @@ bnad_netdev_mc_list_get(struct net_device *netdev, u8 *mc_list)
struct netdev_hw_addr *mc_addr;
netdev_for_each_mc_addr(mc_addr, netdev) {
- memcpy(&mc_list[i * ETH_ALEN], &mc_addr->addr[0],
- ETH_ALEN);
+ ether_addr_copy(&mc_list[i * ETH_ALEN], &mc_addr->addr[0]);
i++;
}
}
@@ -2137,7 +2126,7 @@ bnad_reinit_rx(struct bnad *bnad)
current_err = bnad_setup_rx(bnad, rx_id);
if (current_err && !err) {
err = current_err;
- pr_err("RXQ:%u setup failed\n", rx_id);
+ netdev_err(netdev, "RXQ:%u setup failed\n", rx_id);
}
}
@@ -2338,7 +2327,7 @@ bnad_rx_coalescing_timeo_set(struct bnad *bnad)
* Called with bnad->bna_lock held
*/
int
-bnad_mac_addr_set_locked(struct bnad *bnad, u8 *mac_addr)
+bnad_mac_addr_set_locked(struct bnad *bnad, const u8 *mac_addr)
{
int ret;
@@ -2349,7 +2338,7 @@ bnad_mac_addr_set_locked(struct bnad *bnad, u8 *mac_addr)
if (!bnad->rx_info[0].rx)
return 0;
- ret = bna_rx_ucast_set(bnad->rx_info[0].rx, mac_addr, NULL);
+ ret = bna_rx_ucast_set(bnad->rx_info[0].rx, mac_addr);
if (ret != BNA_CB_SUCCESS)
return -EADDRNOTAVAIL;
@@ -2367,8 +2356,8 @@ bnad_enable_default_bcast(struct bnad *bnad)
init_completion(&bnad->bnad_completions.mcast_comp);
spin_lock_irqsave(&bnad->bna_lock, flags);
- ret = bna_rx_mcast_add(rx_info->rx, (u8 *)bnad_bcast_addr,
- bnad_cb_rx_mcast_add);
+ ret = bna_rx_mcast_add(rx_info->rx, bnad_bcast_addr,
+ bnad_cb_rx_mcast_add);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
if (ret == BNA_CB_SUCCESS)
@@ -2673,8 +2662,9 @@ bnad_enable_msix(struct bnad *bnad)
if (ret < 0) {
goto intx_mode;
} else if (ret < bnad->msix_num) {
- pr_warn("BNA: %d MSI-X vectors allocated < %d requested\n",
- ret, bnad->msix_num);
+ dev_warn(&bnad->pcidev->dev,
+ "%d MSI-X vectors allocated < %d requested\n",
+ ret, bnad->msix_num);
spin_lock_irqsave(&bnad->bna_lock, flags);
/* ret = #of vectors that we got */
@@ -2696,7 +2686,8 @@ bnad_enable_msix(struct bnad *bnad)
return;
intx_mode:
- pr_warn("BNA: MSI-X enable failed - operating in INTx mode\n");
+ dev_warn(&bnad->pcidev->dev,
+ "MSI-X enable failed - operating in INTx mode\n");
kfree(bnad->msix_table);
bnad->msix_table = NULL;
@@ -2754,7 +2745,7 @@ bnad_open(struct net_device *netdev)
spin_lock_irqsave(&bnad->bna_lock, flags);
bna_enet_mtu_set(&bnad->bna.enet,
BNAD_FRAME_SIZE(bnad->netdev->mtu), NULL);
- bna_enet_pause_config(&bnad->bna.enet, &pause_config, NULL);
+ bna_enet_pause_config(&bnad->bna.enet, &pause_config);
bna_enet_enable(&bnad->bna.enet);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
@@ -3128,7 +3119,7 @@ bnad_set_rx_ucast_fltr(struct bnad *bnad)
int entry;
if (netdev_uc_empty(bnad->netdev)) {
- bna_rx_ucast_listset(bnad->rx_info[0].rx, 0, NULL, NULL);
+ bna_rx_ucast_listset(bnad->rx_info[0].rx, 0, NULL);
return;
}
@@ -3141,13 +3132,11 @@ bnad_set_rx_ucast_fltr(struct bnad *bnad)
entry = 0;
netdev_for_each_uc_addr(ha, netdev) {
- memcpy(&mac_list[entry * ETH_ALEN],
- &ha->addr[0], ETH_ALEN);
+ ether_addr_copy(&mac_list[entry * ETH_ALEN], &ha->addr[0]);
entry++;
}
- ret = bna_rx_ucast_listset(bnad->rx_info[0].rx, entry,
- mac_list, NULL);
+ ret = bna_rx_ucast_listset(bnad->rx_info[0].rx, entry, mac_list);
kfree(mac_list);
if (ret != BNA_CB_SUCCESS)
@@ -3158,7 +3147,7 @@ bnad_set_rx_ucast_fltr(struct bnad *bnad)
/* ucast packets not in UCAM are routed to default function */
mode_default:
bnad->cfg_flags |= BNAD_CF_DEFAULT;
- bna_rx_ucast_listset(bnad->rx_info[0].rx, 0, NULL, NULL);
+ bna_rx_ucast_listset(bnad->rx_info[0].rx, 0, NULL);
}
static void
@@ -3183,12 +3172,11 @@ bnad_set_rx_mcast_fltr(struct bnad *bnad)
if (mac_list == NULL)
goto mode_allmulti;
- memcpy(&mac_list[0], &bnad_bcast_addr[0], ETH_ALEN);
+ ether_addr_copy(&mac_list[0], &bnad_bcast_addr[0]);
/* copy rest of the MCAST addresses */
bnad_netdev_mc_list_get(netdev, mac_list);
- ret = bna_rx_mcast_listset(bnad->rx_info[0].rx, mc_count + 1,
- mac_list, NULL);
+ ret = bna_rx_mcast_listset(bnad->rx_info[0].rx, mc_count + 1, mac_list);
kfree(mac_list);
if (ret != BNA_CB_SUCCESS)
@@ -3198,7 +3186,7 @@ bnad_set_rx_mcast_fltr(struct bnad *bnad)
mode_allmulti:
bnad->cfg_flags |= BNAD_CF_ALLMULTI;
- bna_rx_mcast_delall(bnad->rx_info[0].rx, NULL);
+ bna_rx_mcast_delall(bnad->rx_info[0].rx);
}
void
@@ -3237,7 +3225,7 @@ bnad_set_rx_mode(struct net_device *netdev)
mode_mask = BNA_RXMODE_PROMISC | BNA_RXMODE_DEFAULT |
BNA_RXMODE_ALLMULTI;
- bna_rx_mode_set(bnad->rx_info[0].rx, new_mode, mode_mask, NULL);
+ bna_rx_mode_set(bnad->rx_info[0].rx, new_mode, mode_mask);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
@@ -3248,19 +3236,18 @@ bnad_set_rx_mode(struct net_device *netdev)
* in a non-blocking context.
*/
static int
-bnad_set_mac_address(struct net_device *netdev, void *mac_addr)
+bnad_set_mac_address(struct net_device *netdev, void *addr)
{
int err;
struct bnad *bnad = netdev_priv(netdev);
- struct sockaddr *sa = (struct sockaddr *)mac_addr;
+ struct sockaddr *sa = (struct sockaddr *)addr;
unsigned long flags;
spin_lock_irqsave(&bnad->bna_lock, flags);
err = bnad_mac_addr_set_locked(bnad, sa->sa_data);
-
if (!err)
- memcpy(netdev->dev_addr, sa->sa_data, netdev->addr_len);
+ ether_addr_copy(netdev->dev_addr, sa->sa_data);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
@@ -3487,8 +3474,8 @@ bnad_init(struct bnad *bnad,
dev_err(&pdev->dev, "ioremap for bar0 failed\n");
return -ENOMEM;
}
- pr_info("bar0 mapped to %p, len %llu\n", bnad->bar0,
- (unsigned long long) bnad->mmio_len);
+ dev_info(&pdev->dev, "bar0 mapped to %p, len %llu\n", bnad->bar0,
+ (unsigned long long) bnad->mmio_len);
spin_lock_irqsave(&bnad->bna_lock, flags);
if (!bnad_msix_disable)
@@ -3609,13 +3596,10 @@ bnad_pci_probe(struct pci_dev *pdev,
struct bfa_pcidev pcidev_info;
unsigned long flags;
- pr_info("bnad_pci_probe : (0x%p, 0x%p) PCI Func : (%d)\n",
- pdev, pcidev_id, PCI_FUNC(pdev->devfn));
-
mutex_lock(&bnad_fwimg_mutex);
if (!cna_get_firmware_buf(pdev)) {
mutex_unlock(&bnad_fwimg_mutex);
- pr_warn("Failed to load Firmware Image!\n");
+ dev_err(&pdev->dev, "failed to load firmware image!\n");
return -ENODEV;
}
mutex_unlock(&bnad_fwimg_mutex);
@@ -3693,13 +3677,13 @@ bnad_pci_probe(struct pci_dev *pdev,
/* Set up timers */
setup_timer(&bnad->bna.ioceth.ioc.ioc_timer, bnad_ioc_timeout,
- ((unsigned long)bnad));
+ (unsigned long)bnad);
setup_timer(&bnad->bna.ioceth.ioc.hb_timer, bnad_ioc_hb_check,
- ((unsigned long)bnad));
+ (unsigned long)bnad);
setup_timer(&bnad->bna.ioceth.ioc.iocpf_timer, bnad_iocpf_timeout,
- ((unsigned long)bnad));
+ (unsigned long)bnad);
setup_timer(&bnad->bna.ioceth.ioc.sem_timer, bnad_iocpf_sem_timeout,
- ((unsigned long)bnad));
+ (unsigned long)bnad);
/*
* Start the chip
@@ -3708,8 +3692,7 @@ bnad_pci_probe(struct pci_dev *pdev,
*/
err = bnad_ioceth_enable(bnad);
if (err) {
- pr_err("BNA: Initialization failed err=%d\n",
- err);
+ dev_err(&pdev->dev, "initialization failed err=%d\n", err);
goto probe_success;
}
@@ -3742,7 +3725,7 @@ bnad_pci_probe(struct pci_dev *pdev,
/* Get the burnt-in mac */
spin_lock_irqsave(&bnad->bna_lock, flags);
- bna_enet_perm_mac_get(&bna->enet, &bnad->perm_addr);
+ bna_enet_perm_mac_get(&bna->enet, bnad->perm_addr);
bnad_set_netdev_perm_addr(bnad);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
@@ -3751,7 +3734,7 @@ bnad_pci_probe(struct pci_dev *pdev,
/* Finally, reguister with net_device layer */
err = register_netdev(netdev);
if (err) {
- pr_err("BNA : Registering with netdev failed\n");
+ dev_err(&pdev->dev, "registering net device failed\n");
goto probe_uninit;
}
set_bit(BNAD_RF_NETDEV_REGISTERED, &bnad->run_flags);
@@ -3803,7 +3786,6 @@ bnad_pci_remove(struct pci_dev *pdev)
if (!netdev)
return;
- pr_info("%s bnad_pci_remove\n", netdev->name);
bnad = netdev_priv(netdev);
bna = &bnad->bna;
@@ -3864,15 +3846,14 @@ bnad_module_init(void)
{
int err;
- pr_info("QLogic BR-series 10G Ethernet driver - version: %s\n",
- BNAD_VERSION);
+ pr_info("bna: QLogic BR-series 10G Ethernet driver - version: %s\n",
+ BNAD_VERSION);
bfa_nw_ioc_auto_recover(bnad_ioc_auto_recover);
err = pci_register_driver(&bnad_pci_driver);
if (err < 0) {
- pr_err("bna : PCI registration failed in module init "
- "(%d)\n", err);
+ pr_err("bna: PCI driver registration failed err=%d\n", err);
return err;
}
diff --git a/drivers/net/ethernet/brocade/bna/bnad.h b/drivers/net/ethernet/brocade/bna/bnad.h
index 7ead6c23edb6..faedbf24777e 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.h
+++ b/drivers/net/ethernet/brocade/bna/bnad.h
@@ -344,7 +344,7 @@ struct bnad {
struct bnad_completion bnad_completions;
/* Burnt in MAC address */
- mac_t perm_addr;
+ u8 perm_addr[ETH_ALEN];
struct workqueue_struct *work_q;
@@ -385,7 +385,7 @@ u32 *cna_get_firmware_buf(struct pci_dev *pdev);
/* Netdev entry point prototypes */
void bnad_set_rx_mode(struct net_device *netdev);
struct net_device_stats *bnad_get_netdev_stats(struct net_device *netdev);
-int bnad_mac_addr_set_locked(struct bnad *bnad, u8 *mac_addr);
+int bnad_mac_addr_set_locked(struct bnad *bnad, const u8 *mac_addr);
int bnad_enable_default_bcast(struct bnad *bnad);
void bnad_restore_vlans(struct bnad *bnad, u32 rx_id);
void bnad_set_ethtool_ops(struct net_device *netdev);
diff --git a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
index 72c89550417c..8fc246ea1fb8 100644
--- a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
+++ b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
@@ -76,8 +76,7 @@ bnad_debugfs_open_fwtrc(struct inode *inode, struct file *file)
fw_debug->debug_buffer = NULL;
kfree(fw_debug);
fw_debug = NULL;
- pr_warn("bnad %s: Failed to collect fwtrc\n",
- pci_name(bnad->pcidev));
+ netdev_warn(bnad->netdev, "failed to collect fwtrc\n");
return -ENOMEM;
}
@@ -117,8 +116,7 @@ bnad_debugfs_open_fwsave(struct inode *inode, struct file *file)
fw_debug->debug_buffer = NULL;
kfree(fw_debug);
fw_debug = NULL;
- pr_warn("bna %s: Failed to collect fwsave\n",
- pci_name(bnad->pcidev));
+ netdev_warn(bnad->netdev, "failed to collect fwsave\n");
return -ENOMEM;
}
@@ -217,8 +215,7 @@ bnad_debugfs_open_drvinfo(struct inode *inode, struct file *file)
drv_info->debug_buffer = NULL;
kfree(drv_info);
drv_info = NULL;
- pr_warn("bna %s: Failed to collect drvinfo\n",
- pci_name(bnad->pcidev));
+ netdev_warn(bnad->netdev, "failed to collect drvinfo\n");
return -ENOMEM;
}
@@ -271,15 +268,15 @@ bna_reg_offset_check(struct bfa_ioc *ioc, u32 offset, u32 len)
area = (offset >> 15) & 0x7;
if (area == 0) {
/* PCIe core register */
- if ((offset + (len<<2)) > 0x8000) /* 8k dwords or 32KB */
+ if (offset + (len << 2) > 0x8000) /* 8k dwords or 32KB */
return BFA_STATUS_EINVAL;
} else if (area == 0x1) {
/* CB 32 KB memory page */
- if ((offset + (len<<2)) > 0x10000) /* 8k dwords or 32KB */
+ if (offset + (len << 2) > 0x10000) /* 8k dwords or 32KB */
return BFA_STATUS_EINVAL;
} else {
/* CB register space 64KB */
- if ((offset + (len<<2)) > BFA_REG_ADDRMSK(ioc))
+ if (offset + (len << 2) > BFA_REG_ADDRMSK(ioc))
return BFA_STATUS_EINVAL;
}
return BFA_STATUS_OK;
@@ -321,27 +318,20 @@ bnad_debugfs_write_regrd(struct file *file, const char __user *buf,
unsigned long flags;
void *kern_buf;
- /* Allocate memory to store the user space buf */
- kern_buf = kzalloc(nbytes, GFP_KERNEL);
- if (!kern_buf)
- return -ENOMEM;
-
- if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
- kfree(kern_buf);
- return -ENOMEM;
- }
+ /* Copy the user space buf */
+ kern_buf = memdup_user(buf, nbytes);
+ if (IS_ERR(kern_buf))
+ return PTR_ERR(kern_buf);
rc = sscanf(kern_buf, "%x:%x", &addr, &len);
if (rc < 2) {
- pr_warn("bna %s: Failed to read user buffer\n",
- pci_name(bnad->pcidev));
+ netdev_warn(bnad->netdev, "failed to read user buffer\n");
kfree(kern_buf);
return -EINVAL;
}
kfree(kern_buf);
kfree(bnad->regdata);
- bnad->regdata = NULL;
bnad->reglen = 0;
bnad->regdata = kzalloc(len << 2, GFP_KERNEL);
@@ -355,8 +345,7 @@ bnad_debugfs_write_regrd(struct file *file, const char __user *buf,
/* offset and len sanity check */
rc = bna_reg_offset_check(ioc, addr, len);
if (rc) {
- pr_warn("bna %s: Failed reg offset check\n",
- pci_name(bnad->pcidev));
+ netdev_warn(bnad->netdev, "failed reg offset check\n");
kfree(bnad->regdata);
bnad->regdata = NULL;
bnad->reglen = 0;
@@ -388,20 +377,14 @@ bnad_debugfs_write_regwr(struct file *file, const char __user *buf,
unsigned long flags;
void *kern_buf;
- /* Allocate memory to store the user space buf */
- kern_buf = kzalloc(nbytes, GFP_KERNEL);
- if (!kern_buf)
- return -ENOMEM;
-
- if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
- kfree(kern_buf);
- return -ENOMEM;
- }
+ /* Copy the user space buf */
+ kern_buf = memdup_user(buf, nbytes);
+ if (IS_ERR(kern_buf))
+ return PTR_ERR(kern_buf);
rc = sscanf(kern_buf, "%x:%x", &addr, &val);
if (rc < 2) {
- pr_warn("bna %s: Failed to read user buffer\n",
- pci_name(bnad->pcidev));
+ netdev_warn(bnad->netdev, "failed to read user buffer\n");
kfree(kern_buf);
return -EINVAL;
}
@@ -412,8 +395,7 @@ bnad_debugfs_write_regwr(struct file *file, const char __user *buf,
/* offset and len sanity check */
rc = bna_reg_offset_check(ioc, addr, 1);
if (rc) {
- pr_warn("bna %s: Failed reg offset check\n",
- pci_name(bnad->pcidev));
+ netdev_warn(bnad->netdev, "failed reg offset check\n");
return -EINVAL;
}
@@ -525,7 +507,8 @@ bnad_debugfs_init(struct bnad *bnad)
bna_debugfs_root = debugfs_create_dir("bna", NULL);
atomic_set(&bna_debugfs_port_count, 0);
if (!bna_debugfs_root) {
- pr_warn("BNA: debugfs root dir creation failed\n");
+ netdev_warn(bnad->netdev,
+ "debugfs root dir creation failed\n");
return;
}
}
@@ -536,8 +519,8 @@ bnad_debugfs_init(struct bnad *bnad)
bnad->port_debugfs_root =
debugfs_create_dir(name, bna_debugfs_root);
if (!bnad->port_debugfs_root) {
- pr_warn("bna pci_dev %s: root dir creation failed\n",
- pci_name(bnad->pcidev));
+ netdev_warn(bnad->netdev,
+ "debugfs root dir creation failed\n");
return;
}
@@ -552,9 +535,9 @@ bnad_debugfs_init(struct bnad *bnad)
bnad,
file->fops);
if (!bnad->bnad_dentry_files[i]) {
- pr_warn(
- "BNA pci_dev:%s: create %s entry failed\n",
- pci_name(bnad->pcidev), file->name);
+ netdev_warn(bnad->netdev,
+ "create %s entry failed\n",
+ file->name);
return;
}
}
diff --git a/drivers/net/ethernet/brocade/bna/bnad_ethtool.c b/drivers/net/ethernet/brocade/bna/bnad_ethtool.c
index 12f344debd1c..2bdfc5dff4b1 100644
--- a/drivers/net/ethernet/brocade/bna/bnad_ethtool.c
+++ b/drivers/net/ethernet/brocade/bna/bnad_ethtool.c
@@ -445,13 +445,13 @@ bnad_set_ringparam(struct net_device *netdev,
if (ringparam->rx_pending < BNAD_MIN_Q_DEPTH ||
ringparam->rx_pending > BNAD_MAX_RXQ_DEPTH ||
- !BNA_POWER_OF_2(ringparam->rx_pending)) {
+ !is_power_of_2(ringparam->rx_pending)) {
mutex_unlock(&bnad->conf_mutex);
return -EINVAL;
}
if (ringparam->tx_pending < BNAD_MIN_Q_DEPTH ||
ringparam->tx_pending > BNAD_MAX_TXQ_DEPTH ||
- !BNA_POWER_OF_2(ringparam->tx_pending)) {
+ !is_power_of_2(ringparam->tx_pending)) {
mutex_unlock(&bnad->conf_mutex);
return -EINVAL;
}
@@ -533,7 +533,7 @@ bnad_set_pauseparam(struct net_device *netdev,
pause_config.rx_pause = pauseparam->rx_pause;
pause_config.tx_pause = pauseparam->tx_pause;
spin_lock_irqsave(&bnad->bna_lock, flags);
- bna_enet_pause_config(&bnad->bna.enet, &pause_config, NULL);
+ bna_enet_pause_config(&bnad->bna.enet, &pause_config);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
mutex_unlock(&bnad->conf_mutex);
@@ -1080,7 +1080,7 @@ bnad_flash_device(struct net_device *netdev, struct ethtool_flash *eflash)
ret = request_firmware(&fw, eflash->data, &bnad->pcidev->dev);
if (ret) {
- pr_err("BNA: Can't locate firmware %s\n", eflash->data);
+ netdev_err(netdev, "can't load firmware %s\n", eflash->data);
goto out;
}
@@ -1093,7 +1093,7 @@ bnad_flash_device(struct net_device *netdev, struct ethtool_flash *eflash)
bnad->id, (u8 *)fw->data, fw->size, 0,
bnad_cb_completion, &fcomp);
if (ret != BFA_STATUS_OK) {
- pr_warn("BNA: Flash update failed with err: %d\n", ret);
+ netdev_warn(netdev, "flash update failed with err=%d\n", ret);
ret = -EIO;
spin_unlock_irq(&bnad->bna_lock);
goto out;
@@ -1103,8 +1103,9 @@ bnad_flash_device(struct net_device *netdev, struct ethtool_flash *eflash)
wait_for_completion(&fcomp.comp);
if (fcomp.comp_status != BFA_STATUS_OK) {
ret = -EIO;
- pr_warn("BNA: Firmware image update to flash failed with: %d\n",
- fcomp.comp_status);
+ netdev_warn(netdev,
+ "firmware image update failed with err=%d\n",
+ fcomp.comp_status);
}
out:
release_firmware(fw);
diff --git a/drivers/net/ethernet/brocade/bna/cna.h b/drivers/net/ethernet/brocade/bna/cna.h
index 28e7d0ffeab1..75f8f1ac9fb7 100644
--- a/drivers/net/ethernet/brocade/bna/cna.h
+++ b/drivers/net/ethernet/brocade/bna/cna.h
@@ -42,66 +42,4 @@ extern char bfa_version[];
#define CNA_FW_FILE_CT2 "ct2fw-3.2.5.1.bin"
#define FC_SYMNAME_MAX 256 /*!< max name server symbolic name size */
-#pragma pack(1)
-
-typedef struct mac { u8 mac[ETH_ALEN]; } mac_t;
-
-#pragma pack()
-
-#define bfa_q_first(_q) ((void *)(((struct list_head *) (_q))->next))
-#define bfa_q_next(_qe) (((struct list_head *) (_qe))->next)
-#define bfa_q_prev(_qe) (((struct list_head *) (_qe))->prev)
-
-/*
- * bfa_q_qe_init - to initialize a queue element
- */
-#define bfa_q_qe_init(_qe) { \
- bfa_q_next(_qe) = (struct list_head *) NULL; \
- bfa_q_prev(_qe) = (struct list_head *) NULL; \
-}
-
-/*
- * bfa_q_deq - dequeue an element from head of the queue
- */
-#define bfa_q_deq(_q, _qe) { \
- if (!list_empty(_q)) { \
- (*((struct list_head **) (_qe))) = bfa_q_next(_q); \
- bfa_q_prev(bfa_q_next(*((struct list_head **) _qe))) = \
- (struct list_head *) (_q); \
- bfa_q_next(_q) = bfa_q_next(*((struct list_head **) _qe)); \
- bfa_q_qe_init(*((struct list_head **) _qe)); \
- } else { \
- *((struct list_head **)(_qe)) = NULL; \
- } \
-}
-
-/*
- * bfa_q_deq_tail - dequeue an element from tail of the queue
- */
-#define bfa_q_deq_tail(_q, _qe) { \
- if (!list_empty(_q)) { \
- *((struct list_head **) (_qe)) = bfa_q_prev(_q); \
- bfa_q_next(bfa_q_prev(*((struct list_head **) _qe))) = \
- (struct list_head *) (_q); \
- bfa_q_prev(_q) = bfa_q_prev(*(struct list_head **) _qe);\
- bfa_q_qe_init(*((struct list_head **) _qe)); \
- } else { \
- *((struct list_head **) (_qe)) = (struct list_head *) NULL; \
- } \
-}
-
-/*
- * bfa_add_tail_head - enqueue an element at the head of queue
- */
-#define bfa_q_enq_head(_q, _qe) { \
- if (!(bfa_q_next(_qe) == NULL) && (bfa_q_prev(_qe) == NULL)) \
- pr_err("Assertion failure: %s:%d: %d", \
- __FILE__, __LINE__, \
- (bfa_q_next(_qe) == NULL) && (bfa_q_prev(_qe) == NULL));\
- bfa_q_next(_qe) = bfa_q_next(_q); \
- bfa_q_prev(_qe) = (struct list_head *) (_q); \
- bfa_q_prev(bfa_q_next(_q)) = (struct list_head *) (_qe); \
- bfa_q_next(_q) = (struct list_head *) (_qe); \
-}
-
#endif /* __CNA_H__ */
diff --git a/drivers/net/ethernet/brocade/bna/cna_fwimg.c b/drivers/net/ethernet/brocade/bna/cna_fwimg.c
index badea368bdc8..2e7fb97883dc 100644
--- a/drivers/net/ethernet/brocade/bna/cna_fwimg.c
+++ b/drivers/net/ethernet/brocade/bna/cna_fwimg.c
@@ -33,7 +33,7 @@ cna_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
u32 n;
if (request_firmware(&fw, fw_name, &pdev->dev)) {
- pr_alert("Can't locate firmware %s\n", fw_name);
+ dev_alert(&pdev->dev, "can't load firmware %s\n", fw_name);
goto error;
}
diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig
index 1ba3e3a67389..f0bcb15d3fec 100644
--- a/drivers/net/ethernet/cadence/Kconfig
+++ b/drivers/net/ethernet/cadence/Kconfig
@@ -8,8 +8,6 @@ config NET_CADENCE
default y
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
- Make sure you know the name of your card. Read the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
If unsure, say Y.
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index fc646a41d548..caeb39561567 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -54,6 +54,8 @@
#define MACB_MAX_TX_LEN ((unsigned int)((1 << MACB_TX_FRMLEN_SIZE) - 1))
#define GEM_MAX_TX_LEN ((unsigned int)((1 << GEM_TX_FRMLEN_SIZE) - 1))
+#define GEM_MTU_MIN_SIZE 68
+
/*
* Graceful stop timeouts in us. We should allow up to
* 1 frame time (10 Mbits/s, full-duplex, ignoring collisions)
@@ -785,7 +787,7 @@ static int gem_rx(struct macb *bp, int budget)
}
/* now everything is ready for receiving packet */
bp->rx_skbuff[entry] = NULL;
- len = MACB_BFEXT(RX_FRMLEN, ctrl);
+ len = ctrl & bp->rx_frm_len_mask;
netdev_vdbg(bp->dev, "gem_rx %u (len %u)\n", entry, len);
@@ -831,7 +833,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
struct macb_dma_desc *desc;
desc = macb_rx_desc(bp, last_frag);
- len = MACB_BFEXT(RX_FRMLEN, desc->ctrl);
+ len = desc->ctrl & bp->rx_frm_len_mask;
netdev_vdbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n",
macb_rx_ring_wrap(first_frag),
@@ -1651,7 +1653,10 @@ static void macb_init_hw(struct macb *bp)
config |= MACB_BF(RBOF, NET_IP_ALIGN); /* Make eth data aligned */
config |= MACB_BIT(PAE); /* PAuse Enable */
config |= MACB_BIT(DRFCS); /* Discard Rx FCS */
- config |= MACB_BIT(BIG); /* Receive oversized frames */
+ if (bp->caps & MACB_CAPS_JUMBO)
+ config |= MACB_BIT(JFRAME); /* Enable jumbo frames */
+ else
+ config |= MACB_BIT(BIG); /* Receive oversized frames */
if (bp->dev->flags & IFF_PROMISC)
config |= MACB_BIT(CAF); /* Copy All Frames */
else if (macb_is_gem(bp) && bp->dev->features & NETIF_F_RXCSUM)
@@ -1660,8 +1665,13 @@ static void macb_init_hw(struct macb *bp)
config |= MACB_BIT(NBC); /* No BroadCast */
config |= macb_dbw(bp);
macb_writel(bp, NCFGR, config);
+ if ((bp->caps & MACB_CAPS_JUMBO) && bp->jumbo_max_len)
+ gem_writel(bp, JML, bp->jumbo_max_len);
bp->speed = SPEED_10;
bp->duplex = DUPLEX_HALF;
+ bp->rx_frm_len_mask = MACB_RX_FRMLEN_MASK;
+ if (bp->caps & MACB_CAPS_JUMBO)
+ bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK;
macb_configure_dma(bp);
@@ -1865,6 +1875,26 @@ static int macb_close(struct net_device *dev)
return 0;
}
+static int macb_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct macb *bp = netdev_priv(dev);
+ u32 max_mtu;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ max_mtu = ETH_DATA_LEN;
+ if (bp->caps & MACB_CAPS_JUMBO)
+ max_mtu = gem_readl(bp, JML) - ETH_HLEN - ETH_FCS_LEN;
+
+ if ((new_mtu > max_mtu) || (new_mtu < GEM_MTU_MIN_SIZE))
+ return -EINVAL;
+
+ dev->mtu = new_mtu;
+
+ return 0;
+}
+
static void gem_update_stats(struct macb *bp)
{
int i;
@@ -2141,7 +2171,7 @@ static const struct net_device_ops macb_netdev_ops = {
.ndo_get_stats = macb_get_stats,
.ndo_do_ioctl = macb_ioctl,
.ndo_validate_addr = eth_validate_addr,
- .ndo_change_mtu = eth_change_mtu,
+ .ndo_change_mtu = macb_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = macb_poll_controller,
@@ -2683,6 +2713,13 @@ static const struct macb_config pc302gem_config = {
.init = macb_init,
};
+static const struct macb_config sama5d2_config = {
+ .caps = 0,
+ .dma_burst_length = 16,
+ .clk_init = macb_clk_init,
+ .init = macb_init,
+};
+
static const struct macb_config sama5d3_config = {
.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
.dma_burst_length = 16,
@@ -2702,6 +2739,16 @@ static const struct macb_config emac_config = {
.init = at91ether_init,
};
+
+static const struct macb_config zynqmp_config = {
+ .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE |
+ MACB_CAPS_JUMBO,
+ .dma_burst_length = 16,
+ .clk_init = macb_clk_init,
+ .init = macb_init,
+ .jumbo_max_len = 10240,
+};
+
static const struct macb_config zynq_config = {
.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE |
MACB_CAPS_NO_GIGABIT_HALF,
@@ -2716,10 +2763,12 @@ static const struct of_device_id macb_dt_ids[] = {
{ .compatible = "cdns,macb" },
{ .compatible = "cdns,pc302-gem", .data = &pc302gem_config },
{ .compatible = "cdns,gem", .data = &pc302gem_config },
+ { .compatible = "atmel,sama5d2-gem", .data = &sama5d2_config },
{ .compatible = "atmel,sama5d3-gem", .data = &sama5d3_config },
{ .compatible = "atmel,sama5d4-gem", .data = &sama5d4_config },
{ .compatible = "cdns,at91rm9200-emac", .data = &emac_config },
{ .compatible = "cdns,emac", .data = &emac_config },
+ { .compatible = "cdns,zynqmp-gem", .data = &zynqmp_config},
{ .compatible = "cdns,zynq-gem", .data = &zynq_config },
{ /* sentinel */ }
};
@@ -2789,6 +2838,10 @@ static int macb_probe(struct platform_device *pdev)
bp->pclk = pclk;
bp->hclk = hclk;
bp->tx_clk = tx_clk;
+ if (macb_config->jumbo_max_len) {
+ bp->jumbo_max_len = macb_config->jumbo_max_len;
+ }
+
spin_lock_init(&bp->lock);
/* setup capabilities */
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 24b1d9bcd865..d74655993d4b 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -71,6 +71,7 @@
#define GEM_NCFGR 0x0004 /* Network Config */
#define GEM_USRIO 0x000c /* User IO */
#define GEM_DMACFG 0x0010 /* DMA Configuration */
+#define GEM_JML 0x0048 /* Jumbo Max Length */
#define GEM_HRB 0x0080 /* Hash Bottom */
#define GEM_HRT 0x0084 /* Hash Top */
#define GEM_SA1B 0x0088 /* Specific1 Bottom */
@@ -398,6 +399,7 @@
#define MACB_CAPS_GIGABIT_MODE_AVAILABLE 0x20000000
#define MACB_CAPS_SG_DISABLED 0x40000000
#define MACB_CAPS_MACB_IS_GEM 0x80000000
+#define MACB_CAPS_JUMBO 0x00000008
/* Bit manipulation macros */
#define MACB_BIT(name) \
@@ -515,6 +517,9 @@ struct macb_dma_desc {
#define MACB_RX_BROADCAST_OFFSET 31
#define MACB_RX_BROADCAST_SIZE 1
+#define MACB_RX_FRMLEN_MASK 0xFFF
+#define MACB_RX_JFRMLEN_MASK 0x3FFF
+
/* RX checksum offload disabled: bit 24 clear in NCFGR */
#define GEM_RX_TYPEID_MATCH_OFFSET 22
#define GEM_RX_TYPEID_MATCH_SIZE 2
@@ -758,6 +763,7 @@ struct macb_config {
int (*clk_init)(struct platform_device *pdev, struct clk **pclk,
struct clk **hclk, struct clk **tx_clk);
int (*init)(struct platform_device *pdev);
+ int jumbo_max_len;
};
struct macb_queue {
@@ -827,6 +833,9 @@ struct macb {
unsigned int max_tx_length;
u64 ethtool_stats[GEM_STATS_LEN];
+
+ unsigned int rx_frm_len_mask;
+ unsigned int jumbo_max_len;
};
static inline bool macb_is_gem(struct macb *bp)
diff --git a/drivers/net/ethernet/cavium/Kconfig b/drivers/net/ethernet/cavium/Kconfig
new file mode 100644
index 000000000000..c4d6bbe9458d
--- /dev/null
+++ b/drivers/net/ethernet/cavium/Kconfig
@@ -0,0 +1,57 @@
+#
+# Cavium ethernet device configuration
+#
+
+config NET_VENDOR_CAVIUM
+ tristate "Cavium ethernet drivers"
+ depends on PCI
+ default y
+ ---help---
+ Select this option if you want enable Cavium network support.
+
+ If you have a Cavium SoC or network adapter, say Y.
+
+if NET_VENDOR_CAVIUM
+
+config THUNDER_NIC_PF
+ tristate "Thunder Physical function driver"
+ depends on 64BIT
+ default ARCH_THUNDER
+ select THUNDER_NIC_BGX
+ ---help---
+ This driver supports Thunder's NIC physical function.
+ The NIC provides the controller and DMA engines to
+ move network traffic to/from the memory. The NIC
+ works closely with TNS, BGX and SerDes to implement the
+ functions replacing and virtualizing those of a typical
+ standalone PCIe NIC chip.
+
+config THUNDER_NIC_VF
+ tristate "Thunder Virtual function driver"
+ depends on 64BIT
+ default ARCH_THUNDER
+ ---help---
+ This driver supports Thunder's NIC virtual function
+
+config THUNDER_NIC_BGX
+ tristate "Thunder MAC interface driver (BGX)"
+ depends on 64BIT
+ default ARCH_THUNDER
+ ---help---
+ This driver supports programming and controlling of MAC
+ interface from NIC physical function driver.
+
+config LIQUIDIO
+ tristate "Cavium LiquidIO support"
+ depends on 64BIT
+ select PTP_1588_CLOCK
+ select FW_LOADER
+ select LIBCRC32C
+ ---help---
+ This driver supports Cavium LiquidIO Intelligent Server Adapters
+ based on CN66XX and CN68XX chips.
+
+ To compile this driver as a module, choose M here: the module
+ will be called liquidio. This is recommended.
+
+endif # NET_VENDOR_CAVIUM
diff --git a/drivers/net/ethernet/cavium/Makefile b/drivers/net/ethernet/cavium/Makefile
new file mode 100644
index 000000000000..d22f886ac291
--- /dev/null
+++ b/drivers/net/ethernet/cavium/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Cavium ethernet device drivers.
+#
+obj-$(CONFIG_NET_VENDOR_CAVIUM) += thunder/
+obj-$(CONFIG_NET_VENDOR_CAVIUM) += liquidio/
diff --git a/drivers/net/ethernet/cavium/liquidio/Makefile b/drivers/net/ethernet/cavium/liquidio/Makefile
new file mode 100644
index 000000000000..2f366806835d
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/Makefile
@@ -0,0 +1,16 @@
+#
+# Cavium Liquidio ethernet device driver
+#
+obj-$(CONFIG_LIQUIDIO) += liquidio.o
+
+liquidio-objs := lio_main.o \
+ lio_ethtool.o \
+ request_manager.o \
+ response_manager.o \
+ octeon_device.o \
+ cn66xx_device.o \
+ cn68xx_device.o \
+ octeon_mem_ops.o \
+ octeon_droq.o \
+ octeon_console.o \
+ octeon_nic.o
diff --git a/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c b/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c
new file mode 100644
index 000000000000..8ad7425f89bf
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c
@@ -0,0 +1,796 @@
+/**********************************************************************
+* Author: Cavium, Inc.
+*
+* Contact: support@cavium.com
+* Please include "LiquidIO" in the subject.
+*
+* Copyright (c) 2003-2015 Cavium, Inc.
+*
+* This file 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 file is distributed in the hope that it will be useful, but
+* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+* NONINFRINGEMENT. See the GNU General Public License for more
+* details.
+*
+* This file may also be available under a different license from Cavium.
+* Contact Cavium, Inc. for more information
+**********************************************************************/
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include "octeon_config.h"
+#include "liquidio_common.h"
+#include "octeon_droq.h"
+#include "octeon_iq.h"
+#include "response_manager.h"
+#include "octeon_device.h"
+#include "octeon_nic.h"
+#include "octeon_main.h"
+#include "octeon_network.h"
+#include "cn66xx_regs.h"
+#include "cn66xx_device.h"
+#include "liquidio_image.h"
+#include "octeon_mem_ops.h"
+
+int lio_cn6xxx_soft_reset(struct octeon_device *oct)
+{
+ octeon_write_csr64(oct, CN6XXX_WIN_WR_MASK_REG, 0xFF);
+
+ dev_dbg(&oct->pci_dev->dev, "BIST enabled for soft reset\n");
+
+ lio_pci_writeq(oct, 1, CN6XXX_CIU_SOFT_BIST);
+ octeon_write_csr64(oct, CN6XXX_SLI_SCRATCH1, 0x1234ULL);
+
+ lio_pci_readq(oct, CN6XXX_CIU_SOFT_RST);
+ lio_pci_writeq(oct, 1, CN6XXX_CIU_SOFT_RST);
+
+ /* make sure that the reset is written before starting timer */
+ mmiowb();
+
+ /* Wait for 10ms as Octeon resets. */
+ mdelay(100);
+
+ if (octeon_read_csr64(oct, CN6XXX_SLI_SCRATCH1) == 0x1234ULL) {
+ dev_err(&oct->pci_dev->dev, "Soft reset failed\n");
+ return 1;
+ }
+
+ dev_dbg(&oct->pci_dev->dev, "Reset completed\n");
+ octeon_write_csr64(oct, CN6XXX_WIN_WR_MASK_REG, 0xFF);
+
+ return 0;
+}
+
+void lio_cn6xxx_enable_error_reporting(struct octeon_device *oct)
+{
+ u32 val;
+
+ pci_read_config_dword(oct->pci_dev, CN6XXX_PCIE_DEVCTL, &val);
+ if (val & 0x000f0000) {
+ dev_err(&oct->pci_dev->dev, "PCI-E Link error detected: 0x%08x\n",
+ val & 0x000f0000);
+ }
+
+ val |= 0xf; /* Enable Link error reporting */
+
+ dev_dbg(&oct->pci_dev->dev, "Enabling PCI-E error reporting..\n");
+ pci_write_config_dword(oct->pci_dev, CN6XXX_PCIE_DEVCTL, val);
+}
+
+void lio_cn6xxx_setup_pcie_mps(struct octeon_device *oct,
+ enum octeon_pcie_mps mps)
+{
+ u32 val;
+ u64 r64;
+
+ /* Read config register for MPS */
+ pci_read_config_dword(oct->pci_dev, CN6XXX_PCIE_DEVCTL, &val);
+
+ if (mps == PCIE_MPS_DEFAULT) {
+ mps = ((val & (0x7 << 5)) >> 5);
+ } else {
+ val &= ~(0x7 << 5); /* Turn off any MPS bits */
+ val |= (mps << 5); /* Set MPS */
+ pci_write_config_dword(oct->pci_dev, CN6XXX_PCIE_DEVCTL, val);
+ }
+
+ /* Set MPS in DPI_SLI_PRT0_CFG to the same value. */
+ r64 = lio_pci_readq(oct, CN6XXX_DPI_SLI_PRTX_CFG(oct->pcie_port));
+ r64 |= (mps << 4);
+ lio_pci_writeq(oct, r64, CN6XXX_DPI_SLI_PRTX_CFG(oct->pcie_port));
+}
+
+void lio_cn6xxx_setup_pcie_mrrs(struct octeon_device *oct,
+ enum octeon_pcie_mrrs mrrs)
+{
+ u32 val;
+ u64 r64;
+
+ /* Read config register for MRRS */
+ pci_read_config_dword(oct->pci_dev, CN6XXX_PCIE_DEVCTL, &val);
+
+ if (mrrs == PCIE_MRRS_DEFAULT) {
+ mrrs = ((val & (0x7 << 12)) >> 12);
+ } else {
+ val &= ~(0x7 << 12); /* Turn off any MRRS bits */
+ val |= (mrrs << 12); /* Set MRRS */
+ pci_write_config_dword(oct->pci_dev, CN6XXX_PCIE_DEVCTL, val);
+ }
+
+ /* Set MRRS in SLI_S2M_PORT0_CTL to the same value. */
+ r64 = octeon_read_csr64(oct, CN6XXX_SLI_S2M_PORTX_CTL(oct->pcie_port));
+ r64 |= mrrs;
+ octeon_write_csr64(oct, CN6XXX_SLI_S2M_PORTX_CTL(oct->pcie_port), r64);
+
+ /* Set MRRS in DPI_SLI_PRT0_CFG to the same value. */
+ r64 = lio_pci_readq(oct, CN6XXX_DPI_SLI_PRTX_CFG(oct->pcie_port));
+ r64 |= mrrs;
+ lio_pci_writeq(oct, r64, CN6XXX_DPI_SLI_PRTX_CFG(oct->pcie_port));
+}
+
+u32 lio_cn6xxx_coprocessor_clock(struct octeon_device *oct)
+{
+ /* Bits 29:24 of MIO_RST_BOOT holds the ref. clock multiplier
+ * for SLI.
+ */
+ return ((lio_pci_readq(oct, CN6XXX_MIO_RST_BOOT) >> 24) & 0x3f) * 50;
+}
+
+u32 lio_cn6xxx_get_oq_ticks(struct octeon_device *oct,
+ u32 time_intr_in_us)
+{
+ /* This gives the SLI clock per microsec */
+ u32 oqticks_per_us = lio_cn6xxx_coprocessor_clock(oct);
+
+ /* core clock per us / oq ticks will be fractional. TO avoid that
+ * we use the method below.
+ */
+
+ /* This gives the clock cycles per millisecond */
+ oqticks_per_us *= 1000;
+
+ /* This gives the oq ticks (1024 core clock cycles) per millisecond */
+ oqticks_per_us /= 1024;
+
+ /* time_intr is in microseconds. The next 2 steps gives the oq ticks
+ * corressponding to time_intr.
+ */
+ oqticks_per_us *= time_intr_in_us;
+ oqticks_per_us /= 1000;
+
+ return oqticks_per_us;
+}
+
+void lio_cn6xxx_setup_global_input_regs(struct octeon_device *oct)
+{
+ /* Select Round-Robin Arb, ES, RO, NS for Input Queues */
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_INPUT_CONTROL,
+ CN6XXX_INPUT_CTL_MASK);
+
+ /* Instruction Read Size - Max 4 instructions per PCIE Read */
+ octeon_write_csr64(oct, CN6XXX_SLI_PKT_INSTR_RD_SIZE,
+ 0xFFFFFFFFFFFFFFFFULL);
+
+ /* Select PCIE Port for all Input rings. */
+ octeon_write_csr64(oct, CN6XXX_SLI_IN_PCIE_PORT,
+ (oct->pcie_port * 0x5555555555555555ULL));
+}
+
+static void lio_cn66xx_setup_pkt_ctl_regs(struct octeon_device *oct)
+{
+ u64 pktctl;
+
+ struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)oct->chip;
+
+ pktctl = octeon_read_csr64(oct, CN6XXX_SLI_PKT_CTL);
+
+ /* 66XX SPECIFIC */
+ if (CFG_GET_OQ_MAX_Q(cn6xxx->conf) <= 4)
+ /* Disable RING_EN if only upto 4 rings are used. */
+ pktctl &= ~(1 << 4);
+ else
+ pktctl |= (1 << 4);
+
+ if (CFG_GET_IS_SLI_BP_ON(cn6xxx->conf))
+ pktctl |= 0xF;
+ else
+ /* Disable per-port backpressure. */
+ pktctl &= ~0xF;
+ octeon_write_csr64(oct, CN6XXX_SLI_PKT_CTL, pktctl);
+}
+
+void lio_cn6xxx_setup_global_output_regs(struct octeon_device *oct)
+{
+ u32 time_threshold;
+ struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)oct->chip;
+
+ /* / Select PCI-E Port for all Output queues */
+ octeon_write_csr64(oct, CN6XXX_SLI_PKT_PCIE_PORT64,
+ (oct->pcie_port * 0x5555555555555555ULL));
+
+ if (CFG_GET_IS_SLI_BP_ON(cn6xxx->conf)) {
+ octeon_write_csr64(oct, CN6XXX_SLI_OQ_WMARK, 32);
+ } else {
+ /* / Set Output queue watermark to 0 to disable backpressure */
+ octeon_write_csr64(oct, CN6XXX_SLI_OQ_WMARK, 0);
+ }
+
+ /* / Select Info Ptr for length & data */
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_IPTR, 0xFFFFFFFF);
+
+ /* / Select Packet count instead of bytes for SLI_PKTi_CNTS[CNT] */
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_OUT_BMODE, 0);
+
+ /* / Select ES,RO,NS setting from register for Output Queue Packet
+ * Address
+ */
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_DPADDR, 0xFFFFFFFF);
+
+ /* No Relaxed Ordering, No Snoop, 64-bit swap for Output
+ * Queue ScatterList
+ */
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_SLIST_ROR, 0);
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_SLIST_NS, 0);
+
+ /* / ENDIAN_SPECIFIC CHANGES - 0 works for LE. */
+#ifdef __BIG_ENDIAN_BITFIELD
+ octeon_write_csr64(oct, CN6XXX_SLI_PKT_SLIST_ES64,
+ 0x5555555555555555ULL);
+#else
+ octeon_write_csr64(oct, CN6XXX_SLI_PKT_SLIST_ES64, 0ULL);
+#endif
+
+ /* / No Relaxed Ordering, No Snoop, 64-bit swap for Output Queue Data */
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_DATA_OUT_ROR, 0);
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_DATA_OUT_NS, 0);
+ octeon_write_csr64(oct, CN6XXX_SLI_PKT_DATA_OUT_ES64,
+ 0x5555555555555555ULL);
+
+ /* / Set up interrupt packet and time threshold */
+ octeon_write_csr(oct, CN6XXX_SLI_OQ_INT_LEVEL_PKTS,
+ (u32)CFG_GET_OQ_INTR_PKT(cn6xxx->conf));
+ time_threshold =
+ lio_cn6xxx_get_oq_ticks(oct, (u32)
+ CFG_GET_OQ_INTR_TIME(cn6xxx->conf));
+
+ octeon_write_csr(oct, CN6XXX_SLI_OQ_INT_LEVEL_TIME, time_threshold);
+}
+
+static int lio_cn6xxx_setup_device_regs(struct octeon_device *oct)
+{
+ lio_cn6xxx_setup_pcie_mps(oct, PCIE_MPS_DEFAULT);
+ lio_cn6xxx_setup_pcie_mrrs(oct, PCIE_MRRS_512B);
+ lio_cn6xxx_enable_error_reporting(oct);
+
+ lio_cn6xxx_setup_global_input_regs(oct);
+ lio_cn66xx_setup_pkt_ctl_regs(oct);
+ lio_cn6xxx_setup_global_output_regs(oct);
+
+ /* Default error timeout value should be 0x200000 to avoid host hang
+ * when reads invalid register
+ */
+ octeon_write_csr64(oct, CN6XXX_SLI_WINDOW_CTL, 0x200000ULL);
+ return 0;
+}
+
+void lio_cn6xxx_setup_iq_regs(struct octeon_device *oct, u32 iq_no)
+{
+ struct octeon_instr_queue *iq = oct->instr_queue[iq_no];
+
+ /* Disable Packet-by-Packet mode; No Parse Mode or Skip length */
+ octeon_write_csr64(oct, CN6XXX_SLI_IQ_PKT_INSTR_HDR64(iq_no), 0);
+
+ /* Write the start of the input queue's ring and its size */
+ octeon_write_csr64(oct, CN6XXX_SLI_IQ_BASE_ADDR64(iq_no),
+ iq->base_addr_dma);
+ octeon_write_csr(oct, CN6XXX_SLI_IQ_SIZE(iq_no), iq->max_count);
+
+ /* Remember the doorbell & instruction count register addr for this
+ * queue
+ */
+ iq->doorbell_reg = oct->mmio[0].hw_addr + CN6XXX_SLI_IQ_DOORBELL(iq_no);
+ iq->inst_cnt_reg = oct->mmio[0].hw_addr
+ + CN6XXX_SLI_IQ_INSTR_COUNT(iq_no);
+ dev_dbg(&oct->pci_dev->dev, "InstQ[%d]:dbell reg @ 0x%p instcnt_reg @ 0x%p\n",
+ iq_no, iq->doorbell_reg, iq->inst_cnt_reg);
+
+ /* Store the current instruction counter
+ * (used in flush_iq calculation)
+ */
+ iq->reset_instr_cnt = readl(iq->inst_cnt_reg);
+}
+
+static void lio_cn66xx_setup_iq_regs(struct octeon_device *oct, u32 iq_no)
+{
+ lio_cn6xxx_setup_iq_regs(oct, iq_no);
+
+ /* Backpressure for this queue - WMARK set to all F's. This effectively
+ * disables the backpressure mechanism.
+ */
+ octeon_write_csr64(oct, CN66XX_SLI_IQ_BP64(iq_no),
+ (0xFFFFFFFFULL << 32));
+}
+
+void lio_cn6xxx_setup_oq_regs(struct octeon_device *oct, u32 oq_no)
+{
+ u32 intr;
+ struct octeon_droq *droq = oct->droq[oq_no];
+
+ octeon_write_csr64(oct, CN6XXX_SLI_OQ_BASE_ADDR64(oq_no),
+ droq->desc_ring_dma);
+ octeon_write_csr(oct, CN6XXX_SLI_OQ_SIZE(oq_no), droq->max_count);
+
+ octeon_write_csr(oct, CN6XXX_SLI_OQ_BUFF_INFO_SIZE(oq_no),
+ (droq->buffer_size | (OCT_RH_SIZE << 16)));
+
+ /* Get the mapped address of the pkt_sent and pkts_credit regs */
+ droq->pkts_sent_reg =
+ oct->mmio[0].hw_addr + CN6XXX_SLI_OQ_PKTS_SENT(oq_no);
+ droq->pkts_credit_reg =
+ oct->mmio[0].hw_addr + CN6XXX_SLI_OQ_PKTS_CREDIT(oq_no);
+
+ /* Enable this output queue to generate Packet Timer Interrupt */
+ intr = octeon_read_csr(oct, CN6XXX_SLI_PKT_TIME_INT_ENB);
+ intr |= (1 << oq_no);
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_TIME_INT_ENB, intr);
+
+ /* Enable this output queue to generate Packet Timer Interrupt */
+ intr = octeon_read_csr(oct, CN6XXX_SLI_PKT_CNT_INT_ENB);
+ intr |= (1 << oq_no);
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_CNT_INT_ENB, intr);
+}
+
+void lio_cn6xxx_enable_io_queues(struct octeon_device *oct)
+{
+ u32 mask;
+
+ mask = octeon_read_csr(oct, CN6XXX_SLI_PKT_INSTR_SIZE);
+ mask |= oct->io_qmask.iq64B;
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_INSTR_SIZE, mask);
+
+ mask = octeon_read_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB);
+ mask |= oct->io_qmask.iq;
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB, mask);
+
+ mask = octeon_read_csr(oct, CN6XXX_SLI_PKT_OUT_ENB);
+ mask |= oct->io_qmask.oq;
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_OUT_ENB, mask);
+}
+
+void lio_cn6xxx_disable_io_queues(struct octeon_device *oct)
+{
+ u32 mask, i, loop = HZ;
+ u32 d32;
+
+ /* Reset the Enable bits for Input Queues. */
+ mask = octeon_read_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB);
+ mask ^= oct->io_qmask.iq;
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB, mask);
+
+ /* Wait until hardware indicates that the queues are out of reset. */
+ mask = oct->io_qmask.iq;
+ d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_IQ);
+ while (((d32 & mask) != mask) && loop--) {
+ d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_IQ);
+ schedule_timeout_uninterruptible(1);
+ }
+
+ /* Reset the doorbell register for each Input queue. */
+ for (i = 0; i < MAX_OCTEON_INSTR_QUEUES; i++) {
+ if (!(oct->io_qmask.iq & (1UL << i)))
+ continue;
+ octeon_write_csr(oct, CN6XXX_SLI_IQ_DOORBELL(i), 0xFFFFFFFF);
+ d32 = octeon_read_csr(oct, CN6XXX_SLI_IQ_DOORBELL(i));
+ }
+
+ /* Reset the Enable bits for Output Queues. */
+ mask = octeon_read_csr(oct, CN6XXX_SLI_PKT_OUT_ENB);
+ mask ^= oct->io_qmask.oq;
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_OUT_ENB, mask);
+
+ /* Wait until hardware indicates that the queues are out of reset. */
+ loop = HZ;
+ mask = oct->io_qmask.oq;
+ d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_OQ);
+ while (((d32 & mask) != mask) && loop--) {
+ d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_OQ);
+ schedule_timeout_uninterruptible(1);
+ }
+ ;
+
+ /* Reset the doorbell register for each Output queue. */
+ /* for (i = 0; i < oct->num_oqs; i++) { */
+ for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) {
+ if (!(oct->io_qmask.oq & (1UL << i)))
+ continue;
+ octeon_write_csr(oct, CN6XXX_SLI_OQ_PKTS_CREDIT(i), 0xFFFFFFFF);
+ d32 = octeon_read_csr(oct, CN6XXX_SLI_OQ_PKTS_CREDIT(i));
+
+ d32 = octeon_read_csr(oct, CN6XXX_SLI_OQ_PKTS_SENT(i));
+ octeon_write_csr(oct, CN6XXX_SLI_OQ_PKTS_SENT(i), d32);
+ }
+
+ d32 = octeon_read_csr(oct, CN6XXX_SLI_PKT_CNT_INT);
+ if (d32)
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_CNT_INT, d32);
+
+ d32 = octeon_read_csr(oct, CN6XXX_SLI_PKT_TIME_INT);
+ if (d32)
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_TIME_INT, d32);
+}
+
+void lio_cn6xxx_reinit_regs(struct octeon_device *oct)
+{
+ u32 i;
+
+ for (i = 0; i < MAX_OCTEON_INSTR_QUEUES; i++) {
+ if (!(oct->io_qmask.iq & (1UL << i)))
+ continue;
+ oct->fn_list.setup_iq_regs(oct, i);
+ }
+
+ for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) {
+ if (!(oct->io_qmask.oq & (1UL << i)))
+ continue;
+ oct->fn_list.setup_oq_regs(oct, i);
+ }
+
+ oct->fn_list.setup_device_regs(oct);
+
+ oct->fn_list.enable_interrupt(oct->chip);
+
+ oct->fn_list.enable_io_queues(oct);
+
+ /* for (i = 0; i < oct->num_oqs; i++) { */
+ for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) {
+ if (!(oct->io_qmask.oq & (1UL << i)))
+ continue;
+ writel(oct->droq[i]->max_count, oct->droq[i]->pkts_credit_reg);
+ }
+}
+
+void
+lio_cn6xxx_bar1_idx_setup(struct octeon_device *oct,
+ u64 core_addr,
+ u32 idx,
+ int valid)
+{
+ u64 bar1;
+
+ if (valid == 0) {
+ bar1 = lio_pci_readq(oct, CN6XXX_BAR1_REG(idx, oct->pcie_port));
+ lio_pci_writeq(oct, (bar1 & 0xFFFFFFFEULL),
+ CN6XXX_BAR1_REG(idx, oct->pcie_port));
+ bar1 = lio_pci_readq(oct, CN6XXX_BAR1_REG(idx, oct->pcie_port));
+ return;
+ }
+
+ /* Bits 17:4 of the PCI_BAR1_INDEXx stores bits 35:22 of
+ * the Core Addr
+ */
+ lio_pci_writeq(oct, (((core_addr >> 22) << 4) | PCI_BAR1_MASK),
+ CN6XXX_BAR1_REG(idx, oct->pcie_port));
+
+ bar1 = lio_pci_readq(oct, CN6XXX_BAR1_REG(idx, oct->pcie_port));
+}
+
+void lio_cn6xxx_bar1_idx_write(struct octeon_device *oct,
+ u32 idx,
+ u32 mask)
+{
+ lio_pci_writeq(oct, mask, CN6XXX_BAR1_REG(idx, oct->pcie_port));
+}
+
+u32 lio_cn6xxx_bar1_idx_read(struct octeon_device *oct, u32 idx)
+{
+ return (u32)lio_pci_readq(oct, CN6XXX_BAR1_REG(idx, oct->pcie_port));
+}
+
+u32
+lio_cn6xxx_update_read_index(struct octeon_device *oct __attribute__((unused)),
+ struct octeon_instr_queue *iq)
+{
+ u32 new_idx = readl(iq->inst_cnt_reg);
+
+ /* The new instr cnt reg is a 32-bit counter that can roll over. We have
+ * noted the counter's initial value at init time into
+ * reset_instr_cnt
+ */
+ if (iq->reset_instr_cnt < new_idx)
+ new_idx -= iq->reset_instr_cnt;
+ else
+ new_idx += (0xffffffff - iq->reset_instr_cnt) + 1;
+
+ /* Modulo of the new index with the IQ size will give us
+ * the new index.
+ */
+ new_idx %= iq->max_count;
+
+ return new_idx;
+}
+
+void lio_cn6xxx_enable_interrupt(void *chip)
+{
+ struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)chip;
+ u64 mask = cn6xxx->intr_mask64 | CN6XXX_INTR_DMA0_FORCE;
+
+ /* Enable Interrupt */
+ writeq(mask, cn6xxx->intr_enb_reg64);
+}
+
+void lio_cn6xxx_disable_interrupt(void *chip)
+{
+ struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)chip;
+
+ /* Disable Interrupts */
+ writeq(0, cn6xxx->intr_enb_reg64);
+
+ /* make sure interrupts are really disabled */
+ mmiowb();
+}
+
+static void lio_cn6xxx_get_pcie_qlmport(struct octeon_device *oct)
+{
+ /* CN63xx Pass2 and newer parts implements the SLI_MAC_NUMBER register
+ * to determine the PCIE port #
+ */
+ oct->pcie_port = octeon_read_csr(oct, CN6XXX_SLI_MAC_NUMBER) & 0xff;
+
+ dev_dbg(&oct->pci_dev->dev, "Using PCIE Port %d\n", oct->pcie_port);
+}
+
+void
+lio_cn6xxx_process_pcie_error_intr(struct octeon_device *oct, u64 intr64)
+{
+ dev_err(&oct->pci_dev->dev, "Error Intr: 0x%016llx\n",
+ CVM_CAST64(intr64));
+}
+
+int lio_cn6xxx_process_droq_intr_regs(struct octeon_device *oct)
+{
+ struct octeon_droq *droq;
+ u32 oq_no, pkt_count, droq_time_mask, droq_mask, droq_int_enb;
+ u32 droq_cnt_enb, droq_cnt_mask;
+
+ droq_cnt_enb = octeon_read_csr(oct, CN6XXX_SLI_PKT_CNT_INT_ENB);
+ droq_cnt_mask = octeon_read_csr(oct, CN6XXX_SLI_PKT_CNT_INT);
+ droq_mask = droq_cnt_mask & droq_cnt_enb;
+
+ droq_time_mask = octeon_read_csr(oct, CN6XXX_SLI_PKT_TIME_INT);
+ droq_int_enb = octeon_read_csr(oct, CN6XXX_SLI_PKT_TIME_INT_ENB);
+ droq_mask |= (droq_time_mask & droq_int_enb);
+
+ droq_mask &= oct->io_qmask.oq;
+
+ oct->droq_intr = 0;
+
+ /* for (oq_no = 0; oq_no < oct->num_oqs; oq_no++) { */
+ for (oq_no = 0; oq_no < MAX_OCTEON_OUTPUT_QUEUES; oq_no++) {
+ if (!(droq_mask & (1 << oq_no)))
+ continue;
+
+ droq = oct->droq[oq_no];
+ pkt_count = octeon_droq_check_hw_for_pkts(oct, droq);
+ if (pkt_count) {
+ oct->droq_intr |= (1ULL << oq_no);
+ if (droq->ops.poll_mode) {
+ u32 value;
+ u32 reg;
+
+ struct octeon_cn6xxx *cn6xxx =
+ (struct octeon_cn6xxx *)oct->chip;
+
+ /* disable interrupts for this droq */
+ spin_lock
+ (&cn6xxx->lock_for_droq_int_enb_reg);
+ reg = CN6XXX_SLI_PKT_TIME_INT_ENB;
+ value = octeon_read_csr(oct, reg);
+ value &= ~(1 << oq_no);
+ octeon_write_csr(oct, reg, value);
+ reg = CN6XXX_SLI_PKT_CNT_INT_ENB;
+ value = octeon_read_csr(oct, reg);
+ value &= ~(1 << oq_no);
+ octeon_write_csr(oct, reg, value);
+
+ /* Ensure that the enable register is written.
+ */
+ mmiowb();
+
+ spin_unlock(&cn6xxx->lock_for_droq_int_enb_reg);
+ }
+ }
+ }
+
+ droq_time_mask &= oct->io_qmask.oq;
+ droq_cnt_mask &= oct->io_qmask.oq;
+
+ /* Reset the PKT_CNT/TIME_INT registers. */
+ if (droq_time_mask)
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_TIME_INT, droq_time_mask);
+
+ if (droq_cnt_mask) /* reset PKT_CNT register:66xx */
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_CNT_INT, droq_cnt_mask);
+
+ return 0;
+}
+
+irqreturn_t lio_cn6xxx_process_interrupt_regs(void *dev)
+{
+ struct octeon_device *oct = (struct octeon_device *)dev;
+ struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)oct->chip;
+ u64 intr64;
+
+ intr64 = readq(cn6xxx->intr_sum_reg64);
+
+ /* If our device has interrupted, then proceed.
+ * Also check for all f's if interrupt was triggered on an error
+ * and the PCI read fails.
+ */
+ if (!intr64 || (intr64 == 0xFFFFFFFFFFFFFFFFULL))
+ return IRQ_NONE;
+
+ oct->int_status = 0;
+
+ if (intr64 & CN6XXX_INTR_ERR)
+ lio_cn6xxx_process_pcie_error_intr(oct, intr64);
+
+ if (intr64 & CN6XXX_INTR_PKT_DATA) {
+ lio_cn6xxx_process_droq_intr_regs(oct);
+ oct->int_status |= OCT_DEV_INTR_PKT_DATA;
+ }
+
+ if (intr64 & CN6XXX_INTR_DMA0_FORCE)
+ oct->int_status |= OCT_DEV_INTR_DMA0_FORCE;
+
+ if (intr64 & CN6XXX_INTR_DMA1_FORCE)
+ oct->int_status |= OCT_DEV_INTR_DMA1_FORCE;
+
+ /* Clear the current interrupts */
+ writeq(intr64, cn6xxx->intr_sum_reg64);
+
+ return IRQ_HANDLED;
+}
+
+void lio_cn6xxx_setup_reg_address(struct octeon_device *oct,
+ void *chip,
+ struct octeon_reg_list *reg_list)
+{
+ u8 __iomem *bar0_pciaddr = oct->mmio[0].hw_addr;
+ struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)chip;
+
+ reg_list->pci_win_wr_addr_hi =
+ (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_WR_ADDR_HI);
+ reg_list->pci_win_wr_addr_lo =
+ (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_WR_ADDR_LO);
+ reg_list->pci_win_wr_addr =
+ (u64 __iomem *)(bar0_pciaddr + CN6XXX_WIN_WR_ADDR64);
+
+ reg_list->pci_win_rd_addr_hi =
+ (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_RD_ADDR_HI);
+ reg_list->pci_win_rd_addr_lo =
+ (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_RD_ADDR_LO);
+ reg_list->pci_win_rd_addr =
+ (u64 __iomem *)(bar0_pciaddr + CN6XXX_WIN_RD_ADDR64);
+
+ reg_list->pci_win_wr_data_hi =
+ (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_WR_DATA_HI);
+ reg_list->pci_win_wr_data_lo =
+ (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_WR_DATA_LO);
+ reg_list->pci_win_wr_data =
+ (u64 __iomem *)(bar0_pciaddr + CN6XXX_WIN_WR_DATA64);
+
+ reg_list->pci_win_rd_data_hi =
+ (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_RD_DATA_HI);
+ reg_list->pci_win_rd_data_lo =
+ (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_RD_DATA_LO);
+ reg_list->pci_win_rd_data =
+ (u64 __iomem *)(bar0_pciaddr + CN6XXX_WIN_RD_DATA64);
+
+ lio_cn6xxx_get_pcie_qlmport(oct);
+
+ cn6xxx->intr_sum_reg64 = bar0_pciaddr + CN6XXX_SLI_INT_SUM64;
+ cn6xxx->intr_mask64 = CN6XXX_INTR_MASK;
+ cn6xxx->intr_enb_reg64 =
+ bar0_pciaddr + CN6XXX_SLI_INT_ENB64(oct->pcie_port);
+}
+
+int lio_setup_cn66xx_octeon_device(struct octeon_device *oct)
+{
+ struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)oct->chip;
+
+ if (octeon_map_pci_barx(oct, 0, 0))
+ return 1;
+
+ if (octeon_map_pci_barx(oct, 1, MAX_BAR1_IOREMAP_SIZE)) {
+ dev_err(&oct->pci_dev->dev, "%s CN66XX BAR1 map failed\n",
+ __func__);
+ octeon_unmap_pci_barx(oct, 0);
+ return 1;
+ }
+
+ spin_lock_init(&cn6xxx->lock_for_droq_int_enb_reg);
+
+ oct->fn_list.setup_iq_regs = lio_cn66xx_setup_iq_regs;
+ oct->fn_list.setup_oq_regs = lio_cn6xxx_setup_oq_regs;
+
+ oct->fn_list.soft_reset = lio_cn6xxx_soft_reset;
+ oct->fn_list.setup_device_regs = lio_cn6xxx_setup_device_regs;
+ oct->fn_list.reinit_regs = lio_cn6xxx_reinit_regs;
+ oct->fn_list.update_iq_read_idx = lio_cn6xxx_update_read_index;
+
+ oct->fn_list.bar1_idx_setup = lio_cn6xxx_bar1_idx_setup;
+ oct->fn_list.bar1_idx_write = lio_cn6xxx_bar1_idx_write;
+ oct->fn_list.bar1_idx_read = lio_cn6xxx_bar1_idx_read;
+
+ oct->fn_list.process_interrupt_regs = lio_cn6xxx_process_interrupt_regs;
+ oct->fn_list.enable_interrupt = lio_cn6xxx_enable_interrupt;
+ oct->fn_list.disable_interrupt = lio_cn6xxx_disable_interrupt;
+
+ oct->fn_list.enable_io_queues = lio_cn6xxx_enable_io_queues;
+ oct->fn_list.disable_io_queues = lio_cn6xxx_disable_io_queues;
+
+ lio_cn6xxx_setup_reg_address(oct, oct->chip, &oct->reg_list);
+
+ cn6xxx->conf = (struct octeon_config *)
+ oct_get_config_info(oct, LIO_210SV);
+ if (!cn6xxx->conf) {
+ dev_err(&oct->pci_dev->dev, "%s No Config found for CN66XX\n",
+ __func__);
+ octeon_unmap_pci_barx(oct, 0);
+ octeon_unmap_pci_barx(oct, 1);
+ return 1;
+ }
+
+ oct->coproc_clock_rate = 1000000ULL * lio_cn6xxx_coprocessor_clock(oct);
+
+ return 0;
+}
+
+int lio_validate_cn6xxx_config_info(struct octeon_device *oct,
+ struct octeon_config *conf6xxx)
+{
+ /* int total_instrs = 0; */
+
+ if (CFG_GET_IQ_MAX_Q(conf6xxx) > CN6XXX_MAX_INPUT_QUEUES) {
+ dev_err(&oct->pci_dev->dev, "%s: Num IQ (%d) exceeds Max (%d)\n",
+ __func__, CFG_GET_IQ_MAX_Q(conf6xxx),
+ CN6XXX_MAX_INPUT_QUEUES);
+ return 1;
+ }
+
+ if (CFG_GET_OQ_MAX_Q(conf6xxx) > CN6XXX_MAX_OUTPUT_QUEUES) {
+ dev_err(&oct->pci_dev->dev, "%s: Num OQ (%d) exceeds Max (%d)\n",
+ __func__, CFG_GET_OQ_MAX_Q(conf6xxx),
+ CN6XXX_MAX_OUTPUT_QUEUES);
+ return 1;
+ }
+
+ if (CFG_GET_IQ_INSTR_TYPE(conf6xxx) != OCTEON_32BYTE_INSTR &&
+ CFG_GET_IQ_INSTR_TYPE(conf6xxx) != OCTEON_64BYTE_INSTR) {
+ dev_err(&oct->pci_dev->dev, "%s: Invalid instr type for IQ\n",
+ __func__);
+ return 1;
+ }
+ if (!(CFG_GET_OQ_INFO_PTR(conf6xxx)) ||
+ !(CFG_GET_OQ_REFILL_THRESHOLD(conf6xxx))) {
+ dev_err(&oct->pci_dev->dev, "%s: Invalid parameter for OQ\n",
+ __func__);
+ return 1;
+ }
+
+ if (!(CFG_GET_OQ_INTR_TIME(conf6xxx))) {
+ dev_err(&oct->pci_dev->dev, "%s: No Time Interrupt for OQ\n",
+ __func__);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/cavium/liquidio/cn66xx_device.h b/drivers/net/ethernet/cavium/liquidio/cn66xx_device.h
new file mode 100644
index 000000000000..f77918779355
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/cn66xx_device.h
@@ -0,0 +1,107 @@
+/**********************************************************************
+* Author: Cavium, Inc.
+*
+* Contact: support@cavium.com
+* Please include "LiquidIO" in the subject.
+*
+* Copyright (c) 2003-2015 Cavium, Inc.
+*
+* This file 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 file is distributed in the hope that it will be useful, but
+* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+* NONINFRINGEMENT. See the GNU General Public License for more
+* details.
+*
+* This file may also be available under a different license from Cavium.
+* Contact Cavium, Inc. for more information
+**********************************************************************/
+
+/*! \file cn66xx_device.h
+ * \brief Host Driver: Routines that perform CN66XX specific operations.
+ */
+
+#ifndef __CN66XX_DEVICE_H__
+#define __CN66XX_DEVICE_H__
+
+/* Register address and configuration for a CN6XXX devices.
+ * If device specific changes need to be made then add a struct to include
+ * device specific fields as shown in the commented section
+ */
+struct octeon_cn6xxx {
+ /** PCI interrupt summary register */
+ u8 __iomem *intr_sum_reg64;
+
+ /** PCI interrupt enable register */
+ u8 __iomem *intr_enb_reg64;
+
+ /** The PCI interrupt mask used by interrupt handler */
+ u64 intr_mask64;
+
+ struct octeon_config *conf;
+
+ /* Example additional fields - not used currently
+ * struct {
+ * }cn6xyz;
+ */
+
+ /* For the purpose of atomic access to interrupt enable reg */
+ spinlock_t lock_for_droq_int_enb_reg;
+
+};
+
+enum octeon_pcie_mps {
+ PCIE_MPS_DEFAULT = -1, /* Use the default setup by BIOS */
+ PCIE_MPS_128B = 0,
+ PCIE_MPS_256B = 1
+};
+
+enum octeon_pcie_mrrs {
+ PCIE_MRRS_DEFAULT = -1, /* Use the default setup by BIOS */
+ PCIE_MRRS_128B = 0,
+ PCIE_MRRS_256B = 1,
+ PCIE_MRRS_512B = 2,
+ PCIE_MRRS_1024B = 3,
+ PCIE_MRRS_2048B = 4,
+ PCIE_MRRS_4096B = 5
+};
+
+/* Common functions for 66xx and 68xx */
+int lio_cn6xxx_soft_reset(struct octeon_device *oct);
+void lio_cn6xxx_enable_error_reporting(struct octeon_device *oct);
+void lio_cn6xxx_setup_pcie_mps(struct octeon_device *oct,
+ enum octeon_pcie_mps mps);
+void lio_cn6xxx_setup_pcie_mrrs(struct octeon_device *oct,
+ enum octeon_pcie_mrrs mrrs);
+void lio_cn6xxx_setup_global_input_regs(struct octeon_device *oct);
+void lio_cn6xxx_setup_global_output_regs(struct octeon_device *oct);
+void lio_cn6xxx_setup_iq_regs(struct octeon_device *oct, u32 iq_no);
+void lio_cn6xxx_setup_oq_regs(struct octeon_device *oct, u32 oq_no);
+void lio_cn6xxx_enable_io_queues(struct octeon_device *oct);
+void lio_cn6xxx_disable_io_queues(struct octeon_device *oct);
+void lio_cn6xxx_process_pcie_error_intr(struct octeon_device *oct, u64 intr64);
+int lio_cn6xxx_process_droq_intr_regs(struct octeon_device *oct);
+irqreturn_t lio_cn6xxx_process_interrupt_regs(void *dev);
+void lio_cn6xxx_reinit_regs(struct octeon_device *oct);
+void lio_cn6xxx_bar1_idx_setup(struct octeon_device *oct, u64 core_addr,
+ u32 idx, int valid);
+void lio_cn6xxx_bar1_idx_write(struct octeon_device *oct, u32 idx, u32 mask);
+u32 lio_cn6xxx_bar1_idx_read(struct octeon_device *oct, u32 idx);
+u32
+lio_cn6xxx_update_read_index(struct octeon_device *oct __attribute__((unused)),
+ struct octeon_instr_queue *iq);
+void lio_cn6xxx_enable_interrupt(void *chip);
+void lio_cn6xxx_disable_interrupt(void *chip);
+void cn6xxx_get_pcie_qlmport(struct octeon_device *oct);
+void lio_cn6xxx_setup_reg_address(struct octeon_device *oct, void *chip,
+ struct octeon_reg_list *reg_list);
+u32 lio_cn6xxx_coprocessor_clock(struct octeon_device *oct);
+u32 lio_cn6xxx_get_oq_ticks(struct octeon_device *oct, u32 time_intr_in_us);
+int lio_setup_cn66xx_octeon_device(struct octeon_device *);
+int lio_validate_cn6xxx_config_info(struct octeon_device *oct,
+ struct octeon_config *);
+
+#endif
diff --git a/drivers/net/ethernet/cavium/liquidio/cn66xx_regs.h b/drivers/net/ethernet/cavium/liquidio/cn66xx_regs.h
new file mode 100644
index 000000000000..5e3aff242ad3
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/cn66xx_regs.h
@@ -0,0 +1,535 @@
+/**********************************************************************
+* Author: Cavium, Inc.
+*
+* Contact: support@cavium.com
+* Please include "LiquidIO" in the subject.
+*
+* Copyright (c) 2003-2015 Cavium, Inc.
+*
+* This file 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 file is distributed in the hope that it will be useful, but
+* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+* NONINFRINGEMENT. See the GNU General Public License for more
+* details.
+*
+* This file may also be available under a different license from Cavium.
+* Contact Cavium, Inc. for more information
+**********************************************************************/
+
+/*! \file cn66xx_regs.h
+ * \brief Host Driver: Register Address and Register Mask values for
+ * Octeon CN66XX devices.
+ */
+
+#ifndef __CN66XX_REGS_H__
+#define __CN66XX_REGS_H__
+
+#define CN6XXX_XPANSION_BAR 0x30
+
+#define CN6XXX_MSI_CAP 0x50
+#define CN6XXX_MSI_ADDR_LO 0x54
+#define CN6XXX_MSI_ADDR_HI 0x58
+#define CN6XXX_MSI_DATA 0x5C
+
+#define CN6XXX_PCIE_CAP 0x70
+#define CN6XXX_PCIE_DEVCAP 0x74
+#define CN6XXX_PCIE_DEVCTL 0x78
+#define CN6XXX_PCIE_LINKCAP 0x7C
+#define CN6XXX_PCIE_LINKCTL 0x80
+#define CN6XXX_PCIE_SLOTCAP 0x84
+#define CN6XXX_PCIE_SLOTCTL 0x88
+
+#define CN6XXX_PCIE_ENH_CAP 0x100
+#define CN6XXX_PCIE_UNCORR_ERR_STATUS 0x104
+#define CN6XXX_PCIE_UNCORR_ERR_MASK 0x108
+#define CN6XXX_PCIE_UNCORR_ERR 0x10C
+#define CN6XXX_PCIE_CORR_ERR_STATUS 0x110
+#define CN6XXX_PCIE_CORR_ERR_MASK 0x114
+#define CN6XXX_PCIE_ADV_ERR_CAP 0x118
+
+#define CN6XXX_PCIE_ACK_REPLAY_TIMER 0x700
+#define CN6XXX_PCIE_OTHER_MSG 0x704
+#define CN6XXX_PCIE_PORT_FORCE_LINK 0x708
+#define CN6XXX_PCIE_ACK_FREQ 0x70C
+#define CN6XXX_PCIE_PORT_LINK_CTL 0x710
+#define CN6XXX_PCIE_LANE_SKEW 0x714
+#define CN6XXX_PCIE_SYM_NUM 0x718
+#define CN6XXX_PCIE_FLTMSK 0x720
+
+/* ############## BAR0 Registers ################ */
+
+#define CN6XXX_SLI_CTL_PORT0 0x0050
+#define CN6XXX_SLI_CTL_PORT1 0x0060
+
+#define CN6XXX_SLI_WINDOW_CTL 0x02E0
+#define CN6XXX_SLI_DBG_DATA 0x0310
+#define CN6XXX_SLI_SCRATCH1 0x03C0
+#define CN6XXX_SLI_SCRATCH2 0x03D0
+#define CN6XXX_SLI_CTL_STATUS 0x0570
+
+#define CN6XXX_WIN_WR_ADDR_LO 0x0000
+#define CN6XXX_WIN_WR_ADDR_HI 0x0004
+#define CN6XXX_WIN_WR_ADDR64 CN6XXX_WIN_WR_ADDR_LO
+
+#define CN6XXX_WIN_RD_ADDR_LO 0x0010
+#define CN6XXX_WIN_RD_ADDR_HI 0x0014
+#define CN6XXX_WIN_RD_ADDR64 CN6XXX_WIN_RD_ADDR_LO
+
+#define CN6XXX_WIN_WR_DATA_LO 0x0020
+#define CN6XXX_WIN_WR_DATA_HI 0x0024
+#define CN6XXX_WIN_WR_DATA64 CN6XXX_WIN_WR_DATA_LO
+
+#define CN6XXX_WIN_RD_DATA_LO 0x0040
+#define CN6XXX_WIN_RD_DATA_HI 0x0044
+#define CN6XXX_WIN_RD_DATA64 CN6XXX_WIN_RD_DATA_LO
+
+#define CN6XXX_WIN_WR_MASK_LO 0x0030
+#define CN6XXX_WIN_WR_MASK_HI 0x0034
+#define CN6XXX_WIN_WR_MASK_REG CN6XXX_WIN_WR_MASK_LO
+
+/* 1 register (32-bit) to enable Input queues */
+#define CN6XXX_SLI_PKT_INSTR_ENB 0x1000
+
+/* 1 register (32-bit) to enable Output queues */
+#define CN6XXX_SLI_PKT_OUT_ENB 0x1010
+
+/* 1 register (32-bit) to determine whether Output queues are in reset. */
+#define CN6XXX_SLI_PORT_IN_RST_OQ 0x11F0
+
+/* 1 register (32-bit) to determine whether Input queues are in reset. */
+#define CN6XXX_SLI_PORT_IN_RST_IQ 0x11F4
+
+/*###################### REQUEST QUEUE #########################*/
+
+/* 1 register (32-bit) - instr. size of each input queue. */
+#define CN6XXX_SLI_PKT_INSTR_SIZE 0x1020
+
+/* 32 registers for Input Queue Instr Count - SLI_PKT_IN_DONE0_CNTS */
+#define CN6XXX_SLI_IQ_INSTR_COUNT_START 0x2000
+
+/* 32 registers for Input Queue Start Addr - SLI_PKT0_INSTR_BADDR */
+#define CN6XXX_SLI_IQ_BASE_ADDR_START64 0x2800
+
+/* 32 registers for Input Doorbell - SLI_PKT0_INSTR_BAOFF_DBELL */
+#define CN6XXX_SLI_IQ_DOORBELL_START 0x2C00
+
+/* 32 registers for Input Queue size - SLI_PKT0_INSTR_FIFO_RSIZE */
+#define CN6XXX_SLI_IQ_SIZE_START 0x3000
+
+/* 32 registers for Instruction Header Options - SLI_PKT0_INSTR_HEADER */
+#define CN6XXX_SLI_IQ_PKT_INSTR_HDR_START64 0x3400
+
+/* 1 register (64-bit) - Back Pressure for each input queue - SLI_PKT0_IN_BP */
+#define CN66XX_SLI_INPUT_BP_START64 0x3800
+
+/* Each Input Queue register is at a 16-byte Offset in BAR0 */
+#define CN6XXX_IQ_OFFSET 0x10
+
+/* 1 register (32-bit) - ES, RO, NS, Arbitration for Input Queue Data &
+ * gather list fetches. SLI_PKT_INPUT_CONTROL.
+ */
+#define CN6XXX_SLI_PKT_INPUT_CONTROL 0x1170
+
+/* 1 register (64-bit) - Number of instructions to read at one time
+ * - 2 bits for each input ring. SLI_PKT_INSTR_RD_SIZE.
+ */
+#define CN6XXX_SLI_PKT_INSTR_RD_SIZE 0x11A0
+
+/* 1 register (64-bit) - Assign Input ring to MAC port
+ * - 2 bits for each input ring. SLI_PKT_IN_PCIE_PORT.
+ */
+#define CN6XXX_SLI_IN_PCIE_PORT 0x11B0
+
+/*------- Request Queue Macros ---------*/
+#define CN6XXX_SLI_IQ_BASE_ADDR64(iq) \
+ (CN6XXX_SLI_IQ_BASE_ADDR_START64 + ((iq) * CN6XXX_IQ_OFFSET))
+
+#define CN6XXX_SLI_IQ_SIZE(iq) \
+ (CN6XXX_SLI_IQ_SIZE_START + ((iq) * CN6XXX_IQ_OFFSET))
+
+#define CN6XXX_SLI_IQ_PKT_INSTR_HDR64(iq) \
+ (CN6XXX_SLI_IQ_PKT_INSTR_HDR_START64 + ((iq) * CN6XXX_IQ_OFFSET))
+
+#define CN6XXX_SLI_IQ_DOORBELL(iq) \
+ (CN6XXX_SLI_IQ_DOORBELL_START + ((iq) * CN6XXX_IQ_OFFSET))
+
+#define CN6XXX_SLI_IQ_INSTR_COUNT(iq) \
+ (CN6XXX_SLI_IQ_INSTR_COUNT_START + ((iq) * CN6XXX_IQ_OFFSET))
+
+#define CN66XX_SLI_IQ_BP64(iq) \
+ (CN66XX_SLI_INPUT_BP_START64 + ((iq) * CN6XXX_IQ_OFFSET))
+
+/*------------------ Masks ----------------*/
+#define CN6XXX_INPUT_CTL_ROUND_ROBIN_ARB BIT(22)
+#define CN6XXX_INPUT_CTL_DATA_NS BIT(8)
+#define CN6XXX_INPUT_CTL_DATA_ES_64B_SWAP BIT(6)
+#define CN6XXX_INPUT_CTL_DATA_RO BIT(5)
+#define CN6XXX_INPUT_CTL_USE_CSR BIT(4)
+#define CN6XXX_INPUT_CTL_GATHER_NS BIT(3)
+#define CN6XXX_INPUT_CTL_GATHER_ES_64B_SWAP BIT(2)
+#define CN6XXX_INPUT_CTL_GATHER_RO BIT(1)
+
+#ifdef __BIG_ENDIAN_BITFIELD
+#define CN6XXX_INPUT_CTL_MASK \
+ (CN6XXX_INPUT_CTL_DATA_ES_64B_SWAP \
+ | CN6XXX_INPUT_CTL_USE_CSR \
+ | CN6XXX_INPUT_CTL_GATHER_ES_64B_SWAP)
+#else
+#define CN6XXX_INPUT_CTL_MASK \
+ (CN6XXX_INPUT_CTL_DATA_ES_64B_SWAP \
+ | CN6XXX_INPUT_CTL_USE_CSR)
+#endif
+
+/*############################ OUTPUT QUEUE #########################*/
+
+/* 32 registers for Output queue buffer and info size - SLI_PKT0_OUT_SIZE */
+#define CN6XXX_SLI_OQ0_BUFF_INFO_SIZE 0x0C00
+
+/* 32 registers for Output Queue Start Addr - SLI_PKT0_SLIST_BADDR */
+#define CN6XXX_SLI_OQ_BASE_ADDR_START64 0x1400
+
+/* 32 registers for Output Queue Packet Credits - SLI_PKT0_SLIST_BAOFF_DBELL */
+#define CN6XXX_SLI_OQ_PKT_CREDITS_START 0x1800
+
+/* 32 registers for Output Queue size - SLI_PKT0_SLIST_FIFO_RSIZE */
+#define CN6XXX_SLI_OQ_SIZE_START 0x1C00
+
+/* 32 registers for Output Queue Packet Count - SLI_PKT0_CNTS */
+#define CN6XXX_SLI_OQ_PKT_SENT_START 0x2400
+
+/* Each Output Queue register is at a 16-byte Offset in BAR0 */
+#define CN6XXX_OQ_OFFSET 0x10
+
+/* 1 register (32-bit) - 1 bit for each output queue
+ * - Relaxed Ordering setting for reading Output Queues descriptors
+ * - SLI_PKT_SLIST_ROR
+ */
+#define CN6XXX_SLI_PKT_SLIST_ROR 0x1030
+
+/* 1 register (32-bit) - 1 bit for each output queue
+ * - No Snoop mode for reading Output Queues descriptors
+ * - SLI_PKT_SLIST_NS
+ */
+#define CN6XXX_SLI_PKT_SLIST_NS 0x1040
+
+/* 1 register (64-bit) - 2 bits for each output queue
+ * - Endian-Swap mode for reading Output Queue descriptors
+ * - SLI_PKT_SLIST_ES
+ */
+#define CN6XXX_SLI_PKT_SLIST_ES64 0x1050
+
+/* 1 register (32-bit) - 1 bit for each output queue
+ * - InfoPtr mode for Output Queues.
+ * - SLI_PKT_IPTR
+ */
+#define CN6XXX_SLI_PKT_IPTR 0x1070
+
+/* 1 register (32-bit) - 1 bit for each output queue
+ * - DPTR format selector for Output queues.
+ * - SLI_PKT_DPADDR
+ */
+#define CN6XXX_SLI_PKT_DPADDR 0x1080
+
+/* 1 register (32-bit) - 1 bit for each output queue
+ * - Relaxed Ordering setting for reading Output Queues data
+ * - SLI_PKT_DATA_OUT_ROR
+ */
+#define CN6XXX_SLI_PKT_DATA_OUT_ROR 0x1090
+
+/* 1 register (32-bit) - 1 bit for each output queue
+ * - No Snoop mode for reading Output Queues data
+ * - SLI_PKT_DATA_OUT_NS
+ */
+#define CN6XXX_SLI_PKT_DATA_OUT_NS 0x10A0
+
+/* 1 register (64-bit) - 2 bits for each output queue
+ * - Endian-Swap mode for reading Output Queue data
+ * - SLI_PKT_DATA_OUT_ES
+ */
+#define CN6XXX_SLI_PKT_DATA_OUT_ES64 0x10B0
+
+/* 1 register (32-bit) - 1 bit for each output queue
+ * - Controls whether SLI_PKTn_CNTS is incremented for bytes or for packets.
+ * - SLI_PKT_OUT_BMODE
+ */
+#define CN6XXX_SLI_PKT_OUT_BMODE 0x10D0
+
+/* 1 register (64-bit) - 2 bits for each output queue
+ * - Assign PCIE port for Output queues
+ * - SLI_PKT_PCIE_PORT.
+ */
+#define CN6XXX_SLI_PKT_PCIE_PORT64 0x10E0
+
+/* 1 (64-bit) register for Output Queue Packet Count Interrupt Threshold
+ * & Time Threshold. The same setting applies to all 32 queues.
+ * The register is defined as a 64-bit registers, but we use the
+ * 32-bit offsets to define distinct addresses.
+ */
+#define CN6XXX_SLI_OQ_INT_LEVEL_PKTS 0x1120
+#define CN6XXX_SLI_OQ_INT_LEVEL_TIME 0x1124
+
+/* 1 (64-bit register) for Output Queue backpressure across all rings. */
+#define CN6XXX_SLI_OQ_WMARK 0x1180
+
+/* 1 register to control output queue global backpressure & ring enable. */
+#define CN6XXX_SLI_PKT_CTL 0x1220
+
+/*------- Output Queue Macros ---------*/
+#define CN6XXX_SLI_OQ_BASE_ADDR64(oq) \
+ (CN6XXX_SLI_OQ_BASE_ADDR_START64 + ((oq) * CN6XXX_OQ_OFFSET))
+
+#define CN6XXX_SLI_OQ_SIZE(oq) \
+ (CN6XXX_SLI_OQ_SIZE_START + ((oq) * CN6XXX_OQ_OFFSET))
+
+#define CN6XXX_SLI_OQ_BUFF_INFO_SIZE(oq) \
+ (CN6XXX_SLI_OQ0_BUFF_INFO_SIZE + ((oq) * CN6XXX_OQ_OFFSET))
+
+#define CN6XXX_SLI_OQ_PKTS_SENT(oq) \
+ (CN6XXX_SLI_OQ_PKT_SENT_START + ((oq) * CN6XXX_OQ_OFFSET))
+
+#define CN6XXX_SLI_OQ_PKTS_CREDIT(oq) \
+ (CN6XXX_SLI_OQ_PKT_CREDITS_START + ((oq) * CN6XXX_OQ_OFFSET))
+
+/*######################### DMA Counters #########################*/
+
+/* 2 registers (64-bit) - DMA Count - 1 for each DMA counter 0/1. */
+#define CN6XXX_DMA_CNT_START 0x0400
+
+/* 2 registers (64-bit) - DMA Timer 0/1, contains DMA timer values
+ * SLI_DMA_0_TIM
+ */
+#define CN6XXX_DMA_TIM_START 0x0420
+
+/* 2 registers (64-bit) - DMA count & Time Interrupt threshold -
+ * SLI_DMA_0_INT_LEVEL
+ */
+#define CN6XXX_DMA_INT_LEVEL_START 0x03E0
+
+/* Each DMA register is at a 16-byte Offset in BAR0 */
+#define CN6XXX_DMA_OFFSET 0x10
+
+/*---------- DMA Counter Macros ---------*/
+#define CN6XXX_DMA_CNT(dq) \
+ (CN6XXX_DMA_CNT_START + ((dq) * CN6XXX_DMA_OFFSET))
+
+#define CN6XXX_DMA_INT_LEVEL(dq) \
+ (CN6XXX_DMA_INT_LEVEL_START + ((dq) * CN6XXX_DMA_OFFSET))
+
+#define CN6XXX_DMA_PKT_INT_LEVEL(dq) \
+ (CN6XXX_DMA_INT_LEVEL_START + ((dq) * CN6XXX_DMA_OFFSET))
+
+#define CN6XXX_DMA_TIME_INT_LEVEL(dq) \
+ (CN6XXX_DMA_INT_LEVEL_START + 4 + ((dq) * CN6XXX_DMA_OFFSET))
+
+#define CN6XXX_DMA_TIM(dq) \
+ (CN6XXX_DMA_TIM_START + ((dq) * CN6XXX_DMA_OFFSET))
+
+/*######################## INTERRUPTS #########################*/
+
+/* 1 register (64-bit) for Interrupt Summary */
+#define CN6XXX_SLI_INT_SUM64 0x0330
+
+/* 1 register (64-bit) for Interrupt Enable */
+#define CN6XXX_SLI_INT_ENB64_PORT0 0x0340
+#define CN6XXX_SLI_INT_ENB64_PORT1 0x0350
+
+/* 1 register (32-bit) to enable Output Queue Packet/Byte Count Interrupt */
+#define CN6XXX_SLI_PKT_CNT_INT_ENB 0x1150
+
+/* 1 register (32-bit) to enable Output Queue Packet Timer Interrupt */
+#define CN6XXX_SLI_PKT_TIME_INT_ENB 0x1160
+
+/* 1 register (32-bit) to indicate which Output Queue reached pkt threshold */
+#define CN6XXX_SLI_PKT_CNT_INT 0x1130
+
+/* 1 register (32-bit) to indicate which Output Queue reached time threshold */
+#define CN6XXX_SLI_PKT_TIME_INT 0x1140
+
+/*------------------ Interrupt Masks ----------------*/
+
+#define CN6XXX_INTR_RML_TIMEOUT_ERR BIT(1)
+#define CN6XXX_INTR_BAR0_RW_TIMEOUT_ERR BIT(2)
+#define CN6XXX_INTR_IO2BIG_ERR BIT(3)
+#define CN6XXX_INTR_PKT_COUNT BIT(4)
+#define CN6XXX_INTR_PKT_TIME BIT(5)
+#define CN6XXX_INTR_M0UPB0_ERR BIT(8)
+#define CN6XXX_INTR_M0UPWI_ERR BIT(9)
+#define CN6XXX_INTR_M0UNB0_ERR BIT(10)
+#define CN6XXX_INTR_M0UNWI_ERR BIT(11)
+#define CN6XXX_INTR_M1UPB0_ERR BIT(12)
+#define CN6XXX_INTR_M1UPWI_ERR BIT(13)
+#define CN6XXX_INTR_M1UNB0_ERR BIT(14)
+#define CN6XXX_INTR_M1UNWI_ERR BIT(15)
+#define CN6XXX_INTR_MIO_INT0 BIT(16)
+#define CN6XXX_INTR_MIO_INT1 BIT(17)
+#define CN6XXX_INTR_MAC_INT0 BIT(18)
+#define CN6XXX_INTR_MAC_INT1 BIT(19)
+
+#define CN6XXX_INTR_DMA0_FORCE BIT_ULL(32)
+#define CN6XXX_INTR_DMA1_FORCE BIT_ULL(33)
+#define CN6XXX_INTR_DMA0_COUNT BIT_ULL(34)
+#define CN6XXX_INTR_DMA1_COUNT BIT_ULL(35)
+#define CN6XXX_INTR_DMA0_TIME BIT_ULL(36)
+#define CN6XXX_INTR_DMA1_TIME BIT_ULL(37)
+#define CN6XXX_INTR_INSTR_DB_OF_ERR BIT_ULL(48)
+#define CN6XXX_INTR_SLIST_DB_OF_ERR BIT_ULL(49)
+#define CN6XXX_INTR_POUT_ERR BIT_ULL(50)
+#define CN6XXX_INTR_PIN_BP_ERR BIT_ULL(51)
+#define CN6XXX_INTR_PGL_ERR BIT_ULL(52)
+#define CN6XXX_INTR_PDI_ERR BIT_ULL(53)
+#define CN6XXX_INTR_POP_ERR BIT_ULL(54)
+#define CN6XXX_INTR_PINS_ERR BIT_ULL(55)
+#define CN6XXX_INTR_SPRT0_ERR BIT_ULL(56)
+#define CN6XXX_INTR_SPRT1_ERR BIT_ULL(57)
+#define CN6XXX_INTR_ILL_PAD_ERR BIT_ULL(60)
+
+#define CN6XXX_INTR_DMA0_DATA (CN6XXX_INTR_DMA0_TIME)
+
+#define CN6XXX_INTR_DMA1_DATA (CN6XXX_INTR_DMA1_TIME)
+
+#define CN6XXX_INTR_DMA_DATA \
+ (CN6XXX_INTR_DMA0_DATA | CN6XXX_INTR_DMA1_DATA)
+
+#define CN6XXX_INTR_PKT_DATA (CN6XXX_INTR_PKT_TIME | \
+ CN6XXX_INTR_PKT_COUNT)
+
+/* Sum of interrupts for all PCI-Express Data Interrupts */
+#define CN6XXX_INTR_PCIE_DATA \
+ (CN6XXX_INTR_DMA_DATA | CN6XXX_INTR_PKT_DATA)
+
+#define CN6XXX_INTR_MIO \
+ (CN6XXX_INTR_MIO_INT0 | CN6XXX_INTR_MIO_INT1)
+
+#define CN6XXX_INTR_MAC \
+ (CN6XXX_INTR_MAC_INT0 | CN6XXX_INTR_MAC_INT1)
+
+/* Sum of interrupts for error events */
+#define CN6XXX_INTR_ERR \
+ (CN6XXX_INTR_BAR0_RW_TIMEOUT_ERR \
+ | CN6XXX_INTR_IO2BIG_ERR \
+ | CN6XXX_INTR_M0UPB0_ERR \
+ | CN6XXX_INTR_M0UPWI_ERR \
+ | CN6XXX_INTR_M0UNB0_ERR \
+ | CN6XXX_INTR_M0UNWI_ERR \
+ | CN6XXX_INTR_M1UPB0_ERR \
+ | CN6XXX_INTR_M1UPWI_ERR \
+ | CN6XXX_INTR_M1UPB0_ERR \
+ | CN6XXX_INTR_M1UNWI_ERR \
+ | CN6XXX_INTR_INSTR_DB_OF_ERR \
+ | CN6XXX_INTR_SLIST_DB_OF_ERR \
+ | CN6XXX_INTR_POUT_ERR \
+ | CN6XXX_INTR_PIN_BP_ERR \
+ | CN6XXX_INTR_PGL_ERR \
+ | CN6XXX_INTR_PDI_ERR \
+ | CN6XXX_INTR_POP_ERR \
+ | CN6XXX_INTR_PINS_ERR \
+ | CN6XXX_INTR_SPRT0_ERR \
+ | CN6XXX_INTR_SPRT1_ERR \
+ | CN6XXX_INTR_ILL_PAD_ERR)
+
+/* Programmed Mask for Interrupt Sum */
+#define CN6XXX_INTR_MASK \
+ (CN6XXX_INTR_PCIE_DATA \
+ | CN6XXX_INTR_DMA0_FORCE \
+ | CN6XXX_INTR_DMA1_FORCE \
+ | CN6XXX_INTR_MIO \
+ | CN6XXX_INTR_MAC \
+ | CN6XXX_INTR_ERR)
+
+#define CN6XXX_SLI_S2M_PORT0_CTL 0x3D80
+#define CN6XXX_SLI_S2M_PORT1_CTL 0x3D90
+#define CN6XXX_SLI_S2M_PORTX_CTL(port) \
+ (CN6XXX_SLI_S2M_PORT0_CTL + (port * 0x10))
+
+#define CN6XXX_SLI_INT_ENB64(port) \
+ (CN6XXX_SLI_INT_ENB64_PORT0 + (port * 0x10))
+
+#define CN6XXX_SLI_MAC_NUMBER 0x3E00
+
+/* CN6XXX BAR1 Index registers. */
+#define CN6XXX_PEM_BAR1_INDEX000 0x00011800C00000A8ULL
+#define CN6XXX_PEM_OFFSET 0x0000000001000000ULL
+
+#define CN6XXX_BAR1_INDEX_START CN6XXX_PEM_BAR1_INDEX000
+#define CN6XXX_PCI_BAR1_OFFSET 0x8
+
+#define CN6XXX_BAR1_REG(idx, port) \
+ (CN6XXX_BAR1_INDEX_START + (port * CN6XXX_PEM_OFFSET) + \
+ (CN6XXX_PCI_BAR1_OFFSET * (idx)))
+
+/*############################ DPI #########################*/
+
+#define CN6XXX_DPI_CTL 0x0001df0000000040ULL
+
+#define CN6XXX_DPI_DMA_CONTROL 0x0001df0000000048ULL
+
+#define CN6XXX_DPI_REQ_GBL_ENB 0x0001df0000000050ULL
+
+#define CN6XXX_DPI_REQ_ERR_RSP 0x0001df0000000058ULL
+
+#define CN6XXX_DPI_REQ_ERR_RST 0x0001df0000000060ULL
+
+#define CN6XXX_DPI_DMA_ENG0_ENB 0x0001df0000000080ULL
+
+#define CN6XXX_DPI_DMA_ENG_ENB(q_no) \
+ (CN6XXX_DPI_DMA_ENG0_ENB + (q_no * 8))
+
+#define CN6XXX_DPI_DMA_ENG0_BUF 0x0001df0000000880ULL
+
+#define CN6XXX_DPI_DMA_ENG_BUF(q_no) \
+ (CN6XXX_DPI_DMA_ENG0_BUF + (q_no * 8))
+
+#define CN6XXX_DPI_SLI_PRT0_CFG 0x0001df0000000900ULL
+#define CN6XXX_DPI_SLI_PRT1_CFG 0x0001df0000000908ULL
+#define CN6XXX_DPI_SLI_PRTX_CFG(port) \
+ (CN6XXX_DPI_SLI_PRT0_CFG + (port * 0x10))
+
+#define CN6XXX_DPI_DMA_COMMIT_MODE BIT_ULL(58)
+#define CN6XXX_DPI_DMA_PKT_HP BIT_ULL(57)
+#define CN6XXX_DPI_DMA_PKT_EN BIT_ULL(56)
+#define CN6XXX_DPI_DMA_O_ES BIT_ULL(15)
+#define CN6XXX_DPI_DMA_O_MODE BIT_ULL(14)
+
+#define CN6XXX_DPI_DMA_CTL_MASK \
+ (CN6XXX_DPI_DMA_COMMIT_MODE | \
+ CN6XXX_DPI_DMA_PKT_HP | \
+ CN6XXX_DPI_DMA_PKT_EN | \
+ CN6XXX_DPI_DMA_O_ES | \
+ CN6XXX_DPI_DMA_O_MODE)
+
+/*############################ CIU #########################*/
+
+#define CN6XXX_CIU_SOFT_BIST 0x0001070000000738ULL
+#define CN6XXX_CIU_SOFT_RST 0x0001070000000740ULL
+
+/*############################ MIO #########################*/
+#define CN6XXX_MIO_PTP_CLOCK_CFG 0x0001070000000f00ULL
+#define CN6XXX_MIO_PTP_CLOCK_LO 0x0001070000000f08ULL
+#define CN6XXX_MIO_PTP_CLOCK_HI 0x0001070000000f10ULL
+#define CN6XXX_MIO_PTP_CLOCK_COMP 0x0001070000000f18ULL
+#define CN6XXX_MIO_PTP_TIMESTAMP 0x0001070000000f20ULL
+#define CN6XXX_MIO_PTP_EVT_CNT 0x0001070000000f28ULL
+#define CN6XXX_MIO_PTP_CKOUT_THRESH_LO 0x0001070000000f30ULL
+#define CN6XXX_MIO_PTP_CKOUT_THRESH_HI 0x0001070000000f38ULL
+#define CN6XXX_MIO_PTP_CKOUT_HI_INCR 0x0001070000000f40ULL
+#define CN6XXX_MIO_PTP_CKOUT_LO_INCR 0x0001070000000f48ULL
+#define CN6XXX_MIO_PTP_PPS_THRESH_LO 0x0001070000000f50ULL
+#define CN6XXX_MIO_PTP_PPS_THRESH_HI 0x0001070000000f58ULL
+#define CN6XXX_MIO_PTP_PPS_HI_INCR 0x0001070000000f60ULL
+#define CN6XXX_MIO_PTP_PPS_LO_INCR 0x0001070000000f68ULL
+
+#define CN6XXX_MIO_QLM4_CFG 0x00011800000015B0ULL
+#define CN6XXX_MIO_RST_BOOT 0x0001180000001600ULL
+
+#define CN6XXX_MIO_QLM_CFG_MASK 0x7
+
+/*############################ LMC #########################*/
+
+#define CN6XXX_LMC0_RESET_CTL 0x0001180088000180ULL
+#define CN6XXX_LMC0_RESET_CTL_DDR3RST_MASK 0x0000000000000001ULL
+
+#endif
diff --git a/drivers/net/ethernet/cavium/liquidio/cn68xx_device.c b/drivers/net/ethernet/cavium/liquidio/cn68xx_device.c
new file mode 100644
index 000000000000..8e830d0c0754
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/cn68xx_device.c
@@ -0,0 +1,198 @@
+/**********************************************************************
+* Author: Cavium, Inc.
+*
+* Contact: support@cavium.com
+* Please include "LiquidIO" in the subject.
+*
+* Copyright (c) 2003-2015 Cavium, Inc.
+*
+* This file 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 file is distributed in the hope that it will be useful, but
+* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+* NONINFRINGEMENT. See the GNU General Public License for more
+* details.
+*
+* This file may also be available under a different license from Cavium.
+* Contact Cavium, Inc. for more information
+**********************************************************************/
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include "octeon_config.h"
+#include "liquidio_common.h"
+#include "octeon_droq.h"
+#include "octeon_iq.h"
+#include "response_manager.h"
+#include "octeon_device.h"
+#include "octeon_nic.h"
+#include "octeon_main.h"
+#include "octeon_network.h"
+#include "cn66xx_regs.h"
+#include "cn66xx_device.h"
+#include "cn68xx_regs.h"
+#include "cn68xx_device.h"
+#include "liquidio_image.h"
+#include "octeon_mem_ops.h"
+
+static void lio_cn68xx_set_dpi_regs(struct octeon_device *oct)
+{
+ u32 i;
+ u32 fifo_sizes[6] = { 3, 3, 1, 1, 1, 8 };
+
+ lio_pci_writeq(oct, CN6XXX_DPI_DMA_CTL_MASK, CN6XXX_DPI_DMA_CONTROL);
+ dev_dbg(&oct->pci_dev->dev, "DPI_DMA_CONTROL: 0x%016llx\n",
+ lio_pci_readq(oct, CN6XXX_DPI_DMA_CONTROL));
+
+ for (i = 0; i < 6; i++) {
+ /* Prevent service of instruction queue for all DMA engines
+ * Engine 5 will remain 0. Engines 0 - 4 will be setup by
+ * core.
+ */
+ lio_pci_writeq(oct, 0, CN6XXX_DPI_DMA_ENG_ENB(i));
+ lio_pci_writeq(oct, fifo_sizes[i], CN6XXX_DPI_DMA_ENG_BUF(i));
+ dev_dbg(&oct->pci_dev->dev, "DPI_ENG_BUF%d: 0x%016llx\n", i,
+ lio_pci_readq(oct, CN6XXX_DPI_DMA_ENG_BUF(i)));
+ }
+
+ /* DPI_SLI_PRT_CFG has MPS and MRRS settings that will be set
+ * separately.
+ */
+
+ lio_pci_writeq(oct, 1, CN6XXX_DPI_CTL);
+ dev_dbg(&oct->pci_dev->dev, "DPI_CTL: 0x%016llx\n",
+ lio_pci_readq(oct, CN6XXX_DPI_CTL));
+}
+
+static int lio_cn68xx_soft_reset(struct octeon_device *oct)
+{
+ lio_cn6xxx_soft_reset(oct);
+ lio_cn68xx_set_dpi_regs(oct);
+
+ return 0;
+}
+
+static void lio_cn68xx_setup_pkt_ctl_regs(struct octeon_device *oct)
+{
+ struct octeon_cn6xxx *cn68xx = (struct octeon_cn6xxx *)oct->chip;
+ u64 pktctl, tx_pipe, max_oqs;
+
+ pktctl = octeon_read_csr64(oct, CN6XXX_SLI_PKT_CTL);
+
+ /* 68XX specific */
+ max_oqs = CFG_GET_OQ_MAX_Q(CHIP_FIELD(oct, cn6xxx, conf));
+ tx_pipe = octeon_read_csr64(oct, CN68XX_SLI_TX_PIPE);
+ tx_pipe &= 0xffffffffff00ffffULL; /* clear out NUMP field */
+ tx_pipe |= max_oqs << 16; /* put max_oqs in NUMP field */
+ octeon_write_csr64(oct, CN68XX_SLI_TX_PIPE, tx_pipe);
+
+ if (CFG_GET_IS_SLI_BP_ON(cn68xx->conf))
+ pktctl |= 0xF;
+ else
+ /* Disable per-port backpressure. */
+ pktctl &= ~0xF;
+ octeon_write_csr64(oct, CN6XXX_SLI_PKT_CTL, pktctl);
+}
+
+static int lio_cn68xx_setup_device_regs(struct octeon_device *oct)
+{
+ lio_cn6xxx_setup_pcie_mps(oct, PCIE_MPS_DEFAULT);
+ lio_cn6xxx_setup_pcie_mrrs(oct, PCIE_MRRS_256B);
+ lio_cn6xxx_enable_error_reporting(oct);
+
+ lio_cn6xxx_setup_global_input_regs(oct);
+ lio_cn68xx_setup_pkt_ctl_regs(oct);
+ lio_cn6xxx_setup_global_output_regs(oct);
+
+ /* Default error timeout value should be 0x200000 to avoid host hang
+ * when reads invalid register
+ */
+ octeon_write_csr64(oct, CN6XXX_SLI_WINDOW_CTL, 0x200000ULL);
+
+ return 0;
+}
+
+static inline void lio_cn68xx_vendor_message_fix(struct octeon_device *oct)
+{
+ u32 val = 0;
+
+ /* Set M_VEND1_DRP and M_VEND0_DRP bits */
+ pci_read_config_dword(oct->pci_dev, CN6XXX_PCIE_FLTMSK, &val);
+ val |= 0x3;
+ pci_write_config_dword(oct->pci_dev, CN6XXX_PCIE_FLTMSK, val);
+}
+
+int lio_is_210nv(struct octeon_device *oct)
+{
+ u64 mio_qlm4_cfg = lio_pci_readq(oct, CN6XXX_MIO_QLM4_CFG);
+
+ return ((mio_qlm4_cfg & CN6XXX_MIO_QLM_CFG_MASK) == 0);
+}
+
+int lio_setup_cn68xx_octeon_device(struct octeon_device *oct)
+{
+ struct octeon_cn6xxx *cn68xx = (struct octeon_cn6xxx *)oct->chip;
+ u16 card_type = LIO_410NV;
+
+ if (octeon_map_pci_barx(oct, 0, 0))
+ return 1;
+
+ if (octeon_map_pci_barx(oct, 1, MAX_BAR1_IOREMAP_SIZE)) {
+ dev_err(&oct->pci_dev->dev, "%s CN68XX BAR1 map failed\n",
+ __func__);
+ octeon_unmap_pci_barx(oct, 0);
+ return 1;
+ }
+
+ spin_lock_init(&cn68xx->lock_for_droq_int_enb_reg);
+
+ oct->fn_list.setup_iq_regs = lio_cn6xxx_setup_iq_regs;
+ oct->fn_list.setup_oq_regs = lio_cn6xxx_setup_oq_regs;
+
+ oct->fn_list.process_interrupt_regs = lio_cn6xxx_process_interrupt_regs;
+ oct->fn_list.soft_reset = lio_cn68xx_soft_reset;
+ oct->fn_list.setup_device_regs = lio_cn68xx_setup_device_regs;
+ oct->fn_list.reinit_regs = lio_cn6xxx_reinit_regs;
+ oct->fn_list.update_iq_read_idx = lio_cn6xxx_update_read_index;
+
+ oct->fn_list.bar1_idx_setup = lio_cn6xxx_bar1_idx_setup;
+ oct->fn_list.bar1_idx_write = lio_cn6xxx_bar1_idx_write;
+ oct->fn_list.bar1_idx_read = lio_cn6xxx_bar1_idx_read;
+
+ oct->fn_list.enable_interrupt = lio_cn6xxx_enable_interrupt;
+ oct->fn_list.disable_interrupt = lio_cn6xxx_disable_interrupt;
+
+ oct->fn_list.enable_io_queues = lio_cn6xxx_enable_io_queues;
+ oct->fn_list.disable_io_queues = lio_cn6xxx_disable_io_queues;
+
+ lio_cn6xxx_setup_reg_address(oct, oct->chip, &oct->reg_list);
+
+ /* Determine variant of card */
+ if (lio_is_210nv(oct))
+ card_type = LIO_210NV;
+
+ cn68xx->conf = (struct octeon_config *)
+ oct_get_config_info(oct, card_type);
+ if (!cn68xx->conf) {
+ dev_err(&oct->pci_dev->dev, "%s No Config found for CN68XX %s\n",
+ __func__,
+ (card_type == LIO_410NV) ? LIO_410NV_NAME :
+ LIO_210NV_NAME);
+ octeon_unmap_pci_barx(oct, 0);
+ octeon_unmap_pci_barx(oct, 1);
+ return 1;
+ }
+
+ oct->coproc_clock_rate = 1000000ULL * lio_cn6xxx_coprocessor_clock(oct);
+
+ lio_cn68xx_vendor_message_fix(oct);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/cavium/liquidio/cn68xx_device.h b/drivers/net/ethernet/cavium/liquidio/cn68xx_device.h
new file mode 100644
index 000000000000..d4e1c9fb0bf2
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/cn68xx_device.h
@@ -0,0 +1,33 @@
+/**********************************************************************
+* Author: Cavium, Inc.
+*
+* Contact: support@cavium.com
+* Please include "LiquidIO" in the subject.
+*
+* Copyright (c) 2003-2015 Cavium, Inc.
+*
+* This file 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 file is distributed in the hope that it will be useful, but
+* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+* NONINFRINGEMENT. See the GNU General Public License for more
+* details.
+*
+* This file may also be available under a different license from Cavium.
+* Contact Cavium, Inc. for more information
+**********************************************************************/
+
+/*! \file cn68xx_device.h
+ * \brief Host Driver: Routines that perform CN68XX specific operations.
+ */
+
+#ifndef __CN68XX_DEVICE_H__
+#define __CN68XX_DEVICE_H__
+
+int lio_setup_cn68xx_octeon_device(struct octeon_device *oct);
+int lio_is_210nv(struct octeon_device *oct);
+
+#endif
diff --git a/drivers/net/ethernet/cavium/liquidio/cn68xx_regs.h b/drivers/net/ethernet/cavium/liquidio/cn68xx_regs.h
new file mode 100644
index 000000000000..38cddbd107b6
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/cn68xx_regs.h
@@ -0,0 +1,51 @@
+/**********************************************************************
+* Author: Cavium, Inc.
+*
+* Contact: support@cavium.com
+* Please include "LiquidIO" in the subject.
+*
+* Copyright (c) 2003-2015 Cavium, Inc.
+*
+* This file 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 file is distributed in the hope that it will be useful, but
+* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+* NONINFRINGEMENT. See the GNU General Public License for more
+* details.
+*
+* This file may also be available under a different license from Cavium.
+* Contact Cavium, Inc. for more information
+**********************************************************************/
+
+/*! \file cn68xx_regs.h
+ * \brief Host Driver: Register Address and Register Mask values for
+ * Octeon CN68XX devices. The register map for CN66XX is the same
+ * for most registers. This file has the other registers that are
+ * 68XX-specific.
+ */
+
+#ifndef __CN68XX_REGS_H__
+#define __CN68XX_REGS_H__
+#include "cn66xx_regs.h"
+
+/*###################### REQUEST QUEUE #########################*/
+
+#define CN68XX_SLI_IQ_PORT0_PKIND 0x0800
+
+#define CN68XX_SLI_IQ_PORT_PKIND(iq) \
+ (CN68XX_SLI_IQ_PORT0_PKIND + ((iq) * CN6XXX_IQ_OFFSET))
+
+/*############################ OUTPUT QUEUE #########################*/
+
+/* Starting pipe number and number of pipes used by the SLI packet output. */
+#define CN68XX_SLI_TX_PIPE 0x1230
+
+/*######################## INTERRUPTS #########################*/
+
+/*------------------ Interrupt Masks ----------------*/
+#define CN68XX_INTR_PIPE_ERR BIT_ULL(61)
+
+#endif
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c
new file mode 100644
index 000000000000..160f8077692c
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c
@@ -0,0 +1,1216 @@
+/**********************************************************************
+* Author: Cavium, Inc.
+*
+* Contact: support@cavium.com
+* Please include "LiquidIO" in the subject.
+*
+* Copyright (c) 2003-2015 Cavium, Inc.
+*
+* This file 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 file is distributed in the hope that it will be useful, but
+* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+* NONINFRINGEMENT. See the GNU General Public License for more
+* details.
+*
+* This file may also be available under a different license from Cavium.
+* Contact Cavium, Inc. for more information
+**********************************************************************/
+#include <linux/version.h>
+#include <linux/netdevice.h>
+#include <linux/net_tstamp.h>
+#include <linux/ethtool.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include "octeon_config.h"
+#include "liquidio_common.h"
+#include "octeon_droq.h"
+#include "octeon_iq.h"
+#include "response_manager.h"
+#include "octeon_device.h"
+#include "octeon_nic.h"
+#include "octeon_main.h"
+#include "octeon_network.h"
+#include "cn66xx_regs.h"
+#include "cn66xx_device.h"
+#include "cn68xx_regs.h"
+#include "cn68xx_device.h"
+#include "liquidio_image.h"
+
+struct oct_mdio_cmd_context {
+ int octeon_id;
+ wait_queue_head_t wc;
+ int cond;
+};
+
+struct oct_mdio_cmd_resp {
+ u64 rh;
+ struct oct_mdio_cmd resp;
+ u64 status;
+};
+
+#define OCT_MDIO45_RESP_SIZE (sizeof(struct oct_mdio_cmd_resp))
+
+/* Octeon's interface mode of operation */
+enum {
+ INTERFACE_MODE_DISABLED,
+ INTERFACE_MODE_RGMII,
+ INTERFACE_MODE_GMII,
+ INTERFACE_MODE_SPI,
+ INTERFACE_MODE_PCIE,
+ INTERFACE_MODE_XAUI,
+ INTERFACE_MODE_SGMII,
+ INTERFACE_MODE_PICMG,
+ INTERFACE_MODE_NPI,
+ INTERFACE_MODE_LOOP,
+ INTERFACE_MODE_SRIO,
+ INTERFACE_MODE_ILK,
+ INTERFACE_MODE_RXAUI,
+ INTERFACE_MODE_QSGMII,
+ INTERFACE_MODE_AGL,
+};
+
+#define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0]))
+#define OCT_ETHTOOL_REGDUMP_LEN 4096
+#define OCT_ETHTOOL_REGSVER 1
+
+static const char oct_iq_stats_strings[][ETH_GSTRING_LEN] = {
+ "Instr posted",
+ "Instr processed",
+ "Instr dropped",
+ "Bytes Sent",
+ "Sgentry_sent",
+ "Inst cntreg",
+ "Tx done",
+ "Tx Iq busy",
+ "Tx dropped",
+ "Tx bytes",
+};
+
+static const char oct_droq_stats_strings[][ETH_GSTRING_LEN] = {
+ "OQ Pkts Received",
+ "OQ Bytes Received",
+ "Dropped no dispatch",
+ "Dropped nomem",
+ "Dropped toomany",
+ "Stack RX cnt",
+ "Stack RX Bytes",
+ "RX dropped",
+};
+
+#define OCTNIC_NCMD_AUTONEG_ON 0x1
+#define OCTNIC_NCMD_PHY_ON 0x2
+
+static int lio_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+ struct oct_link_info *linfo;
+
+ linfo = &lio->linfo;
+
+ if (linfo->link.s.interface == INTERFACE_MODE_XAUI ||
+ linfo->link.s.interface == INTERFACE_MODE_RXAUI) {
+ ecmd->port = PORT_FIBRE;
+ ecmd->supported =
+ (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE |
+ SUPPORTED_Pause);
+ ecmd->advertising =
+ (ADVERTISED_10000baseT_Full | ADVERTISED_Pause);
+ ecmd->transceiver = XCVR_EXTERNAL;
+ ecmd->autoneg = AUTONEG_DISABLE;
+
+ } else {
+ dev_err(&oct->pci_dev->dev, "Unknown link interface reported\n");
+ }
+
+ if (linfo->link.s.status) {
+ ethtool_cmd_speed_set(ecmd, linfo->link.s.speed);
+ ecmd->duplex = linfo->link.s.duplex;
+ } else {
+ ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN);
+ ecmd->duplex = DUPLEX_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static void
+lio_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
+{
+ struct lio *lio;
+ struct octeon_device *oct;
+
+ lio = GET_LIO(netdev);
+ oct = lio->oct_dev;
+
+ memset(drvinfo, 0, sizeof(struct ethtool_drvinfo));
+ strcpy(drvinfo->driver, "liquidio");
+ strcpy(drvinfo->version, LIQUIDIO_VERSION);
+ strncpy(drvinfo->fw_version, oct->fw_info.liquidio_firmware_version,
+ ETHTOOL_FWVERS_LEN);
+ strncpy(drvinfo->bus_info, pci_name(oct->pci_dev), 32);
+ drvinfo->regdump_len = OCT_ETHTOOL_REGDUMP_LEN;
+}
+
+static void
+lio_ethtool_get_channels(struct net_device *dev,
+ struct ethtool_channels *channel)
+{
+ struct lio *lio = GET_LIO(dev);
+ struct octeon_device *oct = lio->oct_dev;
+ u32 max_rx = 0, max_tx = 0, tx_count = 0, rx_count = 0;
+
+ if (OCTEON_CN6XXX(oct)) {
+ struct octeon_config *conf6x = CHIP_FIELD(oct, cn6xxx, conf);
+
+ max_rx = CFG_GET_OQ_MAX_Q(conf6x);
+ max_tx = CFG_GET_IQ_MAX_Q(conf6x);
+ rx_count = CFG_GET_NUM_RXQS_NIC_IF(conf6x, lio->ifidx);
+ tx_count = CFG_GET_NUM_TXQS_NIC_IF(conf6x, lio->ifidx);
+ }
+
+ channel->max_rx = max_rx;
+ channel->max_tx = max_tx;
+ channel->rx_count = rx_count;
+ channel->tx_count = tx_count;
+}
+
+static int lio_get_eeprom_len(struct net_device *netdev)
+{
+ u8 buf[128];
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct_dev = lio->oct_dev;
+ struct octeon_board_info *board_info;
+ int len;
+
+ board_info = (struct octeon_board_info *)(&oct_dev->boardinfo);
+ len = sprintf(buf, "boardname:%s serialnum:%s maj:%lld min:%lld\n",
+ board_info->name, board_info->serial_number,
+ board_info->major, board_info->minor);
+
+ return len;
+}
+
+static int
+lio_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
+ u8 *bytes)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct_dev = lio->oct_dev;
+ struct octeon_board_info *board_info;
+ int len;
+
+ if (eeprom->offset != 0)
+ return -EINVAL;
+
+ eeprom->magic = oct_dev->pci_dev->vendor;
+ board_info = (struct octeon_board_info *)(&oct_dev->boardinfo);
+ len =
+ sprintf((char *)bytes,
+ "boardname:%s serialnum:%s maj:%lld min:%lld\n",
+ board_info->name, board_info->serial_number,
+ board_info->major, board_info->minor);
+
+ return 0;
+}
+
+static int octnet_gpio_access(struct net_device *netdev, int addr, int val)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+ struct octnic_ctrl_pkt nctrl;
+ struct octnic_ctrl_params nparams;
+ int ret = 0;
+
+ memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));
+
+ nctrl.ncmd.u64 = 0;
+ nctrl.ncmd.s.cmd = OCTNET_CMD_GPIO_ACCESS;
+ nctrl.ncmd.s.param1 = lio->linfo.ifidx;
+ nctrl.ncmd.s.param2 = addr;
+ nctrl.ncmd.s.param3 = val;
+ nctrl.wait_time = 100;
+ nctrl.netpndev = (u64)netdev;
+ nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
+
+ nparams.resp_order = OCTEON_RESP_ORDERED;
+
+ ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl, nparams);
+ if (ret < 0) {
+ dev_err(&oct->pci_dev->dev, "Failed to configure gpio value\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Callback for when mdio command response arrives
+ */
+static void octnet_mdio_resp_callback(struct octeon_device *oct,
+ u32 status,
+ void *buf)
+{
+ struct oct_mdio_cmd_resp *mdio_cmd_rsp;
+ struct oct_mdio_cmd_context *mdio_cmd_ctx;
+ struct octeon_soft_command *sc = (struct octeon_soft_command *)buf;
+
+ mdio_cmd_rsp = (struct oct_mdio_cmd_resp *)sc->virtrptr;
+ mdio_cmd_ctx = (struct oct_mdio_cmd_context *)sc->ctxptr;
+
+ oct = lio_get_device(mdio_cmd_ctx->octeon_id);
+ if (status) {
+ dev_err(&oct->pci_dev->dev, "MIDO instruction failed. Status: %llx\n",
+ CVM_CAST64(status));
+ ACCESS_ONCE(mdio_cmd_ctx->cond) = -1;
+ } else {
+ ACCESS_ONCE(mdio_cmd_ctx->cond) = 1;
+ }
+ wake_up_interruptible(&mdio_cmd_ctx->wc);
+}
+
+/* This routine provides PHY access routines for
+ * mdio clause45 .
+ */
+static int
+octnet_mdio45_access(struct lio *lio, int op, int loc, int *value)
+{
+ struct octeon_device *oct_dev = lio->oct_dev;
+ struct octeon_soft_command *sc;
+ struct oct_mdio_cmd_resp *mdio_cmd_rsp;
+ struct oct_mdio_cmd_context *mdio_cmd_ctx;
+ struct oct_mdio_cmd *mdio_cmd;
+ int retval = 0;
+
+ sc = (struct octeon_soft_command *)
+ octeon_alloc_soft_command(oct_dev,
+ sizeof(struct oct_mdio_cmd),
+ sizeof(struct oct_mdio_cmd_resp),
+ sizeof(struct oct_mdio_cmd_context));
+
+ if (!sc)
+ return -ENOMEM;
+
+ mdio_cmd_ctx = (struct oct_mdio_cmd_context *)sc->ctxptr;
+ mdio_cmd_rsp = (struct oct_mdio_cmd_resp *)sc->virtrptr;
+ mdio_cmd = (struct oct_mdio_cmd *)sc->virtdptr;
+
+ ACCESS_ONCE(mdio_cmd_ctx->cond) = 0;
+ mdio_cmd_ctx->octeon_id = lio_get_device_id(oct_dev);
+ mdio_cmd->op = op;
+ mdio_cmd->mdio_addr = loc;
+ if (op)
+ mdio_cmd->value1 = *value;
+ mdio_cmd->value2 = lio->linfo.ifidx;
+ octeon_swap_8B_data((u64 *)mdio_cmd, sizeof(struct oct_mdio_cmd) / 8);
+
+ octeon_prepare_soft_command(oct_dev, sc, OPCODE_NIC, OPCODE_NIC_MDIO45,
+ 0, 0, 0);
+
+ sc->wait_time = 1000;
+ sc->callback = octnet_mdio_resp_callback;
+ sc->callback_arg = sc;
+
+ init_waitqueue_head(&mdio_cmd_ctx->wc);
+
+ retval = octeon_send_soft_command(oct_dev, sc);
+
+ if (retval) {
+ dev_err(&oct_dev->pci_dev->dev,
+ "octnet_mdio45_access instruction failed status: %x\n",
+ retval);
+ retval = -EBUSY;
+ } else {
+ /* Sleep on a wait queue till the cond flag indicates that the
+ * response arrived
+ */
+ sleep_cond(&mdio_cmd_ctx->wc, &mdio_cmd_ctx->cond);
+ retval = mdio_cmd_rsp->status;
+ if (retval) {
+ dev_err(&oct_dev->pci_dev->dev, "octnet mdio45 access failed\n");
+ retval = -EBUSY;
+ } else {
+ octeon_swap_8B_data((u64 *)(&mdio_cmd_rsp->resp),
+ sizeof(struct oct_mdio_cmd) / 8);
+
+ if (ACCESS_ONCE(mdio_cmd_ctx->cond) == 1) {
+ if (!op)
+ *value = mdio_cmd_rsp->resp.value1;
+ } else {
+ retval = -EINVAL;
+ }
+ }
+ }
+
+ octeon_free_soft_command(oct_dev, sc);
+
+ return retval;
+}
+
+static int lio_set_phys_id(struct net_device *netdev,
+ enum ethtool_phys_id_state state)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+ int value, ret;
+
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ if (oct->chip_id == OCTEON_CN66XX) {
+ octnet_gpio_access(netdev, VITESSE_PHY_GPIO_CFG,
+ VITESSE_PHY_GPIO_DRIVEON);
+ return 2;
+
+ } else if (oct->chip_id == OCTEON_CN68XX) {
+ /* Save the current LED settings */
+ ret = octnet_mdio45_access(lio, 0,
+ LIO68XX_LED_BEACON_ADDR,
+ &lio->phy_beacon_val);
+ if (ret)
+ return ret;
+
+ ret = octnet_mdio45_access(lio, 0,
+ LIO68XX_LED_CTRL_ADDR,
+ &lio->led_ctrl_val);
+ if (ret)
+ return ret;
+
+ /* Configure Beacon values */
+ value = LIO68XX_LED_BEACON_CFGON;
+ ret =
+ octnet_mdio45_access(lio, 1,
+ LIO68XX_LED_BEACON_ADDR,
+ &value);
+ if (ret)
+ return ret;
+
+ value = LIO68XX_LED_CTRL_CFGON;
+ ret =
+ octnet_mdio45_access(lio, 1,
+ LIO68XX_LED_CTRL_ADDR,
+ &value);
+ if (ret)
+ return ret;
+ } else {
+ return -EINVAL;
+ }
+ break;
+
+ case ETHTOOL_ID_ON:
+ if (oct->chip_id == OCTEON_CN66XX) {
+ octnet_gpio_access(netdev, VITESSE_PHY_GPIO_CFG,
+ VITESSE_PHY_GPIO_HIGH);
+
+ } else if (oct->chip_id == OCTEON_CN68XX) {
+ return -EINVAL;
+ } else {
+ return -EINVAL;
+ }
+ break;
+
+ case ETHTOOL_ID_OFF:
+ if (oct->chip_id == OCTEON_CN66XX)
+ octnet_gpio_access(netdev, VITESSE_PHY_GPIO_CFG,
+ VITESSE_PHY_GPIO_LOW);
+ else if (oct->chip_id == OCTEON_CN68XX)
+ return -EINVAL;
+ else
+ return -EINVAL;
+
+ break;
+
+ case ETHTOOL_ID_INACTIVE:
+ if (oct->chip_id == OCTEON_CN66XX) {
+ octnet_gpio_access(netdev, VITESSE_PHY_GPIO_CFG,
+ VITESSE_PHY_GPIO_DRIVEOFF);
+ } else if (oct->chip_id == OCTEON_CN68XX) {
+ /* Restore LED settings */
+ ret = octnet_mdio45_access(lio, 1,
+ LIO68XX_LED_CTRL_ADDR,
+ &lio->led_ctrl_val);
+ if (ret)
+ return ret;
+
+ octnet_mdio45_access(lio, 1, LIO68XX_LED_BEACON_ADDR,
+ &lio->phy_beacon_val);
+ if (ret)
+ return ret;
+
+ } else {
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void
+lio_ethtool_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ering)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+ u32 tx_max_pending = 0, rx_max_pending = 0, tx_pending = 0,
+ rx_pending = 0;
+
+ if (OCTEON_CN6XXX(oct)) {
+ struct octeon_config *conf6x = CHIP_FIELD(oct, cn6xxx, conf);
+
+ tx_max_pending = CN6XXX_MAX_IQ_DESCRIPTORS;
+ rx_max_pending = CN6XXX_MAX_OQ_DESCRIPTORS;
+ rx_pending = CFG_GET_NUM_RX_DESCS_NIC_IF(conf6x, lio->ifidx);
+ tx_pending = CFG_GET_NUM_TX_DESCS_NIC_IF(conf6x, lio->ifidx);
+ }
+
+ if (lio->mtu > OCTNET_DEFAULT_FRM_SIZE) {
+ ering->rx_pending = 0;
+ ering->rx_max_pending = 0;
+ ering->rx_mini_pending = 0;
+ ering->rx_jumbo_pending = rx_pending;
+ ering->rx_mini_max_pending = 0;
+ ering->rx_jumbo_max_pending = rx_max_pending;
+ } else {
+ ering->rx_pending = rx_pending;
+ ering->rx_max_pending = rx_max_pending;
+ ering->rx_mini_pending = 0;
+ ering->rx_jumbo_pending = 0;
+ ering->rx_mini_max_pending = 0;
+ ering->rx_jumbo_max_pending = 0;
+ }
+
+ ering->tx_pending = tx_pending;
+ ering->tx_max_pending = tx_max_pending;
+}
+
+static u32 lio_get_msglevel(struct net_device *netdev)
+{
+ struct lio *lio = GET_LIO(netdev);
+
+ return lio->msg_enable;
+}
+
+static void lio_set_msglevel(struct net_device *netdev, u32 msglvl)
+{
+ struct lio *lio = GET_LIO(netdev);
+
+ if ((msglvl ^ lio->msg_enable) & NETIF_MSG_HW) {
+ if (msglvl & NETIF_MSG_HW)
+ liquidio_set_feature(netdev,
+ OCTNET_CMD_VERBOSE_ENABLE);
+ else
+ liquidio_set_feature(netdev,
+ OCTNET_CMD_VERBOSE_DISABLE);
+ }
+
+ lio->msg_enable = msglvl;
+}
+
+static void
+lio_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
+{
+ /* Notes: Not supporting any auto negotiation in these
+ * drivers. Just report pause frame support.
+ */
+ pause->tx_pause = 1;
+ pause->rx_pause = 1; /* TODO: Need to support RX pause frame!!. */
+}
+
+static void
+lio_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct_dev = lio->oct_dev;
+ int i = 0, j;
+
+ for (j = 0; j < MAX_OCTEON_INSTR_QUEUES; j++) {
+ if (!(oct_dev->io_qmask.iq & (1UL << j)))
+ continue;
+ data[i++] =
+ CVM_CAST64(oct_dev->instr_queue[j]->stats.instr_posted);
+ data[i++] =
+ CVM_CAST64(
+ oct_dev->instr_queue[j]->stats.instr_processed);
+ data[i++] =
+ CVM_CAST64(
+ oct_dev->instr_queue[j]->stats.instr_dropped);
+ data[i++] =
+ CVM_CAST64(oct_dev->instr_queue[j]->stats.bytes_sent);
+ data[i++] =
+ CVM_CAST64(oct_dev->instr_queue[j]->stats.sgentry_sent);
+ data[i++] =
+ readl(oct_dev->instr_queue[j]->inst_cnt_reg);
+ data[i++] =
+ CVM_CAST64(oct_dev->instr_queue[j]->stats.tx_done);
+ data[i++] =
+ CVM_CAST64(oct_dev->instr_queue[j]->stats.tx_iq_busy);
+ data[i++] =
+ CVM_CAST64(oct_dev->instr_queue[j]->stats.tx_dropped);
+ data[i++] =
+ CVM_CAST64(oct_dev->instr_queue[j]->stats.tx_tot_bytes);
+ }
+
+ /* for (j = 0; j < oct_dev->num_oqs; j++){ */
+ for (j = 0; j < MAX_OCTEON_OUTPUT_QUEUES; j++) {
+ if (!(oct_dev->io_qmask.oq & (1UL << j)))
+ continue;
+ data[i++] = CVM_CAST64(oct_dev->droq[j]->stats.pkts_received);
+ data[i++] = CVM_CAST64(oct_dev->droq[j]->stats.bytes_received);
+ data[i++] =
+ CVM_CAST64(oct_dev->droq[j]->stats.dropped_nodispatch);
+ data[i++] = CVM_CAST64(oct_dev->droq[j]->stats.dropped_nomem);
+ data[i++] = CVM_CAST64(oct_dev->droq[j]->stats.dropped_toomany);
+ data[i++] =
+ CVM_CAST64(oct_dev->droq[j]->stats.rx_pkts_received);
+ data[i++] =
+ CVM_CAST64(oct_dev->droq[j]->stats.rx_bytes_received);
+ data[i++] =
+ CVM_CAST64(oct_dev->droq[j]->stats.rx_dropped);
+ }
+}
+
+static void lio_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct_dev = lio->oct_dev;
+ int num_iq_stats, num_oq_stats, i, j;
+
+ num_iq_stats = ARRAY_SIZE(oct_iq_stats_strings);
+ for (i = 0; i < MAX_OCTEON_INSTR_QUEUES; i++) {
+ if (!(oct_dev->io_qmask.iq & (1UL << i)))
+ continue;
+ for (j = 0; j < num_iq_stats; j++) {
+ sprintf(data, "IQ%d %s", i, oct_iq_stats_strings[j]);
+ data += ETH_GSTRING_LEN;
+ }
+ }
+
+ num_oq_stats = ARRAY_SIZE(oct_droq_stats_strings);
+ /* for (i = 0; i < oct_dev->num_oqs; i++) { */
+ for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) {
+ if (!(oct_dev->io_qmask.oq & (1UL << i)))
+ continue;
+ for (j = 0; j < num_oq_stats; j++) {
+ sprintf(data, "OQ%d %s", i, oct_droq_stats_strings[j]);
+ data += ETH_GSTRING_LEN;
+ }
+ }
+}
+
+static int lio_get_sset_count(struct net_device *netdev, int sset)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct_dev = lio->oct_dev;
+
+ return (ARRAY_SIZE(oct_iq_stats_strings) * oct_dev->num_iqs) +
+ (ARRAY_SIZE(oct_droq_stats_strings) * oct_dev->num_oqs);
+}
+
+static int lio_get_intr_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *intr_coal)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+ struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)oct->chip;
+ struct octeon_instr_queue *iq;
+ struct oct_intrmod_cfg *intrmod_cfg;
+
+ intrmod_cfg = &oct->intrmod;
+
+ switch (oct->chip_id) {
+ /* case OCTEON_CN73XX: Todo */
+ /* break; */
+ case OCTEON_CN68XX:
+ case OCTEON_CN66XX:
+ if (!intrmod_cfg->intrmod_enable) {
+ intr_coal->rx_coalesce_usecs =
+ CFG_GET_OQ_INTR_TIME(cn6xxx->conf);
+ intr_coal->rx_max_coalesced_frames =
+ CFG_GET_OQ_INTR_PKT(cn6xxx->conf);
+ } else {
+ intr_coal->use_adaptive_rx_coalesce =
+ intrmod_cfg->intrmod_enable;
+ intr_coal->rate_sample_interval =
+ intrmod_cfg->intrmod_check_intrvl;
+ intr_coal->pkt_rate_high =
+ intrmod_cfg->intrmod_maxpkt_ratethr;
+ intr_coal->pkt_rate_low =
+ intrmod_cfg->intrmod_minpkt_ratethr;
+ intr_coal->rx_max_coalesced_frames_high =
+ intrmod_cfg->intrmod_maxcnt_trigger;
+ intr_coal->rx_coalesce_usecs_high =
+ intrmod_cfg->intrmod_maxtmr_trigger;
+ intr_coal->rx_coalesce_usecs_low =
+ intrmod_cfg->intrmod_mintmr_trigger;
+ intr_coal->rx_max_coalesced_frames_low =
+ intrmod_cfg->intrmod_mincnt_trigger;
+ }
+
+ iq = oct->instr_queue[lio->linfo.txpciq[0]];
+ intr_coal->tx_max_coalesced_frames = iq->fill_threshold;
+ break;
+
+ default:
+ netif_info(lio, drv, lio->netdev, "Unknown Chip !!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Callback function for intrmod */
+static void octnet_intrmod_callback(struct octeon_device *oct_dev,
+ u32 status,
+ void *ptr)
+{
+ struct oct_intrmod_cmd *cmd = ptr;
+ struct octeon_soft_command *sc = cmd->sc;
+
+ oct_dev = cmd->oct_dev;
+
+ if (status)
+ dev_err(&oct_dev->pci_dev->dev, "intrmod config failed. Status: %llx\n",
+ CVM_CAST64(status));
+ else
+ dev_info(&oct_dev->pci_dev->dev,
+ "Rx-Adaptive Interrupt moderation enabled:%llx\n",
+ oct_dev->intrmod.intrmod_enable);
+
+ octeon_free_soft_command(oct_dev, sc);
+}
+
+/* Configure interrupt moderation parameters */
+static int octnet_set_intrmod_cfg(void *oct, struct oct_intrmod_cfg *intr_cfg)
+{
+ struct octeon_soft_command *sc;
+ struct oct_intrmod_cmd *cmd;
+ struct oct_intrmod_cfg *cfg;
+ int retval;
+ struct octeon_device *oct_dev = (struct octeon_device *)oct;
+
+ /* Alloc soft command */
+ sc = (struct octeon_soft_command *)
+ octeon_alloc_soft_command(oct_dev,
+ sizeof(struct oct_intrmod_cfg),
+ 0,
+ sizeof(struct oct_intrmod_cmd));
+
+ if (!sc)
+ return -ENOMEM;
+
+ cmd = (struct oct_intrmod_cmd *)sc->ctxptr;
+ cfg = (struct oct_intrmod_cfg *)sc->virtdptr;
+
+ memcpy(cfg, intr_cfg, sizeof(struct oct_intrmod_cfg));
+ octeon_swap_8B_data((u64 *)cfg, (sizeof(struct oct_intrmod_cfg)) / 8);
+ cmd->sc = sc;
+ cmd->cfg = cfg;
+ cmd->oct_dev = oct_dev;
+
+ octeon_prepare_soft_command(oct_dev, sc, OPCODE_NIC,
+ OPCODE_NIC_INTRMOD_CFG, 0, 0, 0);
+
+ sc->callback = octnet_intrmod_callback;
+ sc->callback_arg = cmd;
+ sc->wait_time = 1000;
+
+ retval = octeon_send_soft_command(oct_dev, sc);
+ if (retval) {
+ octeon_free_soft_command(oct_dev, sc);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Enable/Disable auto interrupt Moderation */
+static int oct_cfg_adaptive_intr(struct lio *lio, struct ethtool_coalesce
+ *intr_coal, int adaptive)
+{
+ int ret = 0;
+ struct octeon_device *oct = lio->oct_dev;
+ struct oct_intrmod_cfg *intrmod_cfg;
+
+ intrmod_cfg = &oct->intrmod;
+
+ if (adaptive) {
+ if (intr_coal->rate_sample_interval)
+ intrmod_cfg->intrmod_check_intrvl =
+ intr_coal->rate_sample_interval;
+ else
+ intrmod_cfg->intrmod_check_intrvl =
+ LIO_INTRMOD_CHECK_INTERVAL;
+
+ if (intr_coal->pkt_rate_high)
+ intrmod_cfg->intrmod_maxpkt_ratethr =
+ intr_coal->pkt_rate_high;
+ else
+ intrmod_cfg->intrmod_maxpkt_ratethr =
+ LIO_INTRMOD_MAXPKT_RATETHR;
+
+ if (intr_coal->pkt_rate_low)
+ intrmod_cfg->intrmod_minpkt_ratethr =
+ intr_coal->pkt_rate_low;
+ else
+ intrmod_cfg->intrmod_minpkt_ratethr =
+ LIO_INTRMOD_MINPKT_RATETHR;
+
+ if (intr_coal->rx_max_coalesced_frames_high)
+ intrmod_cfg->intrmod_maxcnt_trigger =
+ intr_coal->rx_max_coalesced_frames_high;
+ else
+ intrmod_cfg->intrmod_maxcnt_trigger =
+ LIO_INTRMOD_MAXCNT_TRIGGER;
+
+ if (intr_coal->rx_coalesce_usecs_high)
+ intrmod_cfg->intrmod_maxtmr_trigger =
+ intr_coal->rx_coalesce_usecs_high;
+ else
+ intrmod_cfg->intrmod_maxtmr_trigger =
+ LIO_INTRMOD_MAXTMR_TRIGGER;
+
+ if (intr_coal->rx_coalesce_usecs_low)
+ intrmod_cfg->intrmod_mintmr_trigger =
+ intr_coal->rx_coalesce_usecs_low;
+ else
+ intrmod_cfg->intrmod_mintmr_trigger =
+ LIO_INTRMOD_MINTMR_TRIGGER;
+
+ if (intr_coal->rx_max_coalesced_frames_low)
+ intrmod_cfg->intrmod_mincnt_trigger =
+ intr_coal->rx_max_coalesced_frames_low;
+ else
+ intrmod_cfg->intrmod_mincnt_trigger =
+ LIO_INTRMOD_MINCNT_TRIGGER;
+ }
+
+ intrmod_cfg->intrmod_enable = adaptive;
+ ret = octnet_set_intrmod_cfg(oct, intrmod_cfg);
+
+ return ret;
+}
+
+static int
+oct_cfg_rx_intrcnt(struct lio *lio, struct ethtool_coalesce *intr_coal)
+{
+ int ret;
+ struct octeon_device *oct = lio->oct_dev;
+ struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)oct->chip;
+ u32 rx_max_coalesced_frames;
+
+ if (!intr_coal->rx_max_coalesced_frames)
+ rx_max_coalesced_frames = CN6XXX_OQ_INTR_PKT;
+ else
+ rx_max_coalesced_frames = intr_coal->rx_max_coalesced_frames;
+
+ /* Disable adaptive interrupt modulation */
+ ret = oct_cfg_adaptive_intr(lio, intr_coal, 0);
+ if (ret)
+ return ret;
+
+ /* Config Cnt based interrupt values */
+ octeon_write_csr(oct, CN6XXX_SLI_OQ_INT_LEVEL_PKTS,
+ rx_max_coalesced_frames);
+ CFG_SET_OQ_INTR_PKT(cn6xxx->conf, rx_max_coalesced_frames);
+ return 0;
+}
+
+static int oct_cfg_rx_intrtime(struct lio *lio, struct ethtool_coalesce
+ *intr_coal)
+{
+ int ret;
+ struct octeon_device *oct = lio->oct_dev;
+ struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)oct->chip;
+ u32 time_threshold, rx_coalesce_usecs;
+
+ if (!intr_coal->rx_coalesce_usecs)
+ rx_coalesce_usecs = CN6XXX_OQ_INTR_TIME;
+ else
+ rx_coalesce_usecs = intr_coal->rx_coalesce_usecs;
+
+ /* Disable adaptive interrupt modulation */
+ ret = oct_cfg_adaptive_intr(lio, intr_coal, 0);
+ if (ret)
+ return ret;
+
+ /* Config Time based interrupt values */
+ time_threshold = lio_cn6xxx_get_oq_ticks(oct, rx_coalesce_usecs);
+ octeon_write_csr(oct, CN6XXX_SLI_OQ_INT_LEVEL_TIME, time_threshold);
+ CFG_SET_OQ_INTR_TIME(cn6xxx->conf, rx_coalesce_usecs);
+
+ return 0;
+}
+
+static int lio_set_intr_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *intr_coal)
+{
+ struct lio *lio = GET_LIO(netdev);
+ int ret;
+ struct octeon_device *oct = lio->oct_dev;
+ u32 j, q_no;
+
+ if ((intr_coal->tx_max_coalesced_frames >= CN6XXX_DB_MIN) &&
+ (intr_coal->tx_max_coalesced_frames <= CN6XXX_DB_MAX)) {
+ for (j = 0; j < lio->linfo.num_txpciq; j++) {
+ q_no = lio->linfo.txpciq[j];
+ oct->instr_queue[q_no]->fill_threshold =
+ intr_coal->tx_max_coalesced_frames;
+ }
+ } else {
+ dev_err(&oct->pci_dev->dev,
+ "LIQUIDIO: Invalid tx-frames:%d. Range is min:%d max:%d\n",
+ intr_coal->tx_max_coalesced_frames, CN6XXX_DB_MIN,
+ CN6XXX_DB_MAX);
+ return -EINVAL;
+ }
+
+ /* User requested adaptive-rx on */
+ if (intr_coal->use_adaptive_rx_coalesce) {
+ ret = oct_cfg_adaptive_intr(lio, intr_coal, 1);
+ if (ret)
+ goto ret_intrmod;
+ }
+
+ /* User requested adaptive-rx off and rx coalesce */
+ if ((intr_coal->rx_coalesce_usecs) &&
+ (!intr_coal->use_adaptive_rx_coalesce)) {
+ ret = oct_cfg_rx_intrtime(lio, intr_coal);
+ if (ret)
+ goto ret_intrmod;
+ }
+
+ /* User requested adaptive-rx off and rx coalesce */
+ if ((intr_coal->rx_max_coalesced_frames) &&
+ (!intr_coal->use_adaptive_rx_coalesce)) {
+ ret = oct_cfg_rx_intrcnt(lio, intr_coal);
+ if (ret)
+ goto ret_intrmod;
+ }
+
+ /* User requested adaptive-rx off, so use default coalesce params */
+ if ((!intr_coal->rx_max_coalesced_frames) &&
+ (!intr_coal->use_adaptive_rx_coalesce) &&
+ (!intr_coal->rx_coalesce_usecs)) {
+ dev_info(&oct->pci_dev->dev,
+ "Turning off adaptive-rx interrupt moderation\n");
+ dev_info(&oct->pci_dev->dev,
+ "Using RX Coalesce Default values rx_coalesce_usecs:%d rx_max_coalesced_frames:%d\n",
+ CN6XXX_OQ_INTR_TIME, CN6XXX_OQ_INTR_PKT);
+ ret = oct_cfg_rx_intrtime(lio, intr_coal);
+ if (ret)
+ goto ret_intrmod;
+
+ ret = oct_cfg_rx_intrcnt(lio, intr_coal);
+ if (ret)
+ goto ret_intrmod;
+ }
+
+ return 0;
+ret_intrmod:
+ return ret;
+}
+
+static int lio_get_ts_info(struct net_device *netdev,
+ struct ethtool_ts_info *info)
+{
+ struct lio *lio = GET_LIO(netdev);
+
+ info->so_timestamping =
+ SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RAW_HARDWARE;
+
+ if (lio->ptp_clock)
+ info->phc_index = ptp_clock_index(lio->ptp_clock);
+ else
+ info->phc_index = -1;
+
+ info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
+
+ info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT);
+
+ return 0;
+}
+
+static int lio_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+ struct oct_link_info *linfo;
+ struct octnic_ctrl_pkt nctrl;
+ struct octnic_ctrl_params nparams;
+ int ret = 0;
+
+ /* get the link info */
+ linfo = &lio->linfo;
+
+ if (ecmd->autoneg != AUTONEG_ENABLE && ecmd->autoneg != AUTONEG_DISABLE)
+ return -EINVAL;
+
+ if (ecmd->autoneg == AUTONEG_DISABLE && ((ecmd->speed != SPEED_100 &&
+ ecmd->speed != SPEED_10) ||
+ (ecmd->duplex != DUPLEX_HALF &&
+ ecmd->duplex != DUPLEX_FULL)))
+ return -EINVAL;
+
+ /* Ethtool Support is not provided for XAUI and RXAUI Interfaces
+ * as they operate at fixed Speed and Duplex settings
+ */
+ if (linfo->link.s.interface == INTERFACE_MODE_XAUI ||
+ linfo->link.s.interface == INTERFACE_MODE_RXAUI) {
+ dev_info(&oct->pci_dev->dev, "XAUI IFs settings cannot be modified.\n");
+ return -EINVAL;
+ }
+
+ memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));
+
+ nctrl.ncmd.u64 = 0;
+ nctrl.ncmd.s.cmd = OCTNET_CMD_SET_SETTINGS;
+ nctrl.wait_time = 1000;
+ nctrl.netpndev = (u64)netdev;
+ nctrl.ncmd.s.param1 = lio->linfo.ifidx;
+ nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
+
+ /* Passing the parameters sent by ethtool like Speed, Autoneg & Duplex
+ * to SE core application using ncmd.s.more & ncmd.s.param
+ */
+ if (ecmd->autoneg == AUTONEG_ENABLE) {
+ /* Autoneg ON */
+ nctrl.ncmd.s.more = OCTNIC_NCMD_PHY_ON |
+ OCTNIC_NCMD_AUTONEG_ON;
+ nctrl.ncmd.s.param2 = ecmd->advertising;
+ } else {
+ /* Autoneg OFF */
+ nctrl.ncmd.s.more = OCTNIC_NCMD_PHY_ON;
+
+ nctrl.ncmd.s.param3 = ecmd->duplex;
+
+ nctrl.ncmd.s.param2 = ecmd->speed;
+ }
+
+ nparams.resp_order = OCTEON_RESP_ORDERED;
+
+ ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl, nparams);
+ if (ret < 0) {
+ dev_err(&oct->pci_dev->dev, "Failed to set settings\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int lio_nway_reset(struct net_device *netdev)
+{
+ if (netif_running(netdev)) {
+ struct ethtool_cmd ecmd;
+
+ memset(&ecmd, 0, sizeof(struct ethtool_cmd));
+ ecmd.autoneg = 0;
+ ecmd.speed = 0;
+ ecmd.duplex = 0;
+ lio_set_settings(netdev, &ecmd);
+ }
+ return 0;
+}
+
+/* Return register dump len. */
+static int lio_get_regs_len(struct net_device *dev)
+{
+ return OCT_ETHTOOL_REGDUMP_LEN;
+}
+
+static int cn6xxx_read_csr_reg(char *s, struct octeon_device *oct)
+{
+ u32 reg;
+ int i, len = 0;
+
+ /* PCI Window Registers */
+
+ len += sprintf(s + len, "\n\t Octeon CSR Registers\n\n");
+ reg = CN6XXX_WIN_WR_ADDR_LO;
+ len += sprintf(s + len, "\n[%02x] (WIN_WR_ADDR_LO): %08x\n",
+ CN6XXX_WIN_WR_ADDR_LO, octeon_read_csr(oct, reg));
+ reg = CN6XXX_WIN_WR_ADDR_HI;
+ len += sprintf(s + len, "[%02x] (WIN_WR_ADDR_HI): %08x\n",
+ CN6XXX_WIN_WR_ADDR_HI, octeon_read_csr(oct, reg));
+ reg = CN6XXX_WIN_RD_ADDR_LO;
+ len += sprintf(s + len, "[%02x] (WIN_RD_ADDR_LO): %08x\n",
+ CN6XXX_WIN_RD_ADDR_LO, octeon_read_csr(oct, reg));
+ reg = CN6XXX_WIN_RD_ADDR_HI;
+ len += sprintf(s + len, "[%02x] (WIN_RD_ADDR_HI): %08x\n",
+ CN6XXX_WIN_RD_ADDR_HI, octeon_read_csr(oct, reg));
+ reg = CN6XXX_WIN_WR_DATA_LO;
+ len += sprintf(s + len, "[%02x] (WIN_WR_DATA_LO): %08x\n",
+ CN6XXX_WIN_WR_DATA_LO, octeon_read_csr(oct, reg));
+ reg = CN6XXX_WIN_WR_DATA_HI;
+ len += sprintf(s + len, "[%02x] (WIN_WR_DATA_HI): %08x\n",
+ CN6XXX_WIN_WR_DATA_HI, octeon_read_csr(oct, reg));
+ len += sprintf(s + len, "[%02x] (WIN_WR_MASK_REG): %08x\n",
+ CN6XXX_WIN_WR_MASK_REG,
+ octeon_read_csr(oct, CN6XXX_WIN_WR_MASK_REG));
+
+ /* PCI Interrupt Register */
+ len += sprintf(s + len, "\n[%x] (INT_ENABLE PORT 0): %08x\n",
+ CN6XXX_SLI_INT_ENB64_PORT0, octeon_read_csr(oct,
+ CN6XXX_SLI_INT_ENB64_PORT0));
+ len += sprintf(s + len, "\n[%x] (INT_ENABLE PORT 1): %08x\n",
+ CN6XXX_SLI_INT_ENB64_PORT1,
+ octeon_read_csr(oct, CN6XXX_SLI_INT_ENB64_PORT1));
+ len += sprintf(s + len, "[%x] (INT_SUM): %08x\n", CN6XXX_SLI_INT_SUM64,
+ octeon_read_csr(oct, CN6XXX_SLI_INT_SUM64));
+
+ /* PCI Output queue registers */
+ for (i = 0; i < oct->num_oqs; i++) {
+ reg = CN6XXX_SLI_OQ_PKTS_SENT(i);
+ len += sprintf(s + len, "\n[%x] (PKTS_SENT_%d): %08x\n",
+ reg, i, octeon_read_csr(oct, reg));
+ reg = CN6XXX_SLI_OQ_PKTS_CREDIT(i);
+ len += sprintf(s + len, "[%x] (PKT_CREDITS_%d): %08x\n",
+ reg, i, octeon_read_csr(oct, reg));
+ }
+ reg = CN6XXX_SLI_OQ_INT_LEVEL_PKTS;
+ len += sprintf(s + len, "\n[%x] (PKTS_SENT_INT_LEVEL): %08x\n",
+ reg, octeon_read_csr(oct, reg));
+ reg = CN6XXX_SLI_OQ_INT_LEVEL_TIME;
+ len += sprintf(s + len, "[%x] (PKTS_SENT_TIME): %08x\n",
+ reg, octeon_read_csr(oct, reg));
+
+ /* PCI Input queue registers */
+ for (i = 0; i <= 3; i++) {
+ u32 reg;
+
+ reg = CN6XXX_SLI_IQ_DOORBELL(i);
+ len += sprintf(s + len, "\n[%x] (INSTR_DOORBELL_%d): %08x\n",
+ reg, i, octeon_read_csr(oct, reg));
+ reg = CN6XXX_SLI_IQ_INSTR_COUNT(i);
+ len += sprintf(s + len, "[%x] (INSTR_COUNT_%d): %08x\n",
+ reg, i, octeon_read_csr(oct, reg));
+ }
+
+ /* PCI DMA registers */
+
+ len += sprintf(s + len, "\n[%x] (DMA_CNT_0): %08x\n",
+ CN6XXX_DMA_CNT(0),
+ octeon_read_csr(oct, CN6XXX_DMA_CNT(0)));
+ reg = CN6XXX_DMA_PKT_INT_LEVEL(0);
+ len += sprintf(s + len, "[%x] (DMA_INT_LEV_0): %08x\n",
+ CN6XXX_DMA_PKT_INT_LEVEL(0), octeon_read_csr(oct, reg));
+ reg = CN6XXX_DMA_TIME_INT_LEVEL(0);
+ len += sprintf(s + len, "[%x] (DMA_TIME_0): %08x\n",
+ CN6XXX_DMA_TIME_INT_LEVEL(0),
+ octeon_read_csr(oct, reg));
+
+ len += sprintf(s + len, "\n[%x] (DMA_CNT_1): %08x\n",
+ CN6XXX_DMA_CNT(1),
+ octeon_read_csr(oct, CN6XXX_DMA_CNT(1)));
+ reg = CN6XXX_DMA_PKT_INT_LEVEL(1);
+ len += sprintf(s + len, "[%x] (DMA_INT_LEV_1): %08x\n",
+ CN6XXX_DMA_PKT_INT_LEVEL(1),
+ octeon_read_csr(oct, reg));
+ reg = CN6XXX_DMA_PKT_INT_LEVEL(1);
+ len += sprintf(s + len, "[%x] (DMA_TIME_1): %08x\n",
+ CN6XXX_DMA_TIME_INT_LEVEL(1),
+ octeon_read_csr(oct, reg));
+
+ /* PCI Index registers */
+
+ len += sprintf(s + len, "\n");
+
+ for (i = 0; i < 16; i++) {
+ reg = lio_pci_readq(oct, CN6XXX_BAR1_REG(i, oct->pcie_port));
+ len += sprintf(s + len, "[%llx] (BAR1_INDEX_%02d): %08x\n",
+ CN6XXX_BAR1_REG(i, oct->pcie_port), i, reg);
+ }
+
+ return len;
+}
+
+static int cn6xxx_read_config_reg(char *s, struct octeon_device *oct)
+{
+ u32 val;
+ int i, len = 0;
+
+ /* PCI CONFIG Registers */
+
+ len += sprintf(s + len,
+ "\n\t Octeon Config space Registers\n\n");
+
+ for (i = 0; i <= 13; i++) {
+ pci_read_config_dword(oct->pci_dev, (i * 4), &val);
+ len += sprintf(s + len, "[0x%x] (Config[%d]): 0x%08x\n",
+ (i * 4), i, val);
+ }
+
+ for (i = 30; i <= 34; i++) {
+ pci_read_config_dword(oct->pci_dev, (i * 4), &val);
+ len += sprintf(s + len, "[0x%x] (Config[%d]): 0x%08x\n",
+ (i * 4), i, val);
+ }
+
+ return len;
+}
+
+/* Return register dump user app. */
+static void lio_get_regs(struct net_device *dev,
+ struct ethtool_regs *regs, void *regbuf)
+{
+ struct lio *lio = GET_LIO(dev);
+ int len = 0;
+ struct octeon_device *oct = lio->oct_dev;
+
+ memset(regbuf, 0, OCT_ETHTOOL_REGDUMP_LEN);
+ regs->version = OCT_ETHTOOL_REGSVER;
+
+ switch (oct->chip_id) {
+ /* case OCTEON_CN73XX: Todo */
+ case OCTEON_CN68XX:
+ case OCTEON_CN66XX:
+ len += cn6xxx_read_csr_reg(regbuf + len, oct);
+ len += cn6xxx_read_config_reg(regbuf + len, oct);
+ break;
+ default:
+ dev_err(&oct->pci_dev->dev, "%s Unknown chipid: %d\n",
+ __func__, oct->chip_id);
+ }
+}
+
+static const struct ethtool_ops lio_ethtool_ops = {
+ .get_settings = lio_get_settings,
+ .get_link = ethtool_op_get_link,
+ .get_drvinfo = lio_get_drvinfo,
+ .get_ringparam = lio_ethtool_get_ringparam,
+ .get_channels = lio_ethtool_get_channels,
+ .set_phys_id = lio_set_phys_id,
+ .get_eeprom_len = lio_get_eeprom_len,
+ .get_eeprom = lio_get_eeprom,
+ .get_strings = lio_get_strings,
+ .get_ethtool_stats = lio_get_ethtool_stats,
+ .get_pauseparam = lio_get_pauseparam,
+ .get_regs_len = lio_get_regs_len,
+ .get_regs = lio_get_regs,
+ .get_msglevel = lio_get_msglevel,
+ .set_msglevel = lio_set_msglevel,
+ .get_sset_count = lio_get_sset_count,
+ .nway_reset = lio_nway_reset,
+ .set_settings = lio_set_settings,
+ .get_coalesce = lio_get_intr_coalesce,
+ .set_coalesce = lio_set_intr_coalesce,
+ .get_ts_info = lio_get_ts_info,
+};
+
+void liquidio_set_ethtool_ops(struct net_device *netdev)
+{
+ netdev->ethtool_ops = &lio_ethtool_ops;
+}
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c
new file mode 100644
index 000000000000..0660deecc2c9
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c
@@ -0,0 +1,3668 @@
+/**********************************************************************
+* Author: Cavium, Inc.
+*
+* Contact: support@cavium.com
+* Please include "LiquidIO" in the subject.
+*
+* Copyright (c) 2003-2015 Cavium, Inc.
+*
+* This file 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 file is distributed in the hope that it will be useful, but
+* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+* NONINFRINGEMENT. See the GNU General Public License for more
+* details.
+*
+* This file may also be available under a different license from Cavium.
+* Contact Cavium, Inc. for more information
+**********************************************************************/
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/ip.h>
+#include <net/ip.h>
+#include <linux/ipv6.h>
+#include <linux/net_tstamp.h>
+#include <linux/if_vlan.h>
+#include <linux/firmware.h>
+#include <linux/ethtool.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include "octeon_config.h"
+#include "liquidio_common.h"
+#include "octeon_droq.h"
+#include "octeon_iq.h"
+#include "response_manager.h"
+#include "octeon_device.h"
+#include "octeon_nic.h"
+#include "octeon_main.h"
+#include "octeon_network.h"
+#include "cn66xx_regs.h"
+#include "cn66xx_device.h"
+#include "cn68xx_regs.h"
+#include "cn68xx_device.h"
+#include "liquidio_image.h"
+
+MODULE_AUTHOR("Cavium Networks, <support@cavium.com>");
+MODULE_DESCRIPTION("Cavium LiquidIO Intelligent Server Adapter Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(LIQUIDIO_VERSION);
+MODULE_FIRMWARE(LIO_FW_DIR LIO_FW_BASE_NAME LIO_210SV_NAME LIO_FW_NAME_SUFFIX);
+MODULE_FIRMWARE(LIO_FW_DIR LIO_FW_BASE_NAME LIO_210NV_NAME LIO_FW_NAME_SUFFIX);
+MODULE_FIRMWARE(LIO_FW_DIR LIO_FW_BASE_NAME LIO_410NV_NAME LIO_FW_NAME_SUFFIX);
+
+static int ddr_timeout = 10000;
+module_param(ddr_timeout, int, 0644);
+MODULE_PARM_DESC(ddr_timeout,
+ "Number of milliseconds to wait for DDR initialization. 0 waits for ddr_timeout to be set to non-zero value before starting to check");
+
+static u32 console_bitmask;
+module_param(console_bitmask, int, 0644);
+MODULE_PARM_DESC(console_bitmask,
+ "Bitmask indicating which consoles have debug output redirected to syslog.");
+
+#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
+
+static int debug = -1;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "NETIF_MSG debug bits");
+
+static char fw_type[LIO_MAX_FW_TYPE_LEN];
+module_param_string(fw_type, fw_type, sizeof(fw_type), 0000);
+MODULE_PARM_DESC(fw_type, "Type of firmware to be loaded. Default \"nic\"");
+
+static int conf_type;
+module_param(conf_type, int, 0);
+MODULE_PARM_DESC(conf_type, "select octeon configuration 0 default 1 ovs");
+
+/* Bit mask values for lio->ifstate */
+#define LIO_IFSTATE_DROQ_OPS 0x01
+#define LIO_IFSTATE_REGISTERED 0x02
+#define LIO_IFSTATE_RUNNING 0x04
+#define LIO_IFSTATE_RX_TIMESTAMP_ENABLED 0x08
+
+/* Polling interval for determining when NIC application is alive */
+#define LIQUIDIO_STARTER_POLL_INTERVAL_MS 100
+
+/* runtime link query interval */
+#define LIQUIDIO_LINK_QUERY_INTERVAL_MS 1000
+
+struct liquidio_if_cfg_context {
+ int octeon_id;
+
+ wait_queue_head_t wc;
+
+ int cond;
+};
+
+struct liquidio_if_cfg_resp {
+ u64 rh;
+ struct liquidio_if_cfg_info cfg_info;
+ u64 status;
+};
+
+struct oct_link_status_resp {
+ u64 rh;
+ struct oct_link_info link_info;
+ u64 status;
+};
+
+struct oct_timestamp_resp {
+ u64 rh;
+ u64 timestamp;
+ u64 status;
+};
+
+#define OCT_TIMESTAMP_RESP_SIZE (sizeof(struct oct_timestamp_resp))
+
+union tx_info {
+ u64 u64;
+ struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u16 gso_size;
+ u16 gso_segs;
+ u32 reserved;
+#else
+ u32 reserved;
+ u16 gso_segs;
+ u16 gso_size;
+#endif
+ } s;
+};
+
+/** Octeon device properties to be used by the NIC module.
+ * Each octeon device in the system will be represented
+ * by this structure in the NIC module.
+ */
+
+#define OCTNIC_MAX_SG (MAX_SKB_FRAGS)
+
+#define OCTNIC_GSO_MAX_HEADER_SIZE 128
+#define OCTNIC_GSO_MAX_SIZE (GSO_MAX_SIZE - OCTNIC_GSO_MAX_HEADER_SIZE)
+
+/** Structure of a node in list of gather components maintained by
+ * NIC driver for each network device.
+ */
+struct octnic_gather {
+ /** List manipulation. Next and prev pointers. */
+ struct list_head list;
+
+ /** Size of the gather component at sg in bytes. */
+ int sg_size;
+
+ /** Number of bytes that sg was adjusted to make it 8B-aligned. */
+ int adjust;
+
+ /** Gather component that can accommodate max sized fragment list
+ * received from the IP layer.
+ */
+ struct octeon_sg_entry *sg;
+};
+
+/** This structure is used by NIC driver to store information required
+ * to free the sk_buff when the packet has been fetched by Octeon.
+ * Bytes offset below assume worst-case of a 64-bit system.
+ */
+struct octnet_buf_free_info {
+ /** Bytes 1-8. Pointer to network device private structure. */
+ struct lio *lio;
+
+ /** Bytes 9-16. Pointer to sk_buff. */
+ struct sk_buff *skb;
+
+ /** Bytes 17-24. Pointer to gather list. */
+ struct octnic_gather *g;
+
+ /** Bytes 25-32. Physical address of skb->data or gather list. */
+ u64 dptr;
+
+ /** Bytes 33-47. Piggybacked soft command, if any */
+ struct octeon_soft_command *sc;
+};
+
+struct handshake {
+ struct completion init;
+ struct completion started;
+ struct pci_dev *pci_dev;
+ int init_ok;
+ int started_ok;
+};
+
+struct octeon_device_priv {
+ /** Tasklet structures for this device. */
+ struct tasklet_struct droq_tasklet;
+ unsigned long napi_mask;
+};
+
+static int octeon_device_init(struct octeon_device *);
+static void liquidio_remove(struct pci_dev *pdev);
+static int liquidio_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+
+static struct handshake handshake[MAX_OCTEON_DEVICES];
+static struct completion first_stage;
+
+static void octeon_droq_bh(unsigned long pdev)
+{
+ int q_no;
+ int reschedule = 0;
+ struct octeon_device *oct = (struct octeon_device *)pdev;
+ struct octeon_device_priv *oct_priv =
+ (struct octeon_device_priv *)oct->priv;
+
+ /* for (q_no = 0; q_no < oct->num_oqs; q_no++) { */
+ for (q_no = 0; q_no < MAX_OCTEON_OUTPUT_QUEUES; q_no++) {
+ if (!(oct->io_qmask.oq & (1UL << q_no)))
+ continue;
+ reschedule |= octeon_droq_process_packets(oct, oct->droq[q_no],
+ MAX_PACKET_BUDGET);
+ }
+
+ if (reschedule)
+ tasklet_schedule(&oct_priv->droq_tasklet);
+}
+
+static int lio_wait_for_oq_pkts(struct octeon_device *oct)
+{
+ struct octeon_device_priv *oct_priv =
+ (struct octeon_device_priv *)oct->priv;
+ int retry = 100, pkt_cnt = 0, pending_pkts = 0;
+ int i;
+
+ do {
+ pending_pkts = 0;
+
+ for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) {
+ if (!(oct->io_qmask.oq & (1UL << i)))
+ continue;
+ pkt_cnt += octeon_droq_check_hw_for_pkts(oct,
+ oct->droq[i]);
+ }
+ if (pkt_cnt > 0) {
+ pending_pkts += pkt_cnt;
+ tasklet_schedule(&oct_priv->droq_tasklet);
+ }
+ pkt_cnt = 0;
+ schedule_timeout_uninterruptible(1);
+
+ } while (retry-- && pending_pkts);
+
+ return pkt_cnt;
+}
+
+void octeon_report_tx_completion_to_bql(void *txq, unsigned int pkts_compl,
+ unsigned int bytes_compl)
+{
+ struct netdev_queue *netdev_queue = txq;
+
+ netdev_tx_completed_queue(netdev_queue, pkts_compl, bytes_compl);
+}
+
+void octeon_update_tx_completion_counters(void *buf, int reqtype,
+ unsigned int *pkts_compl,
+ unsigned int *bytes_compl)
+{
+ struct octnet_buf_free_info *finfo;
+ struct sk_buff *skb = NULL;
+ struct octeon_soft_command *sc;
+
+ switch (reqtype) {
+ case REQTYPE_NORESP_NET:
+ case REQTYPE_NORESP_NET_SG:
+ finfo = buf;
+ skb = finfo->skb;
+ break;
+
+ case REQTYPE_RESP_NET_SG:
+ case REQTYPE_RESP_NET:
+ sc = buf;
+ skb = sc->callback_arg;
+ break;
+
+ default:
+ return;
+ }
+
+ (*pkts_compl)++;
+ *bytes_compl += skb->len;
+}
+
+void octeon_report_sent_bytes_to_bql(void *buf, int reqtype)
+{
+ struct octnet_buf_free_info *finfo;
+ struct sk_buff *skb;
+ struct octeon_soft_command *sc;
+ struct netdev_queue *txq;
+
+ switch (reqtype) {
+ case REQTYPE_NORESP_NET:
+ case REQTYPE_NORESP_NET_SG:
+ finfo = buf;
+ skb = finfo->skb;
+ break;
+
+ case REQTYPE_RESP_NET_SG:
+ case REQTYPE_RESP_NET:
+ sc = buf;
+ skb = sc->callback_arg;
+ break;
+
+ default:
+ return;
+ }
+
+ txq = netdev_get_tx_queue(skb->dev, skb_get_queue_mapping(skb));
+ netdev_tx_sent_queue(txq, skb->len);
+}
+
+int octeon_console_debug_enabled(u32 console)
+{
+ return (console_bitmask >> (console)) & 0x1;
+}
+
+/**
+ * \brief Forces all IO queues off on a given device
+ * @param oct Pointer to Octeon device
+ */
+static void force_io_queues_off(struct octeon_device *oct)
+{
+ if ((oct->chip_id == OCTEON_CN66XX) ||
+ (oct->chip_id == OCTEON_CN68XX)) {
+ /* Reset the Enable bits for Input Queues. */
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB, 0);
+
+ /* Reset the Enable bits for Output Queues. */
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_OUT_ENB, 0);
+ }
+}
+
+/**
+ * \brief wait for all pending requests to complete
+ * @param oct Pointer to Octeon device
+ *
+ * Called during shutdown sequence
+ */
+static int wait_for_pending_requests(struct octeon_device *oct)
+{
+ int i, pcount = 0;
+
+ for (i = 0; i < 100; i++) {
+ pcount =
+ atomic_read(&oct->response_list
+ [OCTEON_ORDERED_SC_LIST].pending_req_count);
+ if (pcount)
+ schedule_timeout_uninterruptible(HZ / 10);
+ else
+ break;
+ }
+
+ if (pcount)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * \brief Cause device to go quiet so it can be safely removed/reset/etc
+ * @param oct Pointer to Octeon device
+ */
+static inline void pcierror_quiesce_device(struct octeon_device *oct)
+{
+ int i;
+
+ /* Disable the input and output queues now. No more packets will
+ * arrive from Octeon, but we should wait for all packet processing
+ * to finish.
+ */
+ force_io_queues_off(oct);
+
+ /* To allow for in-flight requests */
+ schedule_timeout_uninterruptible(100);
+
+ if (wait_for_pending_requests(oct))
+ dev_err(&oct->pci_dev->dev, "There were pending requests\n");
+
+ /* Force all requests waiting to be fetched by OCTEON to complete. */
+ for (i = 0; i < MAX_OCTEON_INSTR_QUEUES; i++) {
+ struct octeon_instr_queue *iq;
+
+ if (!(oct->io_qmask.iq & (1UL << i)))
+ continue;
+ iq = oct->instr_queue[i];
+
+ if (atomic_read(&iq->instr_pending)) {
+ spin_lock_bh(&iq->lock);
+ iq->fill_cnt = 0;
+ iq->octeon_read_index = iq->host_write_index;
+ iq->stats.instr_processed +=
+ atomic_read(&iq->instr_pending);
+ lio_process_iq_request_list(oct, iq);
+ spin_unlock_bh(&iq->lock);
+ }
+ }
+
+ /* Force all pending ordered list requests to time out. */
+ lio_process_ordered_list(oct, 1);
+
+ /* We do not need to wait for output queue packets to be processed. */
+}
+
+/**
+ * \brief Cleanup PCI AER uncorrectable error status
+ * @param dev Pointer to PCI device
+ */
+static void cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
+{
+ int pos = 0x100;
+ u32 status, mask;
+
+ pr_info("%s :\n", __func__);
+
+ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
+ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
+ if (dev->error_state == pci_channel_io_normal)
+ status &= ~mask; /* Clear corresponding nonfatal bits */
+ else
+ status &= mask; /* Clear corresponding fatal bits */
+ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
+}
+
+/**
+ * \brief Stop all PCI IO to a given device
+ * @param dev Pointer to Octeon device
+ */
+static void stop_pci_io(struct octeon_device *oct)
+{
+ /* No more instructions will be forwarded. */
+ atomic_set(&oct->status, OCT_DEV_IN_RESET);
+
+ pci_disable_device(oct->pci_dev);
+
+ /* Disable interrupts */
+ oct->fn_list.disable_interrupt(oct->chip);
+
+ pcierror_quiesce_device(oct);
+
+ /* Release the interrupt line */
+ free_irq(oct->pci_dev->irq, oct);
+
+ if (oct->flags & LIO_FLAG_MSI_ENABLED)
+ pci_disable_msi(oct->pci_dev);
+
+ dev_dbg(&oct->pci_dev->dev, "Device state is now %s\n",
+ lio_get_state_string(&oct->status));
+
+ /* cn63xx_cleanup_aer_uncorrect_error_status(oct->pci_dev); */
+ /* making it a common function for all OCTEON models */
+ cleanup_aer_uncorrect_error_status(oct->pci_dev);
+}
+
+/**
+ * \brief called when PCI error is detected
+ * @param pdev Pointer to PCI device
+ * @param state The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t liquidio_pcie_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct octeon_device *oct = pci_get_drvdata(pdev);
+
+ /* Non-correctable Non-fatal errors */
+ if (state == pci_channel_io_normal) {
+ dev_err(&oct->pci_dev->dev, "Non-correctable non-fatal error reported:\n");
+ cleanup_aer_uncorrect_error_status(oct->pci_dev);
+ return PCI_ERS_RESULT_CAN_RECOVER;
+ }
+
+ /* Non-correctable Fatal errors */
+ dev_err(&oct->pci_dev->dev, "Non-correctable FATAL reported by PCI AER driver\n");
+ stop_pci_io(oct);
+
+ /* Always return a DISCONNECT. There is no support for recovery but only
+ * for a clean shutdown.
+ */
+ return PCI_ERS_RESULT_DISCONNECT;
+}
+
+/**
+ * \brief mmio handler
+ * @param pdev Pointer to PCI device
+ */
+static pci_ers_result_t liquidio_pcie_mmio_enabled(struct pci_dev *pdev)
+{
+ /* We should never hit this since we never ask for a reset for a Fatal
+ * Error. We always return DISCONNECT in io_error above.
+ * But play safe and return RECOVERED for now.
+ */
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * \brief called after the pci bus has been reset.
+ * @param pdev Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot. Implementation
+ * resembles the first-half of the octeon_resume routine.
+ */
+static pci_ers_result_t liquidio_pcie_slot_reset(struct pci_dev *pdev)
+{
+ /* We should never hit this since we never ask for a reset for a Fatal
+ * Error. We always return DISCONNECT in io_error above.
+ * But play safe and return RECOVERED for now.
+ */
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * \brief called when traffic can start flowing again.
+ * @param pdev Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation. Implementation resembles the
+ * second-half of the octeon_resume routine.
+ */
+static void liquidio_pcie_resume(struct pci_dev *pdev)
+{
+ /* Nothing to be done here. */
+}
+
+#ifdef CONFIG_PM
+/**
+ * \brief called when suspending
+ * @param pdev Pointer to PCI device
+ * @param state state to suspend to
+ */
+static int liquidio_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ return 0;
+}
+
+/**
+ * \brief called when resuming
+ * @param pdev Pointer to PCI device
+ */
+static int liquidio_resume(struct pci_dev *pdev)
+{
+ return 0;
+}
+#endif
+
+/* For PCI-E Advanced Error Recovery (AER) Interface */
+static struct pci_error_handlers liquidio_err_handler = {
+ .error_detected = liquidio_pcie_error_detected,
+ .mmio_enabled = liquidio_pcie_mmio_enabled,
+ .slot_reset = liquidio_pcie_slot_reset,
+ .resume = liquidio_pcie_resume,
+};
+
+static const struct pci_device_id liquidio_pci_tbl[] = {
+ { /* 68xx */
+ PCI_VENDOR_ID_CAVIUM, 0x91, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0
+ },
+ { /* 66xx */
+ PCI_VENDOR_ID_CAVIUM, 0x92, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 0
+ }
+};
+MODULE_DEVICE_TABLE(pci, liquidio_pci_tbl);
+
+static struct pci_driver liquidio_pci_driver = {
+ .name = "LiquidIO",
+ .id_table = liquidio_pci_tbl,
+ .probe = liquidio_probe,
+ .remove = liquidio_remove,
+ .err_handler = &liquidio_err_handler, /* For AER */
+
+#ifdef CONFIG_PM
+ .suspend = liquidio_suspend,
+ .resume = liquidio_resume,
+#endif
+
+};
+
+/**
+ * \brief register PCI driver
+ */
+static int liquidio_init_pci(void)
+{
+ return pci_register_driver(&liquidio_pci_driver);
+}
+
+/**
+ * \brief unregister PCI driver
+ */
+static void liquidio_deinit_pci(void)
+{
+ pci_unregister_driver(&liquidio_pci_driver);
+}
+
+/**
+ * \brief check interface state
+ * @param lio per-network private data
+ * @param state_flag flag state to check
+ */
+static inline int ifstate_check(struct lio *lio, int state_flag)
+{
+ return atomic_read(&lio->ifstate) & state_flag;
+}
+
+/**
+ * \brief set interface state
+ * @param lio per-network private data
+ * @param state_flag flag state to set
+ */
+static inline void ifstate_set(struct lio *lio, int state_flag)
+{
+ atomic_set(&lio->ifstate, (atomic_read(&lio->ifstate) | state_flag));
+}
+
+/**
+ * \brief clear interface state
+ * @param lio per-network private data
+ * @param state_flag flag state to clear
+ */
+static inline void ifstate_reset(struct lio *lio, int state_flag)
+{
+ atomic_set(&lio->ifstate, (atomic_read(&lio->ifstate) & ~(state_flag)));
+}
+
+/**
+ * \brief Stop Tx queues
+ * @param netdev network device
+ */
+static inline void txqs_stop(struct net_device *netdev)
+{
+ if (netif_is_multiqueue(netdev)) {
+ int i;
+
+ for (i = 0; i < netdev->num_tx_queues; i++)
+ netif_stop_subqueue(netdev, i);
+ } else {
+ netif_stop_queue(netdev);
+ }
+}
+
+/**
+ * \brief Start Tx queues
+ * @param netdev network device
+ */
+static inline void txqs_start(struct net_device *netdev)
+{
+ if (netif_is_multiqueue(netdev)) {
+ int i;
+
+ for (i = 0; i < netdev->num_tx_queues; i++)
+ netif_start_subqueue(netdev, i);
+ } else {
+ netif_start_queue(netdev);
+ }
+}
+
+/**
+ * \brief Wake Tx queues
+ * @param netdev network device
+ */
+static inline void txqs_wake(struct net_device *netdev)
+{
+ if (netif_is_multiqueue(netdev)) {
+ int i;
+
+ for (i = 0; i < netdev->num_tx_queues; i++)
+ netif_wake_subqueue(netdev, i);
+ } else {
+ netif_wake_queue(netdev);
+ }
+}
+
+/**
+ * \brief Stop Tx queue
+ * @param netdev network device
+ */
+static void stop_txq(struct net_device *netdev)
+{
+ txqs_stop(netdev);
+}
+
+/**
+ * \brief Start Tx queue
+ * @param netdev network device
+ */
+static void start_txq(struct net_device *netdev)
+{
+ struct lio *lio = GET_LIO(netdev);
+
+ if (lio->linfo.link.s.status) {
+ txqs_start(netdev);
+ return;
+ }
+}
+
+/**
+ * \brief Wake a queue
+ * @param netdev network device
+ * @param q which queue to wake
+ */
+static inline void wake_q(struct net_device *netdev, int q)
+{
+ if (netif_is_multiqueue(netdev))
+ netif_wake_subqueue(netdev, q);
+ else
+ netif_wake_queue(netdev);
+}
+
+/**
+ * \brief Stop a queue
+ * @param netdev network device
+ * @param q which queue to stop
+ */
+static inline void stop_q(struct net_device *netdev, int q)
+{
+ if (netif_is_multiqueue(netdev))
+ netif_stop_subqueue(netdev, q);
+ else
+ netif_stop_queue(netdev);
+}
+
+/**
+ * \brief Check Tx queue status, and take appropriate action
+ * @param lio per-network private data
+ * @returns 0 if full, number of queues woken up otherwise
+ */
+static inline int check_txq_status(struct lio *lio)
+{
+ int ret_val = 0;
+
+ if (netif_is_multiqueue(lio->netdev)) {
+ int numqs = lio->netdev->num_tx_queues;
+ int q, iq = 0;
+
+ /* check each sub-queue state */
+ for (q = 0; q < numqs; q++) {
+ iq = lio->linfo.txpciq[q & (lio->linfo.num_txpciq - 1)];
+ if (octnet_iq_is_full(lio->oct_dev, iq))
+ continue;
+ wake_q(lio->netdev, q);
+ ret_val++;
+ }
+ } else {
+ if (octnet_iq_is_full(lio->oct_dev, lio->txq))
+ return 0;
+ wake_q(lio->netdev, lio->txq);
+ ret_val = 1;
+ }
+ return ret_val;
+}
+
+/**
+ * Remove the node at the head of the list. The list would be empty at
+ * the end of this call if there are no more nodes in the list.
+ */
+static inline struct list_head *list_delete_head(struct list_head *root)
+{
+ struct list_head *node;
+
+ if ((root->prev == root) && (root->next == root))
+ node = NULL;
+ else
+ node = root->next;
+
+ if (node)
+ list_del(node);
+
+ return node;
+}
+
+/**
+ * \brief Delete gather list
+ * @param lio per-network private data
+ */
+static void delete_glist(struct lio *lio)
+{
+ struct octnic_gather *g;
+
+ do {
+ g = (struct octnic_gather *)
+ list_delete_head(&lio->glist);
+ if (g) {
+ if (g->sg)
+ kfree((void *)((unsigned long)g->sg -
+ g->adjust));
+ kfree(g);
+ }
+ } while (g);
+}
+
+/**
+ * \brief Setup gather list
+ * @param lio per-network private data
+ */
+static int setup_glist(struct lio *lio)
+{
+ int i;
+ struct octnic_gather *g;
+
+ INIT_LIST_HEAD(&lio->glist);
+
+ for (i = 0; i < lio->tx_qsize; i++) {
+ g = kmalloc(sizeof(*g), GFP_KERNEL);
+ if (!g)
+ break;
+ memset(g, 0, sizeof(struct octnic_gather));
+
+ g->sg_size =
+ ((ROUNDUP4(OCTNIC_MAX_SG) >> 2) * OCT_SG_ENTRY_SIZE);
+
+ g->sg = kmalloc(g->sg_size + 8, GFP_KERNEL);
+ if (!g->sg) {
+ kfree(g);
+ break;
+ }
+
+ /* The gather component should be aligned on 64-bit boundary */
+ if (((unsigned long)g->sg) & 7) {
+ g->adjust = 8 - (((unsigned long)g->sg) & 7);
+ g->sg = (struct octeon_sg_entry *)
+ ((unsigned long)g->sg + g->adjust);
+ }
+ list_add_tail(&g->list, &lio->glist);
+ }
+
+ if (i == lio->tx_qsize)
+ return 0;
+
+ delete_glist(lio);
+ return 1;
+}
+
+/**
+ * \brief Print link information
+ * @param netdev network device
+ */
+static void print_link_info(struct net_device *netdev)
+{
+ struct lio *lio = GET_LIO(netdev);
+
+ if (atomic_read(&lio->ifstate) & LIO_IFSTATE_REGISTERED) {
+ struct oct_link_info *linfo = &lio->linfo;
+
+ if (linfo->link.s.status) {
+ netif_info(lio, link, lio->netdev, "%d Mbps %s Duplex UP\n",
+ linfo->link.s.speed,
+ (linfo->link.s.duplex) ? "Full" : "Half");
+ } else {
+ netif_info(lio, link, lio->netdev, "Link Down\n");
+ }
+ }
+}
+
+/**
+ * \brief Update link status
+ * @param netdev network device
+ * @param ls link status structure
+ *
+ * Called on receipt of a link status response from the core application to
+ * update each interface's link status.
+ */
+static inline void update_link_status(struct net_device *netdev,
+ union oct_link_status *ls)
+{
+ struct lio *lio = GET_LIO(netdev);
+
+ if ((lio->intf_open) && (lio->linfo.link.u64 != ls->u64)) {
+ lio->linfo.link.u64 = ls->u64;
+
+ print_link_info(netdev);
+
+ if (lio->linfo.link.s.status) {
+ netif_carrier_on(netdev);
+ /* start_txq(netdev); */
+ txqs_wake(netdev);
+ } else {
+ netif_carrier_off(netdev);
+ stop_txq(netdev);
+ }
+ }
+}
+
+/**
+ * \brief Droq packet processor sceduler
+ * @param oct octeon device
+ */
+static
+void liquidio_schedule_droq_pkt_handlers(struct octeon_device *oct)
+{
+ struct octeon_device_priv *oct_priv =
+ (struct octeon_device_priv *)oct->priv;
+ u64 oq_no;
+ struct octeon_droq *droq;
+
+ if (oct->int_status & OCT_DEV_INTR_PKT_DATA) {
+ for (oq_no = 0; oq_no < MAX_OCTEON_OUTPUT_QUEUES; oq_no++) {
+ if (!(oct->droq_intr & (1 << oq_no)))
+ continue;
+
+ droq = oct->droq[oq_no];
+
+ if (droq->ops.poll_mode) {
+ droq->ops.napi_fn(droq);
+ oct_priv->napi_mask |= (1 << oq_no);
+ } else {
+ tasklet_schedule(&oct_priv->droq_tasklet);
+ }
+ }
+ }
+}
+
+/**
+ * \brief Interrupt handler for octeon
+ * @param irq unused
+ * @param dev octeon device
+ */
+static
+irqreturn_t liquidio_intr_handler(int irq __attribute__((unused)), void *dev)
+{
+ struct octeon_device *oct = (struct octeon_device *)dev;
+ irqreturn_t ret;
+
+ /* Disable our interrupts for the duration of ISR */
+ oct->fn_list.disable_interrupt(oct->chip);
+
+ ret = oct->fn_list.process_interrupt_regs(oct);
+
+ if (ret == IRQ_HANDLED)
+ liquidio_schedule_droq_pkt_handlers(oct);
+
+ /* Re-enable our interrupts */
+ if (!(atomic_read(&oct->status) == OCT_DEV_IN_RESET))
+ oct->fn_list.enable_interrupt(oct->chip);
+
+ return ret;
+}
+
+/**
+ * \brief Setup interrupt for octeon device
+ * @param oct octeon device
+ *
+ * Enable interrupt in Octeon device as given in the PCI interrupt mask.
+ */
+static int octeon_setup_interrupt(struct octeon_device *oct)
+{
+ int irqret, err;
+
+ err = pci_enable_msi(oct->pci_dev);
+ if (err)
+ dev_warn(&oct->pci_dev->dev, "Reverting to legacy interrupts. Error: %d\n",
+ err);
+ else
+ oct->flags |= LIO_FLAG_MSI_ENABLED;
+
+ irqret = request_irq(oct->pci_dev->irq, liquidio_intr_handler,
+ IRQF_SHARED, "octeon", oct);
+ if (irqret) {
+ if (oct->flags & LIO_FLAG_MSI_ENABLED)
+ pci_disable_msi(oct->pci_dev);
+ dev_err(&oct->pci_dev->dev, "Request IRQ failed with code: %d\n",
+ irqret);
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * \brief PCI probe handler
+ * @param pdev PCI device structure
+ * @param ent unused
+ */
+static int liquidio_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct octeon_device *oct_dev = NULL;
+ struct handshake *hs;
+
+ oct_dev = octeon_allocate_device(pdev->device,
+ sizeof(struct octeon_device_priv));
+ if (!oct_dev) {
+ dev_err(&pdev->dev, "Unable to allocate device\n");
+ return -ENOMEM;
+ }
+
+ dev_info(&pdev->dev, "Initializing device %x:%x.\n",
+ (u32)pdev->vendor, (u32)pdev->device);
+
+ /* Assign octeon_device for this device to the private data area. */
+ pci_set_drvdata(pdev, oct_dev);
+
+ /* set linux specific device pointer */
+ oct_dev->pci_dev = (void *)pdev;
+
+ hs = &handshake[oct_dev->octeon_id];
+ init_completion(&hs->init);
+ init_completion(&hs->started);
+ hs->pci_dev = pdev;
+
+ if (oct_dev->octeon_id == 0)
+ /* first LiquidIO NIC is detected */
+ complete(&first_stage);
+
+ if (octeon_device_init(oct_dev)) {
+ liquidio_remove(pdev);
+ return -ENOMEM;
+ }
+
+ dev_dbg(&oct_dev->pci_dev->dev, "Device is ready\n");
+
+ return 0;
+}
+
+/**
+ *\brief Destroy resources associated with octeon device
+ * @param pdev PCI device structure
+ * @param ent unused
+ */
+static void octeon_destroy_resources(struct octeon_device *oct)
+{
+ int i;
+ struct octeon_device_priv *oct_priv =
+ (struct octeon_device_priv *)oct->priv;
+
+ struct handshake *hs;
+
+ switch (atomic_read(&oct->status)) {
+ case OCT_DEV_RUNNING:
+ case OCT_DEV_CORE_OK:
+
+ /* No more instructions will be forwarded. */
+ atomic_set(&oct->status, OCT_DEV_IN_RESET);
+
+ oct->app_mode = CVM_DRV_INVALID_APP;
+ dev_dbg(&oct->pci_dev->dev, "Device state is now %s\n",
+ lio_get_state_string(&oct->status));
+
+ schedule_timeout_uninterruptible(HZ / 10);
+
+ /* fallthrough */
+ case OCT_DEV_HOST_OK:
+
+ /* fallthrough */
+ case OCT_DEV_CONSOLE_INIT_DONE:
+ /* Remove any consoles */
+ octeon_remove_consoles(oct);
+
+ /* fallthrough */
+ case OCT_DEV_IO_QUEUES_DONE:
+ if (wait_for_pending_requests(oct))
+ dev_err(&oct->pci_dev->dev, "There were pending requests\n");
+
+ if (lio_wait_for_instr_fetch(oct))
+ dev_err(&oct->pci_dev->dev, "IQ had pending instructions\n");
+
+ /* Disable the input and output queues now. No more packets will
+ * arrive from Octeon, but we should wait for all packet
+ * processing to finish.
+ */
+ oct->fn_list.disable_io_queues(oct);
+
+ if (lio_wait_for_oq_pkts(oct))
+ dev_err(&oct->pci_dev->dev, "OQ had pending packets\n");
+
+ /* Disable interrupts */
+ oct->fn_list.disable_interrupt(oct->chip);
+
+ /* Release the interrupt line */
+ free_irq(oct->pci_dev->irq, oct);
+
+ if (oct->flags & LIO_FLAG_MSI_ENABLED)
+ pci_disable_msi(oct->pci_dev);
+
+ /* Soft reset the octeon device before exiting */
+ oct->fn_list.soft_reset(oct);
+
+ /* Disable the device, releasing the PCI INT */
+ pci_disable_device(oct->pci_dev);
+
+ /* fallthrough */
+ case OCT_DEV_IN_RESET:
+ case OCT_DEV_DROQ_INIT_DONE:
+ /*atomic_set(&oct->status, OCT_DEV_DROQ_INIT_DONE);*/
+ mdelay(100);
+ for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) {
+ if (!(oct->io_qmask.oq & (1UL << i)))
+ continue;
+ octeon_delete_droq(oct, i);
+ }
+
+ /* Force any pending handshakes to complete */
+ for (i = 0; i < MAX_OCTEON_DEVICES; i++) {
+ hs = &handshake[i];
+
+ if (hs->pci_dev) {
+ handshake[oct->octeon_id].init_ok = 0;
+ complete(&handshake[oct->octeon_id].init);
+ handshake[oct->octeon_id].started_ok = 0;
+ complete(&handshake[oct->octeon_id].started);
+ }
+ }
+
+ /* fallthrough */
+ case OCT_DEV_RESP_LIST_INIT_DONE:
+ octeon_delete_response_list(oct);
+
+ /* fallthrough */
+ case OCT_DEV_SC_BUFF_POOL_INIT_DONE:
+ octeon_free_sc_buffer_pool(oct);
+
+ /* fallthrough */
+ case OCT_DEV_INSTR_QUEUE_INIT_DONE:
+ for (i = 0; i < MAX_OCTEON_INSTR_QUEUES; i++) {
+ if (!(oct->io_qmask.iq & (1UL << i)))
+ continue;
+ octeon_delete_instr_queue(oct, i);
+ }
+
+ /* fallthrough */
+ case OCT_DEV_DISPATCH_INIT_DONE:
+ octeon_delete_dispatch_list(oct);
+ cancel_delayed_work_sync(&oct->nic_poll_work.work);
+
+ /* fallthrough */
+ case OCT_DEV_PCI_MAP_DONE:
+ octeon_unmap_pci_barx(oct, 0);
+ octeon_unmap_pci_barx(oct, 1);
+
+ /* fallthrough */
+ case OCT_DEV_BEGIN_STATE:
+ /* Nothing to be done here either */
+ break;
+ } /* end switch(oct->status) */
+
+ tasklet_kill(&oct_priv->droq_tasklet);
+}
+
+/**
+ * \brief Send Rx control command
+ * @param lio per-network private data
+ * @param start_stop whether to start or stop
+ */
+static void send_rx_ctrl_cmd(struct lio *lio, int start_stop)
+{
+ struct octnic_ctrl_pkt nctrl;
+ struct octnic_ctrl_params nparams;
+
+ memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));
+
+ nctrl.ncmd.s.cmd = OCTNET_CMD_RX_CTL;
+ nctrl.ncmd.s.param1 = lio->linfo.ifidx;
+ nctrl.ncmd.s.param2 = start_stop;
+ nctrl.netpndev = (u64)lio->netdev;
+
+ nparams.resp_order = OCTEON_RESP_NORESPONSE;
+
+ if (octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl, nparams) < 0)
+ netif_info(lio, rx_err, lio->netdev, "Failed to send RX Control message\n");
+}
+
+/**
+ * \brief Destroy NIC device interface
+ * @param oct octeon device
+ * @param ifidx which interface to destroy
+ *
+ * Cleanup associated with each interface for an Octeon device when NIC
+ * module is being unloaded or if initialization fails during load.
+ */
+static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx)
+{
+ struct net_device *netdev = oct->props[ifidx].netdev;
+ struct lio *lio;
+
+ if (!netdev) {
+ dev_err(&oct->pci_dev->dev, "%s No netdevice ptr for index %d\n",
+ __func__, ifidx);
+ return;
+ }
+
+ lio = GET_LIO(netdev);
+
+ dev_dbg(&oct->pci_dev->dev, "NIC device cleanup\n");
+
+ send_rx_ctrl_cmd(lio, 0);
+
+ if (atomic_read(&lio->ifstate) & LIO_IFSTATE_RUNNING)
+ txqs_stop(netdev);
+
+ if (atomic_read(&lio->ifstate) & LIO_IFSTATE_REGISTERED)
+ unregister_netdev(netdev);
+
+ delete_glist(lio);
+
+ free_netdev(netdev);
+
+ oct->props[ifidx].netdev = NULL;
+}
+
+/**
+ * \brief Stop complete NIC functionality
+ * @param oct octeon device
+ */
+static int liquidio_stop_nic_module(struct octeon_device *oct)
+{
+ int i, j;
+ struct lio *lio;
+
+ dev_dbg(&oct->pci_dev->dev, "Stopping network interfaces\n");
+ if (!oct->ifcount) {
+ dev_err(&oct->pci_dev->dev, "Init for Octeon was not completed\n");
+ return 1;
+ }
+
+ for (i = 0; i < oct->ifcount; i++) {
+ lio = GET_LIO(oct->props[i].netdev);
+ for (j = 0; j < lio->linfo.num_rxpciq; j++)
+ octeon_unregister_droq_ops(oct, lio->linfo.rxpciq[j]);
+ }
+
+ for (i = 0; i < oct->ifcount; i++)
+ liquidio_destroy_nic_device(oct, i);
+
+ dev_dbg(&oct->pci_dev->dev, "Network interfaces stopped\n");
+ return 0;
+}
+
+/**
+ * \brief Cleans up resources at unload time
+ * @param pdev PCI device structure
+ */
+static void liquidio_remove(struct pci_dev *pdev)
+{
+ struct octeon_device *oct_dev = pci_get_drvdata(pdev);
+
+ dev_dbg(&oct_dev->pci_dev->dev, "Stopping device\n");
+
+ if (oct_dev->app_mode && (oct_dev->app_mode == CVM_DRV_NIC_APP))
+ liquidio_stop_nic_module(oct_dev);
+
+ /* Reset the octeon device and cleanup all memory allocated for
+ * the octeon device by driver.
+ */
+ octeon_destroy_resources(oct_dev);
+
+ dev_info(&oct_dev->pci_dev->dev, "Device removed\n");
+
+ /* This octeon device has been removed. Update the global
+ * data structure to reflect this. Free the device structure.
+ */
+ octeon_free_device_mem(oct_dev);
+}
+
+/**
+ * \brief Identify the Octeon device and to map the BAR address space
+ * @param oct octeon device
+ */
+static int octeon_chip_specific_setup(struct octeon_device *oct)
+{
+ u32 dev_id, rev_id;
+ int ret = 1;
+
+ pci_read_config_dword(oct->pci_dev, 0, &dev_id);
+ pci_read_config_dword(oct->pci_dev, 8, &rev_id);
+ oct->rev_id = rev_id & 0xff;
+
+ switch (dev_id) {
+ case OCTEON_CN68XX_PCIID:
+ oct->chip_id = OCTEON_CN68XX;
+ ret = lio_setup_cn68xx_octeon_device(oct);
+ break;
+
+ case OCTEON_CN66XX_PCIID:
+ oct->chip_id = OCTEON_CN66XX;
+ ret = lio_setup_cn66xx_octeon_device(oct);
+ break;
+ default:
+ dev_err(&oct->pci_dev->dev, "Unknown device found (dev_id: %x)\n",
+ dev_id);
+ }
+
+ if (!ret)
+ dev_info(&oct->pci_dev->dev, "CN68XX PASS%d.%d %s\n",
+ OCTEON_MAJOR_REV(oct),
+ OCTEON_MINOR_REV(oct),
+ octeon_get_conf(oct)->card_name);
+
+ return ret;
+}
+
+/**
+ * \brief PCI initialization for each Octeon device.
+ * @param oct octeon device
+ */
+static int octeon_pci_os_setup(struct octeon_device *oct)
+{
+ /* setup PCI stuff first */
+ if (pci_enable_device(oct->pci_dev)) {
+ dev_err(&oct->pci_dev->dev, "pci_enable_device failed\n");
+ return 1;
+ }
+
+ if (dma_set_mask_and_coherent(&oct->pci_dev->dev, DMA_BIT_MASK(64))) {
+ dev_err(&oct->pci_dev->dev, "Unexpected DMA device capability\n");
+ return 1;
+ }
+
+ /* Enable PCI DMA Master. */
+ pci_set_master(oct->pci_dev);
+
+ return 0;
+}
+
+/**
+ * \brief Check Tx queue state for a given network buffer
+ * @param lio per-network private data
+ * @param skb network buffer
+ */
+static inline int check_txq_state(struct lio *lio, struct sk_buff *skb)
+{
+ int q = 0, iq = 0;
+
+ if (netif_is_multiqueue(lio->netdev)) {
+ q = skb->queue_mapping;
+ iq = lio->linfo.txpciq[(q & (lio->linfo.num_txpciq - 1))];
+ } else {
+ iq = lio->txq;
+ }
+
+ if (octnet_iq_is_full(lio->oct_dev, iq))
+ return 0;
+ wake_q(lio->netdev, q);
+ return 1;
+}
+
+/**
+ * \brief Unmap and free network buffer
+ * @param buf buffer
+ */
+static void free_netbuf(void *buf)
+{
+ struct sk_buff *skb;
+ struct octnet_buf_free_info *finfo;
+ struct lio *lio;
+
+ finfo = (struct octnet_buf_free_info *)buf;
+ skb = finfo->skb;
+ lio = finfo->lio;
+
+ dma_unmap_single(&lio->oct_dev->pci_dev->dev, finfo->dptr, skb->len,
+ DMA_TO_DEVICE);
+
+ check_txq_state(lio, skb);
+
+ recv_buffer_free((struct sk_buff *)skb);
+}
+
+/**
+ * \brief Unmap and free gather buffer
+ * @param buf buffer
+ */
+static void free_netsgbuf(void *buf)
+{
+ struct octnet_buf_free_info *finfo;
+ struct sk_buff *skb;
+ struct lio *lio;
+ struct octnic_gather *g;
+ int i, frags;
+
+ finfo = (struct octnet_buf_free_info *)buf;
+ skb = finfo->skb;
+ lio = finfo->lio;
+ g = finfo->g;
+ frags = skb_shinfo(skb)->nr_frags;
+
+ dma_unmap_single(&lio->oct_dev->pci_dev->dev,
+ g->sg[0].ptr[0], (skb->len - skb->data_len),
+ DMA_TO_DEVICE);
+
+ i = 1;
+ while (frags--) {
+ struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i - 1];
+
+ pci_unmap_page((lio->oct_dev)->pci_dev,
+ g->sg[(i >> 2)].ptr[(i & 3)],
+ frag->size, DMA_TO_DEVICE);
+ i++;
+ }
+
+ dma_unmap_single(&lio->oct_dev->pci_dev->dev,
+ finfo->dptr, g->sg_size,
+ DMA_TO_DEVICE);
+
+ spin_lock(&lio->lock);
+ list_add_tail(&g->list, &lio->glist);
+ spin_unlock(&lio->lock);
+
+ check_txq_state(lio, skb); /* mq support: sub-queue state check */
+
+ recv_buffer_free((struct sk_buff *)skb);
+}
+
+/**
+ * \brief Unmap and free gather buffer with response
+ * @param buf buffer
+ */
+static void free_netsgbuf_with_resp(void *buf)
+{
+ struct octeon_soft_command *sc;
+ struct octnet_buf_free_info *finfo;
+ struct sk_buff *skb;
+ struct lio *lio;
+ struct octnic_gather *g;
+ int i, frags;
+
+ sc = (struct octeon_soft_command *)buf;
+ skb = (struct sk_buff *)sc->callback_arg;
+ finfo = (struct octnet_buf_free_info *)&skb->cb;
+
+ lio = finfo->lio;
+ g = finfo->g;
+ frags = skb_shinfo(skb)->nr_frags;
+
+ dma_unmap_single(&lio->oct_dev->pci_dev->dev,
+ g->sg[0].ptr[0], (skb->len - skb->data_len),
+ DMA_TO_DEVICE);
+
+ i = 1;
+ while (frags--) {
+ struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i - 1];
+
+ pci_unmap_page((lio->oct_dev)->pci_dev,
+ g->sg[(i >> 2)].ptr[(i & 3)],
+ frag->size, DMA_TO_DEVICE);
+ i++;
+ }
+
+ dma_unmap_single(&lio->oct_dev->pci_dev->dev,
+ finfo->dptr, g->sg_size,
+ DMA_TO_DEVICE);
+
+ spin_lock(&lio->lock);
+ list_add_tail(&g->list, &lio->glist);
+ spin_unlock(&lio->lock);
+
+ /* Don't free the skb yet */
+
+ check_txq_state(lio, skb);
+}
+
+/**
+ * \brief Adjust ptp frequency
+ * @param ptp PTP clock info
+ * @param ppb how much to adjust by, in parts-per-billion
+ */
+static int liquidio_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+ struct lio *lio = container_of(ptp, struct lio, ptp_info);
+ struct octeon_device *oct = (struct octeon_device *)lio->oct_dev;
+ u64 comp, delta;
+ unsigned long flags;
+ bool neg_adj = false;
+
+ if (ppb < 0) {
+ neg_adj = true;
+ ppb = -ppb;
+ }
+
+ /* The hardware adds the clock compensation value to the
+ * PTP clock on every coprocessor clock cycle, so we
+ * compute the delta in terms of coprocessor clocks.
+ */
+ delta = (u64)ppb << 32;
+ do_div(delta, oct->coproc_clock_rate);
+
+ spin_lock_irqsave(&lio->ptp_lock, flags);
+ comp = lio_pci_readq(oct, CN6XXX_MIO_PTP_CLOCK_COMP);
+ if (neg_adj)
+ comp -= delta;
+ else
+ comp += delta;
+ lio_pci_writeq(oct, comp, CN6XXX_MIO_PTP_CLOCK_COMP);
+ spin_unlock_irqrestore(&lio->ptp_lock, flags);
+
+ return 0;
+}
+
+/**
+ * \brief Adjust ptp time
+ * @param ptp PTP clock info
+ * @param delta how much to adjust by, in nanosecs
+ */
+static int liquidio_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ unsigned long flags;
+ struct lio *lio = container_of(ptp, struct lio, ptp_info);
+
+ spin_lock_irqsave(&lio->ptp_lock, flags);
+ lio->ptp_adjust += delta;
+ spin_unlock_irqrestore(&lio->ptp_lock, flags);
+
+ return 0;
+}
+
+/**
+ * \brief Get hardware clock time, including any adjustment
+ * @param ptp PTP clock info
+ * @param ts timespec
+ */
+static int liquidio_ptp_gettime(struct ptp_clock_info *ptp,
+ struct timespec64 *ts)
+{
+ u64 ns;
+ u32 remainder;
+ unsigned long flags;
+ struct lio *lio = container_of(ptp, struct lio, ptp_info);
+ struct octeon_device *oct = (struct octeon_device *)lio->oct_dev;
+
+ spin_lock_irqsave(&lio->ptp_lock, flags);
+ ns = lio_pci_readq(oct, CN6XXX_MIO_PTP_CLOCK_HI);
+ ns += lio->ptp_adjust;
+ spin_unlock_irqrestore(&lio->ptp_lock, flags);
+
+ ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &remainder);
+ ts->tv_nsec = remainder;
+
+ return 0;
+}
+
+/**
+ * \brief Set hardware clock time. Reset adjustment
+ * @param ptp PTP clock info
+ * @param ts timespec
+ */
+static int liquidio_ptp_settime(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ u64 ns;
+ unsigned long flags;
+ struct lio *lio = container_of(ptp, struct lio, ptp_info);
+ struct octeon_device *oct = (struct octeon_device *)lio->oct_dev;
+
+ ns = timespec_to_ns(ts);
+
+ spin_lock_irqsave(&lio->ptp_lock, flags);
+ lio_pci_writeq(oct, ns, CN6XXX_MIO_PTP_CLOCK_HI);
+ lio->ptp_adjust = 0;
+ spin_unlock_irqrestore(&lio->ptp_lock, flags);
+
+ return 0;
+}
+
+/**
+ * \brief Check if PTP is enabled
+ * @param ptp PTP clock info
+ * @param rq request
+ * @param on is it on
+ */
+static int liquidio_ptp_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
+{
+ return -EOPNOTSUPP;
+}
+
+/**
+ * \brief Open PTP clock source
+ * @param netdev network device
+ */
+static void oct_ptp_open(struct net_device *netdev)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = (struct octeon_device *)lio->oct_dev;
+
+ spin_lock_init(&lio->ptp_lock);
+
+ snprintf(lio->ptp_info.name, 16, "%s", netdev->name);
+ lio->ptp_info.owner = THIS_MODULE;
+ lio->ptp_info.max_adj = 250000000;
+ lio->ptp_info.n_alarm = 0;
+ lio->ptp_info.n_ext_ts = 0;
+ lio->ptp_info.n_per_out = 0;
+ lio->ptp_info.pps = 0;
+ lio->ptp_info.adjfreq = liquidio_ptp_adjfreq;
+ lio->ptp_info.adjtime = liquidio_ptp_adjtime;
+ lio->ptp_info.gettime64 = liquidio_ptp_gettime;
+ lio->ptp_info.settime64 = liquidio_ptp_settime;
+ lio->ptp_info.enable = liquidio_ptp_enable;
+
+ lio->ptp_adjust = 0;
+
+ lio->ptp_clock = ptp_clock_register(&lio->ptp_info,
+ &oct->pci_dev->dev);
+
+ if (IS_ERR(lio->ptp_clock))
+ lio->ptp_clock = NULL;
+}
+
+/**
+ * \brief Init PTP clock
+ * @param oct octeon device
+ */
+static void liquidio_ptp_init(struct octeon_device *oct)
+{
+ u64 clock_comp, cfg;
+
+ clock_comp = (u64)NSEC_PER_SEC << 32;
+ do_div(clock_comp, oct->coproc_clock_rate);
+ lio_pci_writeq(oct, clock_comp, CN6XXX_MIO_PTP_CLOCK_COMP);
+
+ /* Enable */
+ cfg = lio_pci_readq(oct, CN6XXX_MIO_PTP_CLOCK_CFG);
+ lio_pci_writeq(oct, cfg | 0x01, CN6XXX_MIO_PTP_CLOCK_CFG);
+}
+
+/**
+ * \brief Load firmware to device
+ * @param oct octeon device
+ *
+ * Maps device to firmware filename, requests firmware, and downloads it
+ */
+static int load_firmware(struct octeon_device *oct)
+{
+ int ret = 0;
+ const struct firmware *fw;
+ char fw_name[LIO_MAX_FW_FILENAME_LEN];
+ char *tmp_fw_type;
+
+ if (strncmp(fw_type, LIO_FW_NAME_TYPE_NONE,
+ sizeof(LIO_FW_NAME_TYPE_NONE)) == 0) {
+ dev_info(&oct->pci_dev->dev, "Skipping firmware load\n");
+ return ret;
+ }
+
+ if (fw_type[0] == '\0')
+ tmp_fw_type = LIO_FW_NAME_TYPE_NIC;
+ else
+ tmp_fw_type = fw_type;
+
+ sprintf(fw_name, "%s%s%s_%s%s", LIO_FW_DIR, LIO_FW_BASE_NAME,
+ octeon_get_conf(oct)->card_name, tmp_fw_type,
+ LIO_FW_NAME_SUFFIX);
+
+ ret = request_firmware(&fw, fw_name, &oct->pci_dev->dev);
+ if (ret) {
+ dev_err(&oct->pci_dev->dev, "Request firmware failed. Could not find file %s.\n.",
+ fw_name);
+ return ret;
+ }
+
+ ret = octeon_download_firmware(oct, fw->data, fw->size);
+
+ release_firmware(fw);
+
+ return ret;
+}
+
+/**
+ * \brief Setup output queue
+ * @param oct octeon device
+ * @param q_no which queue
+ * @param num_descs how many descriptors
+ * @param desc_size size of each descriptor
+ * @param app_ctx application context
+ */
+static int octeon_setup_droq(struct octeon_device *oct, int q_no, int num_descs,
+ int desc_size, void *app_ctx)
+{
+ int ret_val = 0;
+
+ dev_dbg(&oct->pci_dev->dev, "Creating Droq: %d\n", q_no);
+ /* droq creation and local register settings. */
+ ret_val = octeon_create_droq(oct, q_no, num_descs, desc_size, app_ctx);
+ if (ret_val == -1)
+ return ret_val;
+
+ if (ret_val == 1) {
+ dev_dbg(&oct->pci_dev->dev, "Using default droq %d\n", q_no);
+ return 0;
+ }
+ /* tasklet creation for the droq */
+
+ /* Enable the droq queues */
+ octeon_set_droq_pkt_op(oct, q_no, 1);
+
+ /* Send Credit for Octeon Output queues. Credits are always
+ * sent after the output queue is enabled.
+ */
+ writel(oct->droq[q_no]->max_count,
+ oct->droq[q_no]->pkts_credit_reg);
+
+ return ret_val;
+}
+
+/**
+ * \brief Callback for getting interface configuration
+ * @param status status of request
+ * @param buf pointer to resp structure
+ */
+static void if_cfg_callback(struct octeon_device *oct,
+ u32 status,
+ void *buf)
+{
+ struct octeon_soft_command *sc = (struct octeon_soft_command *)buf;
+ struct liquidio_if_cfg_resp *resp;
+ struct liquidio_if_cfg_context *ctx;
+
+ resp = (struct liquidio_if_cfg_resp *)sc->virtrptr;
+ ctx = (struct liquidio_if_cfg_context *)sc->ctxptr;
+
+ oct = lio_get_device(ctx->octeon_id);
+ if (resp->status)
+ dev_err(&oct->pci_dev->dev, "nic if cfg instruction failed. Status: %llx\n",
+ CVM_CAST64(resp->status));
+ ACCESS_ONCE(ctx->cond) = 1;
+
+ /* This barrier is required to be sure that the response has been
+ * written fully before waking up the handler
+ */
+ wmb();
+
+ wake_up_interruptible(&ctx->wc);
+}
+
+/**
+ * \brief Select queue based on hash
+ * @param dev Net device
+ * @param skb sk_buff structure
+ * @returns selected queue number
+ */
+static u16 select_q(struct net_device *dev, struct sk_buff *skb,
+ void *accel_priv, select_queue_fallback_t fallback)
+{
+ int qindex;
+ struct lio *lio;
+
+ lio = GET_LIO(dev);
+ /* select queue on chosen queue_mapping or core */
+ qindex = skb_rx_queue_recorded(skb) ?
+ skb_get_rx_queue(skb) : smp_processor_id();
+ return (u16)(qindex & (lio->linfo.num_txpciq - 1));
+}
+
+/** Routine to push packets arriving on Octeon interface upto network layer.
+ * @param oct_id - octeon device id.
+ * @param skbuff - skbuff struct to be passed to network layer.
+ * @param len - size of total data received.
+ * @param rh - Control header associated with the packet
+ * @param param - additional control data with the packet
+ */
+static void
+liquidio_push_packet(u32 octeon_id,
+ void *skbuff,
+ u32 len,
+ union octeon_rh *rh,
+ void *param)
+{
+ struct napi_struct *napi = param;
+ struct octeon_device *oct = lio_get_device(octeon_id);
+ struct sk_buff *skb = (struct sk_buff *)skbuff;
+ struct skb_shared_hwtstamps *shhwtstamps;
+ u64 ns;
+ struct net_device *netdev =
+ (struct net_device *)oct->props[rh->r_dh.link].netdev;
+ struct octeon_droq *droq = container_of(param, struct octeon_droq,
+ napi);
+ if (netdev) {
+ int packet_was_received;
+ struct lio *lio = GET_LIO(netdev);
+
+ /* Do not proceed if the interface is not in RUNNING state. */
+ if (!ifstate_check(lio, LIO_IFSTATE_RUNNING)) {
+ recv_buffer_free(skb);
+ droq->stats.rx_dropped++;
+ return;
+ }
+
+ skb->dev = netdev;
+
+ if (rh->r_dh.has_hwtstamp) {
+ /* timestamp is included from the hardware at the
+ * beginning of the packet.
+ */
+ if (ifstate_check(lio,
+ LIO_IFSTATE_RX_TIMESTAMP_ENABLED)) {
+ /* Nanoseconds are in the first 64-bits
+ * of the packet.
+ */
+ memcpy(&ns, (skb->data), sizeof(ns));
+ shhwtstamps = skb_hwtstamps(skb);
+ shhwtstamps->hwtstamp =
+ ns_to_ktime(ns + lio->ptp_adjust);
+ }
+ skb_pull(skb, sizeof(ns));
+ }
+
+ skb->protocol = eth_type_trans(skb, skb->dev);
+
+ if ((netdev->features & NETIF_F_RXCSUM) &&
+ (rh->r_dh.csum_verified == CNNIC_CSUM_VERIFIED))
+ /* checksum has already been verified */
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+
+ packet_was_received = napi_gro_receive(napi, skb) != GRO_DROP;
+
+ if (packet_was_received) {
+ droq->stats.rx_bytes_received += len;
+ droq->stats.rx_pkts_received++;
+ netdev->last_rx = jiffies;
+ } else {
+ droq->stats.rx_dropped++;
+ netif_info(lio, rx_err, lio->netdev,
+ "droq:%d error rx_dropped:%llu\n",
+ droq->q_no, droq->stats.rx_dropped);
+ }
+
+ } else {
+ recv_buffer_free(skb);
+ }
+}
+
+/**
+ * \brief wrapper for calling napi_schedule
+ * @param param parameters to pass to napi_schedule
+ *
+ * Used when scheduling on different CPUs
+ */
+static void napi_schedule_wrapper(void *param)
+{
+ struct napi_struct *napi = param;
+
+ napi_schedule(napi);
+}
+
+/**
+ * \brief callback when receive interrupt occurs and we are in NAPI mode
+ * @param arg pointer to octeon output queue
+ */
+static void liquidio_napi_drv_callback(void *arg)
+{
+ struct octeon_droq *droq = arg;
+ int this_cpu = smp_processor_id();
+
+ if (droq->cpu_id == this_cpu) {
+ napi_schedule(&droq->napi);
+ } else {
+ struct call_single_data *csd = &droq->csd;
+
+ csd->func = napi_schedule_wrapper;
+ csd->info = &droq->napi;
+ csd->flags = 0;
+
+ smp_call_function_single_async(droq->cpu_id, csd);
+ }
+}
+
+/**
+ * \brief Main NAPI poll function
+ * @param droq octeon output queue
+ * @param budget maximum number of items to process
+ */
+static int liquidio_napi_do_rx(struct octeon_droq *droq, int budget)
+{
+ int work_done;
+ struct lio *lio = GET_LIO(droq->napi.dev);
+ struct octeon_device *oct = lio->oct_dev;
+
+ work_done = octeon_process_droq_poll_cmd(oct, droq->q_no,
+ POLL_EVENT_PROCESS_PKTS,
+ budget);
+ if (work_done < 0) {
+ netif_info(lio, rx_err, lio->netdev,
+ "Receive work_done < 0, rxq:%d\n", droq->q_no);
+ goto octnet_napi_finish;
+ }
+
+ if (work_done > budget)
+ dev_err(&oct->pci_dev->dev, ">>>> %s work_done: %d budget: %d\n",
+ __func__, work_done, budget);
+
+ return work_done;
+
+octnet_napi_finish:
+ napi_complete(&droq->napi);
+ octeon_process_droq_poll_cmd(oct, droq->q_no, POLL_EVENT_ENABLE_INTR,
+ 0);
+ return 0;
+}
+
+/**
+ * \brief Entry point for NAPI polling
+ * @param napi NAPI structure
+ * @param budget maximum number of items to process
+ */
+static int liquidio_napi_poll(struct napi_struct *napi, int budget)
+{
+ struct octeon_droq *droq;
+ int work_done;
+
+ droq = container_of(napi, struct octeon_droq, napi);
+
+ work_done = liquidio_napi_do_rx(droq, budget);
+
+ if (work_done < budget) {
+ napi_complete(napi);
+ octeon_process_droq_poll_cmd(droq->oct_dev, droq->q_no,
+ POLL_EVENT_ENABLE_INTR, 0);
+ return 0;
+ }
+
+ return work_done;
+}
+
+/**
+ * \brief Setup input and output queues
+ * @param octeon_dev octeon device
+ * @param net_device Net device
+ *
+ * Note: Queues are with respect to the octeon device. Thus
+ * an input queue is for egress packets, and output queues
+ * are for ingress packets.
+ */
+static inline int setup_io_queues(struct octeon_device *octeon_dev,
+ struct net_device *net_device)
+{
+ static int first_time = 1;
+ static struct octeon_droq_ops droq_ops;
+ static int cpu_id;
+ static int cpu_id_modulus;
+ struct octeon_droq *droq;
+ struct napi_struct *napi;
+ int q, q_no, retval = 0;
+ struct lio *lio;
+ int num_tx_descs;
+
+ lio = GET_LIO(net_device);
+ if (first_time) {
+ first_time = 0;
+ memset(&droq_ops, 0, sizeof(struct octeon_droq_ops));
+
+ droq_ops.fptr = liquidio_push_packet;
+
+ droq_ops.poll_mode = 1;
+ droq_ops.napi_fn = liquidio_napi_drv_callback;
+ cpu_id = 0;
+ cpu_id_modulus = num_present_cpus();
+ }
+
+ /* set up DROQs. */
+ for (q = 0; q < lio->linfo.num_rxpciq; q++) {
+ q_no = lio->linfo.rxpciq[q];
+
+ retval = octeon_setup_droq(octeon_dev, q_no,
+ CFG_GET_NUM_RX_DESCS_NIC_IF
+ (octeon_get_conf(octeon_dev),
+ lio->ifidx),
+ CFG_GET_NUM_RX_BUF_SIZE_NIC_IF
+ (octeon_get_conf(octeon_dev),
+ lio->ifidx), NULL);
+ if (retval) {
+ dev_err(&octeon_dev->pci_dev->dev,
+ " %s : Runtime DROQ(RxQ) creation failed.\n",
+ __func__);
+ return 1;
+ }
+
+ droq = octeon_dev->droq[q_no];
+ napi = &droq->napi;
+ netif_napi_add(net_device, napi, liquidio_napi_poll, 64);
+
+ /* designate a CPU for this droq */
+ droq->cpu_id = cpu_id;
+ cpu_id++;
+ if (cpu_id >= cpu_id_modulus)
+ cpu_id = 0;
+
+ octeon_register_droq_ops(octeon_dev, q_no, &droq_ops);
+ }
+
+ /* set up IQs. */
+ for (q = 0; q < lio->linfo.num_txpciq; q++) {
+ num_tx_descs = CFG_GET_NUM_TX_DESCS_NIC_IF(octeon_get_conf
+ (octeon_dev),
+ lio->ifidx);
+ retval = octeon_setup_iq(octeon_dev, lio->linfo.txpciq[q],
+ num_tx_descs,
+ netdev_get_tx_queue(net_device, q));
+ if (retval) {
+ dev_err(&octeon_dev->pci_dev->dev,
+ " %s : Runtime IQ(TxQ) creation failed.\n",
+ __func__);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Poll routine for checking transmit queue status
+ * @param work work_struct data structure
+ */
+static void octnet_poll_check_txq_status(struct work_struct *work)
+{
+ struct cavium_wk *wk = (struct cavium_wk *)work;
+ struct lio *lio = (struct lio *)wk->ctxptr;
+
+ if (!ifstate_check(lio, LIO_IFSTATE_RUNNING))
+ return;
+
+ check_txq_status(lio);
+ queue_delayed_work(lio->txq_status_wq.wq,
+ &lio->txq_status_wq.wk.work, msecs_to_jiffies(1));
+}
+
+/**
+ * \brief Sets up the txq poll check
+ * @param netdev network device
+ */
+static inline void setup_tx_poll_fn(struct net_device *netdev)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+
+ lio->txq_status_wq.wq = create_workqueue("txq-status");
+ if (!lio->txq_status_wq.wq) {
+ dev_err(&oct->pci_dev->dev, "unable to create cavium txq status wq\n");
+ return;
+ }
+ INIT_DELAYED_WORK(&lio->txq_status_wq.wk.work,
+ octnet_poll_check_txq_status);
+ lio->txq_status_wq.wk.ctxptr = lio;
+ queue_delayed_work(lio->txq_status_wq.wq,
+ &lio->txq_status_wq.wk.work, msecs_to_jiffies(1));
+}
+
+/**
+ * \brief Net device open for LiquidIO
+ * @param netdev network device
+ */
+static int liquidio_open(struct net_device *netdev)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+ struct napi_struct *napi, *n;
+
+ list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list)
+ napi_enable(napi);
+
+ oct_ptp_open(netdev);
+
+ ifstate_set(lio, LIO_IFSTATE_RUNNING);
+ setup_tx_poll_fn(netdev);
+ start_txq(netdev);
+
+ netif_info(lio, ifup, lio->netdev, "Interface Open, ready for traffic\n");
+ try_module_get(THIS_MODULE);
+
+ /* tell Octeon to start forwarding packets to host */
+ send_rx_ctrl_cmd(lio, 1);
+
+ /* Ready for link status updates */
+ lio->intf_open = 1;
+
+ dev_info(&oct->pci_dev->dev, "%s interface is opened\n",
+ netdev->name);
+
+ return 0;
+}
+
+/**
+ * \brief Net device stop for LiquidIO
+ * @param netdev network device
+ */
+static int liquidio_stop(struct net_device *netdev)
+{
+ struct napi_struct *napi, *n;
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+
+ netif_info(lio, ifdown, lio->netdev, "Stopping interface!\n");
+ /* Inform that netif carrier is down */
+ lio->intf_open = 0;
+ lio->linfo.link.s.status = 0;
+
+ netif_carrier_off(netdev);
+
+ /* tell Octeon to stop forwarding packets to host */
+ send_rx_ctrl_cmd(lio, 0);
+
+ cancel_delayed_work_sync(&lio->txq_status_wq.wk.work);
+ flush_workqueue(lio->txq_status_wq.wq);
+ destroy_workqueue(lio->txq_status_wq.wq);
+
+ if (lio->ptp_clock) {
+ ptp_clock_unregister(lio->ptp_clock);
+ lio->ptp_clock = NULL;
+ }
+
+ ifstate_reset(lio, LIO_IFSTATE_RUNNING);
+
+ /* This is a hack that allows DHCP to continue working. */
+ set_bit(__LINK_STATE_START, &lio->netdev->state);
+
+ list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list)
+ napi_disable(napi);
+
+ txqs_stop(netdev);
+
+ dev_info(&oct->pci_dev->dev, "%s interface is stopped\n", netdev->name);
+ module_put(THIS_MODULE);
+
+ return 0;
+}
+
+void liquidio_link_ctrl_cmd_completion(void *nctrl_ptr)
+{
+ struct octnic_ctrl_pkt *nctrl = (struct octnic_ctrl_pkt *)nctrl_ptr;
+ struct net_device *netdev = (struct net_device *)nctrl->netpndev;
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+
+ switch (nctrl->ncmd.s.cmd) {
+ case OCTNET_CMD_CHANGE_DEVFLAGS:
+ case OCTNET_CMD_SET_MULTI_LIST:
+ break;
+
+ case OCTNET_CMD_CHANGE_MACADDR:
+ /* If command is successful, change the MACADDR. */
+ netif_info(lio, probe, lio->netdev, " MACAddr changed to 0x%llx\n",
+ CVM_CAST64(nctrl->udd[0]));
+ dev_info(&oct->pci_dev->dev, "%s MACAddr changed to 0x%llx\n",
+ netdev->name, CVM_CAST64(nctrl->udd[0]));
+ memcpy(netdev->dev_addr, ((u8 *)&nctrl->udd[0]) + 2, ETH_ALEN);
+ break;
+
+ case OCTNET_CMD_CHANGE_MTU:
+ /* If command is successful, change the MTU. */
+ netif_info(lio, probe, lio->netdev, " MTU Changed from %d to %d\n",
+ netdev->mtu, nctrl->ncmd.s.param2);
+ dev_info(&oct->pci_dev->dev, "%s MTU Changed from %d to %d\n",
+ netdev->name, netdev->mtu,
+ nctrl->ncmd.s.param2);
+ netdev->mtu = nctrl->ncmd.s.param2;
+ break;
+
+ case OCTNET_CMD_GPIO_ACCESS:
+ netif_info(lio, probe, lio->netdev, "LED Flashing visual identification\n");
+
+ break;
+
+ case OCTNET_CMD_LRO_ENABLE:
+ dev_info(&oct->pci_dev->dev, "%s LRO Enabled\n", netdev->name);
+ break;
+
+ case OCTNET_CMD_LRO_DISABLE:
+ dev_info(&oct->pci_dev->dev, "%s LRO Disabled\n",
+ netdev->name);
+ break;
+
+ case OCTNET_CMD_VERBOSE_ENABLE:
+ dev_info(&oct->pci_dev->dev, "%s LRO Enabled\n", netdev->name);
+ break;
+
+ case OCTNET_CMD_VERBOSE_DISABLE:
+ dev_info(&oct->pci_dev->dev, "%s LRO Disabled\n",
+ netdev->name);
+ break;
+
+ case OCTNET_CMD_SET_SETTINGS:
+ dev_info(&oct->pci_dev->dev, "%s settings changed\n",
+ netdev->name);
+
+ break;
+
+ default:
+ dev_err(&oct->pci_dev->dev, "%s Unknown cmd %d\n", __func__,
+ nctrl->ncmd.s.cmd);
+ }
+}
+
+/**
+ * \brief Converts a mask based on net device flags
+ * @param netdev network device
+ *
+ * This routine generates a octnet_ifflags mask from the net device flags
+ * received from the OS.
+ */
+static inline enum octnet_ifflags get_new_flags(struct net_device *netdev)
+{
+ enum octnet_ifflags f = OCTNET_IFFLAG_UNICAST;
+
+ if (netdev->flags & IFF_PROMISC)
+ f |= OCTNET_IFFLAG_PROMISC;
+
+ if (netdev->flags & IFF_ALLMULTI)
+ f |= OCTNET_IFFLAG_ALLMULTI;
+
+ if (netdev->flags & IFF_MULTICAST) {
+ f |= OCTNET_IFFLAG_MULTICAST;
+
+ /* Accept all multicast addresses if there are more than we
+ * can handle
+ */
+ if (netdev_mc_count(netdev) > MAX_OCTEON_MULTICAST_ADDR)
+ f |= OCTNET_IFFLAG_ALLMULTI;
+ }
+
+ if (netdev->flags & IFF_BROADCAST)
+ f |= OCTNET_IFFLAG_BROADCAST;
+
+ return f;
+}
+
+/**
+ * \brief Net device set_multicast_list
+ * @param netdev network device
+ */
+static void liquidio_set_mcast_list(struct net_device *netdev)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+ struct octnic_ctrl_pkt nctrl;
+ struct octnic_ctrl_params nparams;
+ struct netdev_hw_addr *ha;
+ u64 *mc;
+ int ret, i;
+ int mc_count = min(netdev_mc_count(netdev), MAX_OCTEON_MULTICAST_ADDR);
+
+ memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));
+
+ /* Create a ctrl pkt command to be sent to core app. */
+ nctrl.ncmd.u64 = 0;
+ nctrl.ncmd.s.cmd = OCTNET_CMD_SET_MULTI_LIST;
+ nctrl.ncmd.s.param1 = lio->linfo.ifidx;
+ nctrl.ncmd.s.param2 = get_new_flags(netdev);
+ nctrl.ncmd.s.param3 = mc_count;
+ nctrl.ncmd.s.more = mc_count;
+ nctrl.netpndev = (u64)netdev;
+ nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
+
+ /* copy all the addresses into the udd */
+ i = 0;
+ mc = &nctrl.udd[0];
+ netdev_for_each_mc_addr(ha, netdev) {
+ *mc = 0;
+ memcpy(((u8 *)mc) + 2, ha->addr, ETH_ALEN);
+ /* no need to swap bytes */
+
+ if (++mc > &nctrl.udd[mc_count])
+ break;
+ }
+
+ /* Apparently, any activity in this call from the kernel has to
+ * be atomic. So we won't wait for response.
+ */
+ nctrl.wait_time = 0;
+
+ nparams.resp_order = OCTEON_RESP_NORESPONSE;
+
+ ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl, nparams);
+ if (ret < 0) {
+ dev_err(&oct->pci_dev->dev, "DEVFLAGS change failed in core (ret: 0x%x)\n",
+ ret);
+ }
+}
+
+/**
+ * \brief Net device set_mac_address
+ * @param netdev network device
+ */
+static int liquidio_set_mac(struct net_device *netdev, void *p)
+{
+ int ret = 0;
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+ struct sockaddr *addr = (struct sockaddr *)p;
+ struct octnic_ctrl_pkt nctrl;
+ struct octnic_ctrl_params nparams;
+
+ if ((!is_valid_ether_addr(addr->sa_data)) ||
+ (ifstate_check(lio, LIO_IFSTATE_RUNNING)))
+ return -EADDRNOTAVAIL;
+
+ memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));
+
+ nctrl.ncmd.u64 = 0;
+ nctrl.ncmd.s.cmd = OCTNET_CMD_CHANGE_MACADDR;
+ nctrl.ncmd.s.param1 = lio->linfo.ifidx;
+ nctrl.ncmd.s.param2 = 0;
+ nctrl.ncmd.s.more = 1;
+ nctrl.netpndev = (u64)netdev;
+ nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
+ nctrl.wait_time = 100;
+
+ nctrl.udd[0] = 0;
+ /* The MAC Address is presented in network byte order. */
+ memcpy((u8 *)&nctrl.udd[0] + 2, addr->sa_data, ETH_ALEN);
+
+ nparams.resp_order = OCTEON_RESP_ORDERED;
+
+ ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl, nparams);
+ if (ret < 0) {
+ dev_err(&oct->pci_dev->dev, "MAC Address change failed\n");
+ return -ENOMEM;
+ }
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ memcpy(((u8 *)&lio->linfo.hw_addr) + 2, addr->sa_data, ETH_ALEN);
+
+ return 0;
+}
+
+/**
+ * \brief Net device get_stats
+ * @param netdev network device
+ */
+static struct net_device_stats *liquidio_get_stats(struct net_device *netdev)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct net_device_stats *stats = &netdev->stats;
+ struct octeon_device *oct;
+ u64 pkts = 0, drop = 0, bytes = 0;
+ struct oct_droq_stats *oq_stats;
+ struct oct_iq_stats *iq_stats;
+ int i, iq_no, oq_no;
+
+ oct = lio->oct_dev;
+
+ for (i = 0; i < lio->linfo.num_txpciq; i++) {
+ iq_no = lio->linfo.txpciq[i];
+ iq_stats = &oct->instr_queue[iq_no]->stats;
+ pkts += iq_stats->tx_done;
+ drop += iq_stats->tx_dropped;
+ bytes += iq_stats->tx_tot_bytes;
+ }
+
+ stats->tx_packets = pkts;
+ stats->tx_bytes = bytes;
+ stats->tx_dropped = drop;
+
+ pkts = 0;
+ drop = 0;
+ bytes = 0;
+
+ for (i = 0; i < lio->linfo.num_rxpciq; i++) {
+ oq_no = lio->linfo.rxpciq[i];
+ oq_stats = &oct->droq[oq_no]->stats;
+ pkts += oq_stats->rx_pkts_received;
+ drop += (oq_stats->rx_dropped +
+ oq_stats->dropped_nodispatch +
+ oq_stats->dropped_toomany +
+ oq_stats->dropped_nomem);
+ bytes += oq_stats->rx_bytes_received;
+ }
+
+ stats->rx_bytes = bytes;
+ stats->rx_packets = pkts;
+ stats->rx_dropped = drop;
+
+ return stats;
+}
+
+/**
+ * \brief Net device change_mtu
+ * @param netdev network device
+ */
+static int liquidio_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+ struct octnic_ctrl_pkt nctrl;
+ struct octnic_ctrl_params nparams;
+ int max_frm_size = new_mtu + OCTNET_FRM_HEADER_SIZE;
+ int ret = 0;
+
+ /* Limit the MTU to make sure the ethernet packets are between 64 bytes
+ * and 65535 bytes
+ */
+ if ((max_frm_size < OCTNET_MIN_FRM_SIZE) ||
+ (max_frm_size > OCTNET_MAX_FRM_SIZE)) {
+ dev_err(&oct->pci_dev->dev, "Invalid MTU: %d\n", new_mtu);
+ dev_err(&oct->pci_dev->dev, "Valid range %d and %d\n",
+ (OCTNET_MIN_FRM_SIZE - OCTNET_FRM_HEADER_SIZE),
+ (OCTNET_MAX_FRM_SIZE - OCTNET_FRM_HEADER_SIZE));
+ return -EINVAL;
+ }
+
+ memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));
+
+ nctrl.ncmd.u64 = 0;
+ nctrl.ncmd.s.cmd = OCTNET_CMD_CHANGE_MTU;
+ nctrl.ncmd.s.param1 = lio->linfo.ifidx;
+ nctrl.ncmd.s.param2 = new_mtu;
+ nctrl.wait_time = 100;
+ nctrl.netpndev = (u64)netdev;
+ nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
+
+ nparams.resp_order = OCTEON_RESP_ORDERED;
+
+ ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl, nparams);
+ if (ret < 0) {
+ dev_err(&oct->pci_dev->dev, "Failed to set MTU\n");
+ return -1;
+ }
+
+ lio->mtu = new_mtu;
+
+ return 0;
+}
+
+/**
+ * \brief Handler for SIOCSHWTSTAMP ioctl
+ * @param netdev network device
+ * @param ifr interface request
+ * @param cmd command
+ */
+static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct hwtstamp_config conf;
+ struct lio *lio = GET_LIO(netdev);
+
+ if (copy_from_user(&conf, ifr->ifr_data, sizeof(conf)))
+ return -EFAULT;
+
+ if (conf.flags)
+ return -EINVAL;
+
+ switch (conf.tx_type) {
+ case HWTSTAMP_TX_ON:
+ case HWTSTAMP_TX_OFF:
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (conf.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ break;
+ case HWTSTAMP_FILTER_ALL:
+ case HWTSTAMP_FILTER_SOME:
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ conf.rx_filter = HWTSTAMP_FILTER_ALL;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ if (conf.rx_filter == HWTSTAMP_FILTER_ALL)
+ ifstate_set(lio, LIO_IFSTATE_RX_TIMESTAMP_ENABLED);
+
+ else
+ ifstate_reset(lio, LIO_IFSTATE_RX_TIMESTAMP_ENABLED);
+
+ return copy_to_user(ifr->ifr_data, &conf, sizeof(conf)) ? -EFAULT : 0;
+}
+
+/**
+ * \brief ioctl handler
+ * @param netdev network device
+ * @param ifr interface request
+ * @param cmd command
+ */
+static int liquidio_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ switch (cmd) {
+ case SIOCSHWTSTAMP:
+ return hwtstamp_ioctl(netdev, ifr, cmd);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+/**
+ * \brief handle a Tx timestamp response
+ * @param status response status
+ * @param buf pointer to skb
+ */
+static void handle_timestamp(struct octeon_device *oct,
+ u32 status,
+ void *buf)
+{
+ struct octnet_buf_free_info *finfo;
+ struct octeon_soft_command *sc;
+ struct oct_timestamp_resp *resp;
+ struct lio *lio;
+ struct sk_buff *skb = (struct sk_buff *)buf;
+
+ finfo = (struct octnet_buf_free_info *)skb->cb;
+ lio = finfo->lio;
+ sc = finfo->sc;
+ oct = lio->oct_dev;
+ resp = (struct oct_timestamp_resp *)sc->virtrptr;
+
+ if (status != OCTEON_REQUEST_DONE) {
+ dev_err(&oct->pci_dev->dev, "Tx timestamp instruction failed. Status: %llx\n",
+ CVM_CAST64(status));
+ resp->timestamp = 0;
+ }
+
+ octeon_swap_8B_data(&resp->timestamp, 1);
+
+ if (unlikely((skb_shinfo(skb)->tx_flags | SKBTX_IN_PROGRESS) != 0)) {
+ struct skb_shared_hwtstamps ts;
+ u64 ns = resp->timestamp;
+
+ netif_info(lio, tx_done, lio->netdev,
+ "Got resulting SKBTX_HW_TSTAMP skb=%p ns=%016llu\n",
+ skb, (unsigned long long)ns);
+ ts.hwtstamp = ns_to_ktime(ns + lio->ptp_adjust);
+ skb_tstamp_tx(skb, &ts);
+ }
+
+ octeon_free_soft_command(oct, sc);
+ recv_buffer_free(skb);
+}
+
+/* \brief Send a data packet that will be timestamped
+ * @param oct octeon device
+ * @param ndata pointer to network data
+ * @param finfo pointer to private network data
+ */
+static inline int send_nic_timestamp_pkt(struct octeon_device *oct,
+ struct octnic_data_pkt *ndata,
+ struct octnet_buf_free_info *finfo,
+ int xmit_more)
+{
+ int retval;
+ struct octeon_soft_command *sc;
+ struct octeon_instr_ih *ih;
+ struct octeon_instr_rdp *rdp;
+ struct lio *lio;
+ int ring_doorbell;
+
+ lio = finfo->lio;
+
+ sc = octeon_alloc_soft_command_resp(oct, &ndata->cmd,
+ sizeof(struct oct_timestamp_resp));
+ finfo->sc = sc;
+
+ if (!sc) {
+ dev_err(&oct->pci_dev->dev, "No memory for timestamped data packet\n");
+ return IQ_SEND_FAILED;
+ }
+
+ if (ndata->reqtype == REQTYPE_NORESP_NET)
+ ndata->reqtype = REQTYPE_RESP_NET;
+ else if (ndata->reqtype == REQTYPE_NORESP_NET_SG)
+ ndata->reqtype = REQTYPE_RESP_NET_SG;
+
+ sc->callback = handle_timestamp;
+ sc->callback_arg = finfo->skb;
+ sc->iq_no = ndata->q_no;
+
+ ih = (struct octeon_instr_ih *)&sc->cmd.ih;
+ rdp = (struct octeon_instr_rdp *)&sc->cmd.rdp;
+
+ ring_doorbell = !xmit_more;
+ retval = octeon_send_command(oct, sc->iq_no, ring_doorbell, &sc->cmd,
+ sc, ih->dlengsz, ndata->reqtype);
+
+ if (retval) {
+ dev_err(&oct->pci_dev->dev, "timestamp data packet failed status: %x\n",
+ retval);
+ octeon_free_soft_command(oct, sc);
+ } else {
+ netif_info(lio, tx_queued, lio->netdev, "Queued timestamp packet\n");
+ }
+
+ return retval;
+}
+
+static inline int is_ipv4(struct sk_buff *skb)
+{
+ return (skb->protocol == htons(ETH_P_IP)) &&
+ (ip_hdr(skb)->version == 4);
+}
+
+static inline int is_vlan(struct sk_buff *skb)
+{
+ return skb->protocol == htons(ETH_P_8021Q);
+}
+
+static inline int is_ip_fragmented(struct sk_buff *skb)
+{
+ /* The Don't fragment and Reserved flag fields are ignored.
+ * IP is fragmented if
+ * - the More fragments bit is set (indicating this IP is a fragment
+ * with more to follow; the current offset could be 0 ).
+ * - ths offset field is non-zero.
+ */
+ return (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) ? 1 : 0;
+}
+
+static inline int is_ipv6(struct sk_buff *skb)
+{
+ return (skb->protocol == htons(ETH_P_IPV6)) &&
+ (ipv6_hdr(skb)->version == 6);
+}
+
+static inline int is_with_extn_hdr(struct sk_buff *skb)
+{
+ return (ipv6_hdr(skb)->nexthdr != IPPROTO_TCP) &&
+ (ipv6_hdr(skb)->nexthdr != IPPROTO_UDP);
+}
+
+static inline int is_tcpudp(struct sk_buff *skb)
+{
+ return (ip_hdr(skb)->protocol == IPPROTO_TCP) ||
+ (ip_hdr(skb)->protocol == IPPROTO_UDP);
+}
+
+static inline u32 get_ipv4_5tuple_tag(struct sk_buff *skb)
+{
+ u32 tag;
+ struct iphdr *iphdr = ip_hdr(skb);
+
+ tag = crc32(0, &iphdr->protocol, 1);
+ tag = crc32(tag, (u8 *)&iphdr->saddr, 8);
+ tag = crc32(tag, skb_transport_header(skb), 4);
+ return tag;
+}
+
+static inline u32 get_ipv6_5tuple_tag(struct sk_buff *skb)
+{
+ u32 tag;
+ struct ipv6hdr *ipv6hdr = ipv6_hdr(skb);
+
+ tag = crc32(0, &ipv6hdr->nexthdr, 1);
+ tag = crc32(tag, (u8 *)&ipv6hdr->saddr, 32);
+ tag = crc32(tag, skb_transport_header(skb), 4);
+ return tag;
+}
+
+/** \brief Transmit networks packets to the Octeon interface
+ * @param skbuff skbuff struct to be passed to network layer.
+ * @param netdev pointer to network device
+ * @returns whether the packet was transmitted to the device okay or not
+ * (NETDEV_TX_OK or NETDEV_TX_BUSY)
+ */
+static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct lio *lio;
+ struct octnet_buf_free_info *finfo;
+ union octnic_cmd_setup cmdsetup;
+ struct octnic_data_pkt ndata;
+ struct octeon_device *oct;
+ struct oct_iq_stats *stats;
+ int cpu = 0, status = 0;
+ int q_idx = 0, iq_no = 0;
+ int xmit_more;
+ u32 tag = 0;
+
+ lio = GET_LIO(netdev);
+ oct = lio->oct_dev;
+
+ if (netif_is_multiqueue(netdev)) {
+ cpu = skb->queue_mapping;
+ q_idx = (cpu & (lio->linfo.num_txpciq - 1));
+ iq_no = lio->linfo.txpciq[q_idx];
+ } else {
+ iq_no = lio->txq;
+ }
+
+ stats = &oct->instr_queue[iq_no]->stats;
+
+ /* Check for all conditions in which the current packet cannot be
+ * transmitted.
+ */
+ if (!(atomic_read(&lio->ifstate) & LIO_IFSTATE_RUNNING) ||
+ (!lio->linfo.link.s.status) ||
+ (skb->len <= 0)) {
+ netif_info(lio, tx_err, lio->netdev,
+ "Transmit failed link_status : %d\n",
+ lio->linfo.link.s.status);
+ goto lio_xmit_failed;
+ }
+
+ /* Use space in skb->cb to store info used to unmap and
+ * free the buffers.
+ */
+ finfo = (struct octnet_buf_free_info *)skb->cb;
+ finfo->lio = lio;
+ finfo->skb = skb;
+ finfo->sc = NULL;
+
+ /* Prepare the attributes for the data to be passed to OSI. */
+ memset(&ndata, 0, sizeof(struct octnic_data_pkt));
+
+ ndata.buf = (void *)finfo;
+
+ ndata.q_no = iq_no;
+
+ if (netif_is_multiqueue(netdev)) {
+ if (octnet_iq_is_full(oct, ndata.q_no)) {
+ /* defer sending if queue is full */
+ netif_info(lio, tx_err, lio->netdev, "Transmit failed iq:%d full\n",
+ ndata.q_no);
+ stats->tx_iq_busy++;
+ return NETDEV_TX_BUSY;
+ }
+ } else {
+ if (octnet_iq_is_full(oct, lio->txq)) {
+ /* defer sending if queue is full */
+ stats->tx_iq_busy++;
+ netif_info(lio, tx_err, lio->netdev, "Transmit failed iq:%d full\n",
+ ndata.q_no);
+ return NETDEV_TX_BUSY;
+ }
+ }
+ /* pr_info(" XMIT - valid Qs: %d, 1st Q no: %d, cpu: %d, q_no:%d\n",
+ * lio->linfo.num_txpciq, lio->txq, cpu, ndata.q_no );
+ */
+
+ ndata.datasize = skb->len;
+
+ cmdsetup.u64 = 0;
+ cmdsetup.s.ifidx = lio->linfo.ifidx;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (is_ipv4(skb) && !is_ip_fragmented(skb) && is_tcpudp(skb)) {
+ tag = get_ipv4_5tuple_tag(skb);
+
+ cmdsetup.s.cksum_offset = sizeof(struct ethhdr) + 1;
+
+ if (ip_hdr(skb)->ihl > 5)
+ cmdsetup.s.ipv4opts_ipv6exthdr =
+ OCT_PKT_PARAM_IPV4OPTS;
+
+ } else if (is_ipv6(skb)) {
+ tag = get_ipv6_5tuple_tag(skb);
+
+ cmdsetup.s.cksum_offset = sizeof(struct ethhdr) + 1;
+
+ if (is_with_extn_hdr(skb))
+ cmdsetup.s.ipv4opts_ipv6exthdr =
+ OCT_PKT_PARAM_IPV6EXTHDR;
+
+ } else if (is_vlan(skb)) {
+ if (vlan_eth_hdr(skb)->h_vlan_encapsulated_proto
+ == htons(ETH_P_IP) &&
+ !is_ip_fragmented(skb) && is_tcpudp(skb)) {
+ tag = get_ipv4_5tuple_tag(skb);
+
+ cmdsetup.s.cksum_offset =
+ sizeof(struct vlan_ethhdr) + 1;
+
+ if (ip_hdr(skb)->ihl > 5)
+ cmdsetup.s.ipv4opts_ipv6exthdr =
+ OCT_PKT_PARAM_IPV4OPTS;
+
+ } else if (vlan_eth_hdr(skb)->h_vlan_encapsulated_proto
+ == htons(ETH_P_IPV6)) {
+ tag = get_ipv6_5tuple_tag(skb);
+
+ cmdsetup.s.cksum_offset =
+ sizeof(struct vlan_ethhdr) + 1;
+
+ if (is_with_extn_hdr(skb))
+ cmdsetup.s.ipv4opts_ipv6exthdr =
+ OCT_PKT_PARAM_IPV6EXTHDR;
+ }
+ }
+ }
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ cmdsetup.s.timestamp = 1;
+ }
+
+ if (skb_shinfo(skb)->nr_frags == 0) {
+ cmdsetup.s.u.datasize = skb->len;
+ octnet_prepare_pci_cmd(&ndata.cmd, &cmdsetup, tag);
+ /* Offload checksum calculation for TCP/UDP packets */
+ ndata.cmd.dptr = dma_map_single(&oct->pci_dev->dev,
+ skb->data,
+ skb->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&oct->pci_dev->dev, ndata.cmd.dptr)) {
+ dev_err(&oct->pci_dev->dev, "%s DMA mapping error 1\n",
+ __func__);
+ return NETDEV_TX_BUSY;
+ }
+
+ finfo->dptr = ndata.cmd.dptr;
+
+ ndata.reqtype = REQTYPE_NORESP_NET;
+
+ } else {
+ int i, frags;
+ struct skb_frag_struct *frag;
+ struct octnic_gather *g;
+
+ spin_lock(&lio->lock);
+ g = (struct octnic_gather *)list_delete_head(&lio->glist);
+ spin_unlock(&lio->lock);
+
+ if (!g) {
+ netif_info(lio, tx_err, lio->netdev,
+ "Transmit scatter gather: glist null!\n");
+ goto lio_xmit_failed;
+ }
+
+ cmdsetup.s.gather = 1;
+ cmdsetup.s.u.gatherptrs = (skb_shinfo(skb)->nr_frags + 1);
+ octnet_prepare_pci_cmd(&ndata.cmd, &cmdsetup, tag);
+
+ memset(g->sg, 0, g->sg_size);
+
+ g->sg[0].ptr[0] = dma_map_single(&oct->pci_dev->dev,
+ skb->data,
+ (skb->len - skb->data_len),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&oct->pci_dev->dev, g->sg[0].ptr[0])) {
+ dev_err(&oct->pci_dev->dev, "%s DMA mapping error 2\n",
+ __func__);
+ return NETDEV_TX_BUSY;
+ }
+ add_sg_size(&g->sg[0], (skb->len - skb->data_len), 0);
+
+ frags = skb_shinfo(skb)->nr_frags;
+ i = 1;
+ while (frags--) {
+ frag = &skb_shinfo(skb)->frags[i - 1];
+
+ g->sg[(i >> 2)].ptr[(i & 3)] =
+ dma_map_page(&oct->pci_dev->dev,
+ frag->page.p,
+ frag->page_offset,
+ frag->size,
+ DMA_TO_DEVICE);
+
+ add_sg_size(&g->sg[(i >> 2)], frag->size, (i & 3));
+ i++;
+ }
+
+ ndata.cmd.dptr = dma_map_single(&oct->pci_dev->dev,
+ g->sg, g->sg_size,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&oct->pci_dev->dev, ndata.cmd.dptr)) {
+ dev_err(&oct->pci_dev->dev, "%s DMA mapping error 3\n",
+ __func__);
+ dma_unmap_single(&oct->pci_dev->dev, g->sg[0].ptr[0],
+ skb->len - skb->data_len,
+ DMA_TO_DEVICE);
+ return NETDEV_TX_BUSY;
+ }
+
+ finfo->dptr = ndata.cmd.dptr;
+ finfo->g = g;
+
+ ndata.reqtype = REQTYPE_NORESP_NET_SG;
+ }
+
+ if (skb_shinfo(skb)->gso_size) {
+ struct octeon_instr_irh *irh =
+ (struct octeon_instr_irh *)&ndata.cmd.irh;
+ union tx_info *tx_info = (union tx_info *)&ndata.cmd.ossp[0];
+
+ irh->len = 1; /* to indicate that ossp[0] contains tx_info */
+ tx_info->s.gso_size = skb_shinfo(skb)->gso_size;
+ tx_info->s.gso_segs = skb_shinfo(skb)->gso_segs;
+ }
+
+ xmit_more = skb->xmit_more;
+
+ if (unlikely(cmdsetup.s.timestamp))
+ status = send_nic_timestamp_pkt(oct, &ndata, finfo, xmit_more);
+ else
+ status = octnet_send_nic_data_pkt(oct, &ndata, xmit_more);
+ if (status == IQ_SEND_FAILED)
+ goto lio_xmit_failed;
+
+ netif_info(lio, tx_queued, lio->netdev, "Transmit queued successfully\n");
+
+ if (status == IQ_SEND_STOP)
+ stop_q(lio->netdev, q_idx);
+
+ netdev->trans_start = jiffies;
+
+ stats->tx_done++;
+ stats->tx_tot_bytes += skb->len;
+
+ return NETDEV_TX_OK;
+
+lio_xmit_failed:
+ stats->tx_dropped++;
+ netif_info(lio, tx_err, lio->netdev, "IQ%d Transmit dropped:%llu\n",
+ iq_no, stats->tx_dropped);
+ dma_unmap_single(&oct->pci_dev->dev, ndata.cmd.dptr,
+ ndata.datasize, DMA_TO_DEVICE);
+ recv_buffer_free(skb);
+ return NETDEV_TX_OK;
+}
+
+/** \brief Network device Tx timeout
+ * @param netdev pointer to network device
+ */
+static void liquidio_tx_timeout(struct net_device *netdev)
+{
+ struct lio *lio;
+
+ lio = GET_LIO(netdev);
+
+ netif_info(lio, tx_err, lio->netdev,
+ "Transmit timeout tx_dropped:%ld, waking up queues now!!\n",
+ netdev->stats.tx_dropped);
+ netdev->trans_start = jiffies;
+ txqs_wake(netdev);
+}
+
+int liquidio_set_feature(struct net_device *netdev, int cmd)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+ struct octnic_ctrl_pkt nctrl;
+ struct octnic_ctrl_params nparams;
+ int ret = 0;
+
+ memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));
+
+ nctrl.ncmd.u64 = 0;
+ nctrl.ncmd.s.cmd = cmd;
+ nctrl.ncmd.s.param1 = lio->linfo.ifidx;
+ nctrl.ncmd.s.param2 = OCTNIC_LROIPV4 | OCTNIC_LROIPV6;
+ nctrl.wait_time = 100;
+ nctrl.netpndev = (u64)netdev;
+ nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
+
+ nparams.resp_order = OCTEON_RESP_NORESPONSE;
+
+ ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl, nparams);
+ if (ret < 0) {
+ dev_err(&oct->pci_dev->dev, "Feature change failed in core (ret: 0x%x)\n",
+ ret);
+ }
+ return ret;
+}
+
+/** \brief Net device fix features
+ * @param netdev pointer to network device
+ * @param request features requested
+ * @returns updated features list
+ */
+static netdev_features_t liquidio_fix_features(struct net_device *netdev,
+ netdev_features_t request)
+{
+ struct lio *lio = netdev_priv(netdev);
+
+ if ((request & NETIF_F_RXCSUM) &&
+ !(lio->dev_capability & NETIF_F_RXCSUM))
+ request &= ~NETIF_F_RXCSUM;
+
+ if ((request & NETIF_F_HW_CSUM) &&
+ !(lio->dev_capability & NETIF_F_HW_CSUM))
+ request &= ~NETIF_F_HW_CSUM;
+
+ if ((request & NETIF_F_TSO) && !(lio->dev_capability & NETIF_F_TSO))
+ request &= ~NETIF_F_TSO;
+
+ if ((request & NETIF_F_TSO6) && !(lio->dev_capability & NETIF_F_TSO6))
+ request &= ~NETIF_F_TSO6;
+
+ if ((request & NETIF_F_LRO) && !(lio->dev_capability & NETIF_F_LRO))
+ request &= ~NETIF_F_LRO;
+
+ /*Disable LRO if RXCSUM is off */
+ if (!(request & NETIF_F_RXCSUM) && (netdev->features & NETIF_F_LRO) &&
+ (lio->dev_capability & NETIF_F_LRO))
+ request &= ~NETIF_F_LRO;
+
+ return request;
+}
+
+/** \brief Net device set features
+ * @param netdev pointer to network device
+ * @param features features to enable/disable
+ */
+static int liquidio_set_features(struct net_device *netdev,
+ netdev_features_t features)
+{
+ struct lio *lio = netdev_priv(netdev);
+
+ if (!((netdev->features ^ features) & NETIF_F_LRO))
+ return 0;
+
+ if ((features & NETIF_F_LRO) && (lio->dev_capability & NETIF_F_LRO))
+ liquidio_set_feature(netdev, OCTNET_CMD_LRO_ENABLE);
+ else if (!(features & NETIF_F_LRO) &&
+ (lio->dev_capability & NETIF_F_LRO))
+ liquidio_set_feature(netdev, OCTNET_CMD_LRO_DISABLE);
+
+ return 0;
+}
+
+static struct net_device_ops lionetdevops = {
+ .ndo_open = liquidio_open,
+ .ndo_stop = liquidio_stop,
+ .ndo_start_xmit = liquidio_xmit,
+ .ndo_get_stats = liquidio_get_stats,
+ .ndo_set_mac_address = liquidio_set_mac,
+ .ndo_set_rx_mode = liquidio_set_mcast_list,
+ .ndo_tx_timeout = liquidio_tx_timeout,
+ .ndo_change_mtu = liquidio_change_mtu,
+ .ndo_do_ioctl = liquidio_ioctl,
+ .ndo_fix_features = liquidio_fix_features,
+ .ndo_set_features = liquidio_set_features,
+};
+
+/** \brief Entry point for the liquidio module
+ */
+static int __init liquidio_init(void)
+{
+ int i;
+ struct handshake *hs;
+
+ init_completion(&first_stage);
+
+ octeon_init_device_list(conf_type);
+
+ if (liquidio_init_pci())
+ return -EINVAL;
+
+ wait_for_completion_timeout(&first_stage, msecs_to_jiffies(1000));
+
+ for (i = 0; i < MAX_OCTEON_DEVICES; i++) {
+ hs = &handshake[i];
+ if (hs->pci_dev) {
+ wait_for_completion(&hs->init);
+ if (!hs->init_ok) {
+ /* init handshake failed */
+ dev_err(&hs->pci_dev->dev,
+ "Failed to init device\n");
+ liquidio_deinit_pci();
+ return -EIO;
+ }
+ }
+ }
+
+ for (i = 0; i < MAX_OCTEON_DEVICES; i++) {
+ hs = &handshake[i];
+ if (hs->pci_dev) {
+ wait_for_completion_timeout(&hs->started,
+ msecs_to_jiffies(30000));
+ if (!hs->started_ok) {
+ /* starter handshake failed */
+ dev_err(&hs->pci_dev->dev,
+ "Firmware failed to start\n");
+ liquidio_deinit_pci();
+ return -EIO;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int lio_nic_info(struct octeon_recv_info *recv_info, void *buf)
+{
+ struct octeon_device *oct = (struct octeon_device *)buf;
+ struct octeon_recv_pkt *recv_pkt = recv_info->recv_pkt;
+ int ifidx = 0;
+ union oct_link_status *ls;
+ int i;
+
+ if ((recv_pkt->buffer_size[0] != sizeof(*ls)) ||
+ (recv_pkt->rh.r_nic_info.ifidx > oct->ifcount)) {
+ dev_err(&oct->pci_dev->dev, "Malformed NIC_INFO, len=%d, ifidx=%d\n",
+ recv_pkt->buffer_size[0],
+ recv_pkt->rh.r_nic_info.ifidx);
+ goto nic_info_err;
+ }
+
+ ifidx = recv_pkt->rh.r_nic_info.ifidx;
+ ls = (union oct_link_status *)get_rbd(recv_pkt->buffer_ptr[0]);
+
+ octeon_swap_8B_data((u64 *)ls, (sizeof(union oct_link_status)) >> 3);
+
+ update_link_status(oct->props[ifidx].netdev, ls);
+
+nic_info_err:
+ for (i = 0; i < recv_pkt->buffer_count; i++)
+ recv_buffer_free(recv_pkt->buffer_ptr[i]);
+ octeon_free_recv_info(recv_info);
+ return 0;
+}
+
+/**
+ * \brief Setup network interfaces
+ * @param octeon_dev octeon device
+ *
+ * Called during init time for each device. It assumes the NIC
+ * is already up and running. The link information for each
+ * interface is passed in link_info.
+ */
+static int setup_nic_devices(struct octeon_device *octeon_dev)
+{
+ struct lio *lio = NULL;
+ struct net_device *netdev;
+ u8 mac[6], i, j;
+ struct octeon_soft_command *sc;
+ struct liquidio_if_cfg_context *ctx;
+ struct liquidio_if_cfg_resp *resp;
+ struct octdev_props *props;
+ int retval, num_iqueues, num_oqueues, q_no;
+ u64 q_mask;
+ int num_cpus = num_online_cpus();
+ union oct_nic_if_cfg if_cfg;
+ unsigned int base_queue;
+ unsigned int gmx_port_id;
+ u32 resp_size, ctx_size;
+
+ /* This is to handle link status changes */
+ octeon_register_dispatch_fn(octeon_dev, OPCODE_NIC,
+ OPCODE_NIC_INFO,
+ lio_nic_info, octeon_dev);
+
+ /* REQTYPE_RESP_NET and REQTYPE_SOFT_COMMAND do not have free functions.
+ * They are handled directly.
+ */
+ octeon_register_reqtype_free_fn(octeon_dev, REQTYPE_NORESP_NET,
+ free_netbuf);
+
+ octeon_register_reqtype_free_fn(octeon_dev, REQTYPE_NORESP_NET_SG,
+ free_netsgbuf);
+
+ octeon_register_reqtype_free_fn(octeon_dev, REQTYPE_RESP_NET_SG,
+ free_netsgbuf_with_resp);
+
+ for (i = 0; i < octeon_dev->ifcount; i++) {
+ resp_size = sizeof(struct liquidio_if_cfg_resp);
+ ctx_size = sizeof(struct liquidio_if_cfg_context);
+ sc = (struct octeon_soft_command *)
+ octeon_alloc_soft_command(octeon_dev, 0,
+ resp_size, ctx_size);
+ resp = (struct liquidio_if_cfg_resp *)sc->virtrptr;
+ ctx = (struct liquidio_if_cfg_context *)sc->ctxptr;
+
+ num_iqueues =
+ CFG_GET_NUM_TXQS_NIC_IF(octeon_get_conf(octeon_dev), i);
+ num_oqueues =
+ CFG_GET_NUM_RXQS_NIC_IF(octeon_get_conf(octeon_dev), i);
+ base_queue =
+ CFG_GET_BASE_QUE_NIC_IF(octeon_get_conf(octeon_dev), i);
+ gmx_port_id =
+ CFG_GET_GMXID_NIC_IF(octeon_get_conf(octeon_dev), i);
+ if (num_iqueues > num_cpus)
+ num_iqueues = num_cpus;
+ if (num_oqueues > num_cpus)
+ num_oqueues = num_cpus;
+ dev_dbg(&octeon_dev->pci_dev->dev,
+ "requesting config for interface %d, iqs %d, oqs %d\n",
+ i, num_iqueues, num_oqueues);
+ ACCESS_ONCE(ctx->cond) = 0;
+ ctx->octeon_id = lio_get_device_id(octeon_dev);
+ init_waitqueue_head(&ctx->wc);
+
+ if_cfg.u64 = 0;
+ if_cfg.s.num_iqueues = num_iqueues;
+ if_cfg.s.num_oqueues = num_oqueues;
+ if_cfg.s.base_queue = base_queue;
+ if_cfg.s.gmx_port_id = gmx_port_id;
+ octeon_prepare_soft_command(octeon_dev, sc, OPCODE_NIC,
+ OPCODE_NIC_IF_CFG, i,
+ if_cfg.u64, 0);
+
+ sc->callback = if_cfg_callback;
+ sc->callback_arg = sc;
+ sc->wait_time = 1000;
+
+ retval = octeon_send_soft_command(octeon_dev, sc);
+ if (retval) {
+ dev_err(&octeon_dev->pci_dev->dev,
+ "iq/oq config failed status: %x\n",
+ retval);
+ /* Soft instr is freed by driver in case of failure. */
+ goto setup_nic_dev_fail;
+ }
+
+ /* Sleep on a wait queue till the cond flag indicates that the
+ * response arrived or timed-out.
+ */
+ sleep_cond(&ctx->wc, &ctx->cond);
+ retval = resp->status;
+ if (retval) {
+ dev_err(&octeon_dev->pci_dev->dev, "iq/oq config failed\n");
+ goto setup_nic_dev_fail;
+ }
+
+ octeon_swap_8B_data((u64 *)(&resp->cfg_info),
+ (sizeof(struct liquidio_if_cfg_info)) >> 3);
+
+ num_iqueues = hweight64(resp->cfg_info.iqmask);
+ num_oqueues = hweight64(resp->cfg_info.oqmask);
+
+ if (!(num_iqueues) || !(num_oqueues)) {
+ dev_err(&octeon_dev->pci_dev->dev,
+ "Got bad iqueues (%016llx) or oqueues (%016llx) from firmware.\n",
+ resp->cfg_info.iqmask,
+ resp->cfg_info.oqmask);
+ goto setup_nic_dev_fail;
+ }
+ dev_dbg(&octeon_dev->pci_dev->dev,
+ "interface %d, iqmask %016llx, oqmask %016llx, numiqueues %d, numoqueues %d\n",
+ i, resp->cfg_info.iqmask, resp->cfg_info.oqmask,
+ num_iqueues, num_oqueues);
+ netdev = alloc_etherdev_mq(LIO_SIZE, num_iqueues);
+
+ if (!netdev) {
+ dev_err(&octeon_dev->pci_dev->dev, "Device allocation failed\n");
+ goto setup_nic_dev_fail;
+ }
+
+ props = &octeon_dev->props[i];
+ props->netdev = netdev;
+
+ if (num_iqueues > 1)
+ lionetdevops.ndo_select_queue = select_q;
+
+ /* Associate the routines that will handle different
+ * netdev tasks.
+ */
+ netdev->netdev_ops = &lionetdevops;
+
+ lio = GET_LIO(netdev);
+
+ memset(lio, 0, sizeof(struct lio));
+
+ lio->linfo.ifidx = resp->cfg_info.ifidx;
+ lio->ifidx = resp->cfg_info.ifidx;
+
+ lio->linfo.num_rxpciq = num_oqueues;
+ lio->linfo.num_txpciq = num_iqueues;
+ q_mask = resp->cfg_info.oqmask;
+ /* q_mask is 0-based and already verified mask is nonzero */
+ for (j = 0; j < num_oqueues; j++) {
+ q_no = __ffs64(q_mask);
+ q_mask &= (~(1UL << q_no));
+ lio->linfo.rxpciq[j] = q_no;
+ }
+ q_mask = resp->cfg_info.iqmask;
+ for (j = 0; j < num_iqueues; j++) {
+ q_no = __ffs64(q_mask);
+ q_mask &= (~(1UL << q_no));
+ lio->linfo.txpciq[j] = q_no;
+ }
+ lio->linfo.hw_addr = resp->cfg_info.linfo.hw_addr;
+ lio->linfo.gmxport = resp->cfg_info.linfo.gmxport;
+ lio->linfo.link.u64 = resp->cfg_info.linfo.link.u64;
+
+ lio->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
+
+ lio->dev_capability = NETIF_F_HIGHDMA
+ | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
+ | NETIF_F_SG | NETIF_F_RXCSUM
+ | NETIF_F_TSO | NETIF_F_TSO6
+ | NETIF_F_LRO;
+ netif_set_gso_max_size(netdev, OCTNIC_GSO_MAX_SIZE);
+
+ netdev->features = lio->dev_capability;
+ netdev->vlan_features = lio->dev_capability;
+
+ netdev->hw_features = lio->dev_capability;
+
+ /* Point to the properties for octeon device to which this
+ * interface belongs.
+ */
+ lio->oct_dev = octeon_dev;
+ lio->octprops = props;
+ lio->netdev = netdev;
+ spin_lock_init(&lio->lock);
+
+ dev_dbg(&octeon_dev->pci_dev->dev,
+ "if%d gmx: %d hw_addr: 0x%llx\n", i,
+ lio->linfo.gmxport, CVM_CAST64(lio->linfo.hw_addr));
+
+ /* 64-bit swap required on LE machines */
+ octeon_swap_8B_data(&lio->linfo.hw_addr, 1);
+ for (j = 0; j < 6; j++)
+ mac[j] = *((u8 *)(((u8 *)&lio->linfo.hw_addr) + 2 + j));
+
+ /* Copy MAC Address to OS network device structure */
+
+ ether_addr_copy(netdev->dev_addr, mac);
+
+ if (setup_io_queues(octeon_dev, netdev)) {
+ dev_err(&octeon_dev->pci_dev->dev, "I/O queues creation failed\n");
+ goto setup_nic_dev_fail;
+ }
+
+ ifstate_set(lio, LIO_IFSTATE_DROQ_OPS);
+
+ /* By default all interfaces on a single Octeon uses the same
+ * tx and rx queues
+ */
+ lio->txq = lio->linfo.txpciq[0];
+ lio->rxq = lio->linfo.rxpciq[0];
+
+ lio->tx_qsize = octeon_get_tx_qsize(octeon_dev, lio->txq);
+ lio->rx_qsize = octeon_get_rx_qsize(octeon_dev, lio->rxq);
+
+ if (setup_glist(lio)) {
+ dev_err(&octeon_dev->pci_dev->dev,
+ "Gather list allocation failed\n");
+ goto setup_nic_dev_fail;
+ }
+
+ /* Register ethtool support */
+ liquidio_set_ethtool_ops(netdev);
+
+ liquidio_set_feature(netdev, OCTNET_CMD_LRO_ENABLE);
+
+ if ((debug != -1) && (debug & NETIF_MSG_HW))
+ liquidio_set_feature(netdev, OCTNET_CMD_VERBOSE_ENABLE);
+
+ /* Register the network device with the OS */
+ if (register_netdev(netdev)) {
+ dev_err(&octeon_dev->pci_dev->dev, "Device registration failed\n");
+ goto setup_nic_dev_fail;
+ }
+
+ dev_dbg(&octeon_dev->pci_dev->dev,
+ "Setup NIC ifidx:%d mac:%02x%02x%02x%02x%02x%02x\n",
+ i, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ netif_carrier_off(netdev);
+
+ if (lio->linfo.link.s.status) {
+ netif_carrier_on(netdev);
+ start_txq(netdev);
+ } else {
+ netif_carrier_off(netdev);
+ }
+
+ ifstate_set(lio, LIO_IFSTATE_REGISTERED);
+
+ dev_dbg(&octeon_dev->pci_dev->dev,
+ "NIC ifidx:%d Setup successful\n", i);
+
+ octeon_free_soft_command(octeon_dev, sc);
+ }
+
+ return 0;
+
+setup_nic_dev_fail:
+
+ octeon_free_soft_command(octeon_dev, sc);
+
+ while (i--) {
+ dev_err(&octeon_dev->pci_dev->dev,
+ "NIC ifidx:%d Setup failed\n", i);
+ liquidio_destroy_nic_device(octeon_dev, i);
+ }
+ return -ENODEV;
+}
+
+/**
+ * \brief initialize the NIC
+ * @param oct octeon device
+ *
+ * This initialization routine is called once the Octeon device application is
+ * up and running
+ */
+static int liquidio_init_nic_module(struct octeon_device *oct)
+{
+ struct oct_intrmod_cfg *intrmod_cfg;
+ int retval = 0;
+ int num_nic_ports = CFG_GET_NUM_NIC_PORTS(octeon_get_conf(oct));
+
+ dev_dbg(&oct->pci_dev->dev, "Initializing network interfaces\n");
+
+ /* only default iq and oq were initialized
+ * initialize the rest as well
+ */
+ /* run port_config command for each port */
+ oct->ifcount = num_nic_ports;
+
+ memset(oct->props, 0,
+ sizeof(struct octdev_props) * num_nic_ports);
+
+ retval = setup_nic_devices(oct);
+ if (retval) {
+ dev_err(&oct->pci_dev->dev, "Setup NIC devices failed\n");
+ goto octnet_init_failure;
+ }
+
+ liquidio_ptp_init(oct);
+
+ /* Initialize interrupt moderation params */
+ intrmod_cfg = &((struct octeon_device *)oct)->intrmod;
+ intrmod_cfg->intrmod_enable = 1;
+ intrmod_cfg->intrmod_check_intrvl = LIO_INTRMOD_CHECK_INTERVAL;
+ intrmod_cfg->intrmod_maxpkt_ratethr = LIO_INTRMOD_MAXPKT_RATETHR;
+ intrmod_cfg->intrmod_minpkt_ratethr = LIO_INTRMOD_MINPKT_RATETHR;
+ intrmod_cfg->intrmod_maxcnt_trigger = LIO_INTRMOD_MAXCNT_TRIGGER;
+ intrmod_cfg->intrmod_maxtmr_trigger = LIO_INTRMOD_MAXTMR_TRIGGER;
+ intrmod_cfg->intrmod_mintmr_trigger = LIO_INTRMOD_MINTMR_TRIGGER;
+ intrmod_cfg->intrmod_mincnt_trigger = LIO_INTRMOD_MINCNT_TRIGGER;
+
+ dev_dbg(&oct->pci_dev->dev, "Network interfaces ready\n");
+
+ return retval;
+
+octnet_init_failure:
+
+ oct->ifcount = 0;
+
+ return retval;
+}
+
+/**
+ * \brief starter callback that invokes the remaining initialization work after
+ * the NIC is up and running.
+ * @param octptr work struct work_struct
+ */
+static void nic_starter(struct work_struct *work)
+{
+ struct octeon_device *oct;
+ struct cavium_wk *wk = (struct cavium_wk *)work;
+
+ oct = (struct octeon_device *)wk->ctxptr;
+
+ if (atomic_read(&oct->status) == OCT_DEV_RUNNING)
+ return;
+
+ /* If the status of the device is CORE_OK, the core
+ * application has reported its application type. Call
+ * any registered handlers now and move to the RUNNING
+ * state.
+ */
+ if (atomic_read(&oct->status) != OCT_DEV_CORE_OK) {
+ schedule_delayed_work(&oct->nic_poll_work.work,
+ LIQUIDIO_STARTER_POLL_INTERVAL_MS);
+ return;
+ }
+
+ atomic_set(&oct->status, OCT_DEV_RUNNING);
+
+ if (oct->app_mode && oct->app_mode == CVM_DRV_NIC_APP) {
+ dev_dbg(&oct->pci_dev->dev, "Starting NIC module\n");
+
+ if (liquidio_init_nic_module(oct))
+ dev_err(&oct->pci_dev->dev, "NIC initialization failed\n");
+ else
+ handshake[oct->octeon_id].started_ok = 1;
+ } else {
+ dev_err(&oct->pci_dev->dev,
+ "Unexpected application running on NIC (%d). Check firmware.\n",
+ oct->app_mode);
+ }
+
+ complete(&handshake[oct->octeon_id].started);
+}
+
+/**
+ * \brief Device initialization for each Octeon device that is probed
+ * @param octeon_dev octeon device
+ */
+static int octeon_device_init(struct octeon_device *octeon_dev)
+{
+ int j, ret;
+ struct octeon_device_priv *oct_priv =
+ (struct octeon_device_priv *)octeon_dev->priv;
+ atomic_set(&octeon_dev->status, OCT_DEV_BEGIN_STATE);
+
+ /* Enable access to the octeon device and make its DMA capability
+ * known to the OS.
+ */
+ if (octeon_pci_os_setup(octeon_dev))
+ return 1;
+
+ /* Identify the Octeon type and map the BAR address space. */
+ if (octeon_chip_specific_setup(octeon_dev)) {
+ dev_err(&octeon_dev->pci_dev->dev, "Chip specific setup failed\n");
+ return 1;
+ }
+
+ atomic_set(&octeon_dev->status, OCT_DEV_PCI_MAP_DONE);
+
+ octeon_dev->app_mode = CVM_DRV_INVALID_APP;
+
+ /* Do a soft reset of the Octeon device. */
+ if (octeon_dev->fn_list.soft_reset(octeon_dev))
+ return 1;
+
+ /* Initialize the dispatch mechanism used to push packets arriving on
+ * Octeon Output queues.
+ */
+ if (octeon_init_dispatch_list(octeon_dev))
+ return 1;
+
+ octeon_register_dispatch_fn(octeon_dev, OPCODE_NIC,
+ OPCODE_NIC_CORE_DRV_ACTIVE,
+ octeon_core_drv_init,
+ octeon_dev);
+
+ INIT_DELAYED_WORK(&octeon_dev->nic_poll_work.work, nic_starter);
+ octeon_dev->nic_poll_work.ctxptr = (void *)octeon_dev;
+ schedule_delayed_work(&octeon_dev->nic_poll_work.work,
+ LIQUIDIO_STARTER_POLL_INTERVAL_MS);
+
+ atomic_set(&octeon_dev->status, OCT_DEV_DISPATCH_INIT_DONE);
+
+ octeon_set_io_queues_off(octeon_dev);
+
+ /* Setup the data structures that manage this Octeon's Input queues. */
+ if (octeon_setup_instr_queues(octeon_dev)) {
+ dev_err(&octeon_dev->pci_dev->dev,
+ "instruction queue initialization failed\n");
+ /* On error, release any previously allocated queues */
+ for (j = 0; j < octeon_dev->num_iqs; j++)
+ octeon_delete_instr_queue(octeon_dev, j);
+ return 1;
+ }
+ atomic_set(&octeon_dev->status, OCT_DEV_INSTR_QUEUE_INIT_DONE);
+
+ /* Initialize soft command buffer pool
+ */
+ if (octeon_setup_sc_buffer_pool(octeon_dev)) {
+ dev_err(&octeon_dev->pci_dev->dev, "sc buffer pool allocation failed\n");
+ return 1;
+ }
+ atomic_set(&octeon_dev->status, OCT_DEV_SC_BUFF_POOL_INIT_DONE);
+
+ /* Initialize lists to manage the requests of different types that
+ * arrive from user & kernel applications for this octeon device.
+ */
+ if (octeon_setup_response_list(octeon_dev)) {
+ dev_err(&octeon_dev->pci_dev->dev, "Response list allocation failed\n");
+ return 1;
+ }
+ atomic_set(&octeon_dev->status, OCT_DEV_RESP_LIST_INIT_DONE);
+
+ if (octeon_setup_output_queues(octeon_dev)) {
+ dev_err(&octeon_dev->pci_dev->dev, "Output queue initialization failed\n");
+ /* Release any previously allocated queues */
+ for (j = 0; j < octeon_dev->num_oqs; j++)
+ octeon_delete_droq(octeon_dev, j);
+ }
+
+ atomic_set(&octeon_dev->status, OCT_DEV_DROQ_INIT_DONE);
+
+ /* The input and output queue registers were setup earlier (the queues
+ * were not enabled). Any additional registers that need to be
+ * programmed should be done now.
+ */
+ ret = octeon_dev->fn_list.setup_device_regs(octeon_dev);
+ if (ret) {
+ dev_err(&octeon_dev->pci_dev->dev,
+ "Failed to configure device registers\n");
+ return ret;
+ }
+
+ /* Initialize the tasklet that handles output queue packet processing.*/
+ dev_dbg(&octeon_dev->pci_dev->dev, "Initializing droq tasklet\n");
+ tasklet_init(&oct_priv->droq_tasklet, octeon_droq_bh,
+ (unsigned long)octeon_dev);
+
+ /* Setup the interrupt handler and record the INT SUM register address
+ */
+ octeon_setup_interrupt(octeon_dev);
+
+ /* Enable Octeon device interrupts */
+ octeon_dev->fn_list.enable_interrupt(octeon_dev->chip);
+
+ /* Enable the input and output queues for this Octeon device */
+ octeon_dev->fn_list.enable_io_queues(octeon_dev);
+
+ atomic_set(&octeon_dev->status, OCT_DEV_IO_QUEUES_DONE);
+
+ dev_dbg(&octeon_dev->pci_dev->dev, "Waiting for DDR initialization...\n");
+
+ if (ddr_timeout == 0) {
+ dev_info(&octeon_dev->pci_dev->dev,
+ "WAITING. Set ddr_timeout to non-zero value to proceed with initialization.\n");
+ }
+
+ schedule_timeout_uninterruptible(HZ * LIO_RESET_SECS);
+
+ /* Wait for the octeon to initialize DDR after the soft-reset. */
+ ret = octeon_wait_for_ddr_init(octeon_dev, &ddr_timeout);
+ if (ret) {
+ dev_err(&octeon_dev->pci_dev->dev,
+ "DDR not initialized. Please confirm that board is configured to boot from Flash, ret: %d\n",
+ ret);
+ return 1;
+ }
+
+ if (octeon_wait_for_bootloader(octeon_dev, 1000) != 0) {
+ dev_err(&octeon_dev->pci_dev->dev, "Board not responding\n");
+ return 1;
+ }
+
+ dev_dbg(&octeon_dev->pci_dev->dev, "Initializing consoles\n");
+ ret = octeon_init_consoles(octeon_dev);
+ if (ret) {
+ dev_err(&octeon_dev->pci_dev->dev, "Could not access board consoles\n");
+ return 1;
+ }
+ ret = octeon_add_console(octeon_dev, 0);
+ if (ret) {
+ dev_err(&octeon_dev->pci_dev->dev, "Could not access board console\n");
+ return 1;
+ }
+
+ atomic_set(&octeon_dev->status, OCT_DEV_CONSOLE_INIT_DONE);
+
+ dev_dbg(&octeon_dev->pci_dev->dev, "Loading firmware\n");
+ ret = load_firmware(octeon_dev);
+ if (ret) {
+ dev_err(&octeon_dev->pci_dev->dev, "Could not load firmware to board\n");
+ return 1;
+ }
+
+ handshake[octeon_dev->octeon_id].init_ok = 1;
+ complete(&handshake[octeon_dev->octeon_id].init);
+
+ atomic_set(&octeon_dev->status, OCT_DEV_HOST_OK);
+
+ /* Send Credit for Octeon Output queues. Credits are always sent after
+ * the output queue is enabled.
+ */
+ for (j = 0; j < octeon_dev->num_oqs; j++)
+ writel(octeon_dev->droq[j]->max_count,
+ octeon_dev->droq[j]->pkts_credit_reg);
+
+ /* Packets can start arriving on the output queues from this point. */
+
+ return 0;
+}
+
+/**
+ * \brief Exits the module
+ */
+static void __exit liquidio_exit(void)
+{
+ liquidio_deinit_pci();
+
+ pr_info("LiquidIO network module is now unloaded\n");
+}
+
+module_init(liquidio_init);
+module_exit(liquidio_exit);
diff --git a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h
new file mode 100644
index 000000000000..0ac347ccc8ba
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h
@@ -0,0 +1,673 @@
+/**********************************************************************
+* Author: Cavium, Inc.
+*
+* Contact: support@cavium.com
+* Please include "LiquidIO" in the subject.
+*
+* Copyright (c) 2003-2015 Cavium, Inc.
+*
+* This file 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 file is distributed in the hope that it will be useful, but
+* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+* NONINFRINGEMENT. See the GNU General Public License for more
+* details.
+*
+* This file may also be available under a different license from Cavium.
+* Contact Cavium, Inc. for more information
+**********************************************************************/
+
+/*! \file liquidio_common.h
+ * \brief Common: Structures and macros used in PCI-NIC package by core and
+ * host driver.
+ */
+
+#ifndef __LIQUIDIO_COMMON_H__
+#define __LIQUIDIO_COMMON_H__
+
+#include "octeon_config.h"
+
+#define LIQUIDIO_VERSION "1.1.9"
+#define LIQUIDIO_MAJOR_VERSION 1
+#define LIQUIDIO_MINOR_VERSION 1
+#define LIQUIDIO_MICRO_VERSION 9
+
+#define CONTROL_IQ 0
+/** Tag types used by Octeon cores in its work. */
+enum octeon_tag_type {
+ ORDERED_TAG = 0,
+ ATOMIC_TAG = 1,
+ NULL_TAG = 2,
+ NULL_NULL_TAG = 3
+};
+
+/* pre-defined host->NIC tag values */
+#define LIO_CONTROL (0x11111110)
+#define LIO_DATA(i) (0x11111111 + (i))
+
+/* Opcodes used by host driver/apps to perform operations on the core.
+ * These are used to identify the major subsystem that the operation
+ * is for.
+ */
+#define OPCODE_CORE 0 /* used for generic core operations */
+#define OPCODE_NIC 1 /* used for NIC operations */
+#define OPCODE_LAST OPCODE_NIC
+
+/* Subcodes are used by host driver/apps to identify the sub-operation
+ * for the core. They only need to by unique for a given subsystem.
+ */
+#define OPCODE_SUBCODE(op, sub) (((op & 0x0f) << 8) | ((sub) & 0x7f))
+
+/** OPCODE_CORE subcodes. For future use. */
+
+/** OPCODE_NIC subcodes */
+
+/* This subcode is sent by core PCI driver to indicate cores are ready. */
+#define OPCODE_NIC_CORE_DRV_ACTIVE 0x01
+#define OPCODE_NIC_NW_DATA 0x02 /* network packet data */
+#define OPCODE_NIC_CMD 0x03
+#define OPCODE_NIC_INFO 0x04
+#define OPCODE_NIC_PORT_STATS 0x05
+#define OPCODE_NIC_MDIO45 0x06
+#define OPCODE_NIC_TIMESTAMP 0x07
+#define OPCODE_NIC_INTRMOD_CFG 0x08
+#define OPCODE_NIC_IF_CFG 0x09
+
+#define CORE_DRV_TEST_SCATTER_OP 0xFFF5
+
+#define OPCODE_SLOW_PATH(rh) \
+ (OPCODE_SUBCODE(rh->r.opcode, rh->r.subcode) != \
+ OPCODE_SUBCODE(OPCODE_NIC, OPCODE_NIC_NW_DATA))
+
+/* Application codes advertised by the core driver initialization packet. */
+#define CVM_DRV_APP_START 0x0
+#define CVM_DRV_NO_APP 0
+#define CVM_DRV_APP_COUNT 0x2
+#define CVM_DRV_BASE_APP (CVM_DRV_APP_START + 0x0)
+#define CVM_DRV_NIC_APP (CVM_DRV_APP_START + 0x1)
+#define CVM_DRV_INVALID_APP (CVM_DRV_APP_START + 0x2)
+#define CVM_DRV_APP_END (CVM_DRV_INVALID_APP - 1)
+
+/* Macro to increment index.
+ * Index is incremented by count; if the sum exceeds
+ * max, index is wrapped-around to the start.
+ */
+#define INCR_INDEX(index, count, max) \
+do { \
+ if (((index) + (count)) >= (max)) \
+ index = ((index) + (count)) - (max); \
+ else \
+ index += (count); \
+} while (0)
+
+#define INCR_INDEX_BY1(index, max) \
+do { \
+ if ((++(index)) == (max)) \
+ index = 0; \
+} while (0)
+
+#define DECR_INDEX(index, count, max) \
+do { \
+ if ((count) > (index)) \
+ index = ((max) - ((count - index))); \
+ else \
+ index -= count; \
+} while (0)
+
+#define OCT_BOARD_NAME 32
+#define OCT_SERIAL_LEN 64
+
+/* Structure used by core driver to send indication that the Octeon
+ * application is ready.
+ */
+struct octeon_core_setup {
+ u64 corefreq;
+
+ char boardname[OCT_BOARD_NAME];
+
+ char board_serial_number[OCT_SERIAL_LEN];
+
+ u64 board_rev_major;
+
+ u64 board_rev_minor;
+
+};
+
+/*--------------------------- SCATTER GATHER ENTRY -----------------------*/
+
+/* The Scatter-Gather List Entry. The scatter or gather component used with
+ * a Octeon input instruction has this format.
+ */
+struct octeon_sg_entry {
+ /** The first 64 bit gives the size of data in each dptr.*/
+ union {
+ u16 size[4];
+ u64 size64;
+ } u;
+
+ /** The 4 dptr pointers for this entry. */
+ u64 ptr[4];
+
+};
+
+#define OCT_SG_ENTRY_SIZE (sizeof(struct octeon_sg_entry))
+
+/* \brief Add size to gather list
+ * @param sg_entry scatter/gather entry
+ * @param size size to add
+ * @param pos position to add it.
+ */
+static inline void add_sg_size(struct octeon_sg_entry *sg_entry,
+ u16 size,
+ u32 pos)
+{
+#ifdef __BIG_ENDIAN_BITFIELD
+ sg_entry->u.size[pos] = size;
+#else
+ sg_entry->u.size[3 - pos] = size;
+#endif
+}
+
+/*------------------------- End Scatter/Gather ---------------------------*/
+
+#define OCTNET_FRM_PTP_HEADER_SIZE 8
+#define OCTNET_FRM_HEADER_SIZE 30 /* PTP timestamp + VLAN + Ethernet */
+
+#define OCTNET_MIN_FRM_SIZE (64 + OCTNET_FRM_PTP_HEADER_SIZE)
+#define OCTNET_MAX_FRM_SIZE (16000 + OCTNET_FRM_HEADER_SIZE)
+
+#define OCTNET_DEFAULT_FRM_SIZE (1500 + OCTNET_FRM_HEADER_SIZE)
+
+/** NIC Commands are sent using this Octeon Input Queue */
+#define OCTNET_CMD_Q 0
+
+/* NIC Command types */
+#define OCTNET_CMD_CHANGE_MTU 0x1
+#define OCTNET_CMD_CHANGE_MACADDR 0x2
+#define OCTNET_CMD_CHANGE_DEVFLAGS 0x3
+#define OCTNET_CMD_RX_CTL 0x4
+
+#define OCTNET_CMD_SET_MULTI_LIST 0x5
+#define OCTNET_CMD_CLEAR_STATS 0x6
+
+/* command for setting the speed, duplex & autoneg */
+#define OCTNET_CMD_SET_SETTINGS 0x7
+#define OCTNET_CMD_SET_FLOW_CTL 0x8
+
+#define OCTNET_CMD_MDIO_READ_WRITE 0x9
+#define OCTNET_CMD_GPIO_ACCESS 0xA
+#define OCTNET_CMD_LRO_ENABLE 0xB
+#define OCTNET_CMD_LRO_DISABLE 0xC
+#define OCTNET_CMD_SET_RSS 0xD
+#define OCTNET_CMD_WRITE_SA 0xE
+#define OCTNET_CMD_DELETE_SA 0xF
+#define OCTNET_CMD_UPDATE_SA 0x12
+
+#define OCTNET_CMD_TNL_RX_CSUM_CTL 0x10
+#define OCTNET_CMD_TNL_TX_CSUM_CTL 0x11
+#define OCTNET_CMD_IPSECV2_AH_ESP_CTL 0x13
+#define OCTNET_CMD_VERBOSE_ENABLE 0x14
+#define OCTNET_CMD_VERBOSE_DISABLE 0x15
+
+/* RX(packets coming from wire) Checksum verification flags */
+/* TCP/UDP csum */
+#define CNNIC_L4SUM_VERIFIED 0x1
+#define CNNIC_IPSUM_VERIFIED 0x2
+#define CNNIC_TUN_CSUM_VERIFIED 0x4
+#define CNNIC_CSUM_VERIFIED (CNNIC_IPSUM_VERIFIED | CNNIC_L4SUM_VERIFIED)
+
+/*LROIPV4 and LROIPV6 Flags*/
+#define OCTNIC_LROIPV4 0x1
+#define OCTNIC_LROIPV6 0x2
+
+/* Interface flags communicated between host driver and core app. */
+enum octnet_ifflags {
+ OCTNET_IFFLAG_PROMISC = 0x01,
+ OCTNET_IFFLAG_ALLMULTI = 0x02,
+ OCTNET_IFFLAG_MULTICAST = 0x04,
+ OCTNET_IFFLAG_BROADCAST = 0x08,
+ OCTNET_IFFLAG_UNICAST = 0x10
+};
+
+/* wqe
+ * --------------- 0
+ * | wqe word0-3 |
+ * --------------- 32
+ * | PCI IH |
+ * --------------- 40
+ * | RPTR |
+ * --------------- 48
+ * | PCI IRH |
+ * --------------- 56
+ * | OCT_NET_CMD |
+ * --------------- 64
+ * | Addtl 8-BData |
+ * | |
+ * ---------------
+ */
+
+union octnet_cmd {
+ u64 u64;
+
+ struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u64 cmd:5;
+
+ u64 more:6; /* How many udd words follow the command */
+
+ u64 param1:29;
+
+ u64 param2:16;
+
+ u64 param3:8;
+
+#else
+
+ u64 param3:8;
+
+ u64 param2:16;
+
+ u64 param1:29;
+
+ u64 more:6;
+
+ u64 cmd:5;
+
+#endif
+ } s;
+
+};
+
+#define OCTNET_CMD_SIZE (sizeof(union octnet_cmd))
+
+/** Instruction Header */
+struct octeon_instr_ih {
+#ifdef __BIG_ENDIAN_BITFIELD
+ /** Raw mode indicator 1 = RAW */
+ u64 raw:1;
+
+ /** Gather indicator 1=gather*/
+ u64 gather:1;
+
+ /** Data length OR no. of entries in gather list */
+ u64 dlengsz:14;
+
+ /** Front Data size */
+ u64 fsz:6;
+
+ /** Packet Order / Work Unit selection (1 of 8)*/
+ u64 qos:3;
+
+ /** Core group selection (1 of 16) */
+ u64 grp:4;
+
+ /** Short Raw Packet Indicator 1=short raw pkt */
+ u64 rs:1;
+
+ /** Tag type */
+ u64 tagtype:2;
+
+ /** Tag Value */
+ u64 tag:32;
+#else
+ /** Tag Value */
+ u64 tag:32;
+
+ /** Tag type */
+ u64 tagtype:2;
+
+ /** Short Raw Packet Indicator 1=short raw pkt */
+ u64 rs:1;
+
+ /** Core group selection (1 of 16) */
+ u64 grp:4;
+
+ /** Packet Order / Work Unit selection (1 of 8)*/
+ u64 qos:3;
+
+ /** Front Data size */
+ u64 fsz:6;
+
+ /** Data length OR no. of entries in gather list */
+ u64 dlengsz:14;
+
+ /** Gather indicator 1=gather*/
+ u64 gather:1;
+
+ /** Raw mode indicator 1 = RAW */
+ u64 raw:1;
+#endif
+};
+
+/** Input Request Header */
+struct octeon_instr_irh {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u64 opcode:4;
+ u64 rflag:1;
+ u64 subcode:7;
+ u64 len:3;
+ u64 rid:13;
+ u64 reserved:4;
+ u64 ossp:32; /* opcode/subcode specific parameters */
+#else
+ u64 ossp:32; /* opcode/subcode specific parameters */
+ u64 reserved:4;
+ u64 rid:13;
+ u64 len:3;
+ u64 subcode:7;
+ u64 rflag:1;
+ u64 opcode:4;
+#endif
+};
+
+/** Return Data Parameters */
+struct octeon_instr_rdp {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u64 reserved:49;
+ u64 pcie_port:3;
+ u64 rlen:12;
+#else
+ u64 rlen:12;
+ u64 pcie_port:3;
+ u64 reserved:49;
+#endif
+};
+
+/** Receive Header */
+union octeon_rh {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u64 u64;
+ struct {
+ u64 opcode:4;
+ u64 subcode:8;
+ u64 len:3; /** additional 64-bit words */
+ u64 rid:13; /** request id in response to pkt sent by host */
+ u64 reserved:4;
+ u64 ossp:32; /** opcode/subcode specific parameters */
+ } r;
+ struct {
+ u64 opcode:4;
+ u64 subcode:8;
+ u64 len:3; /** additional 64-bit words */
+ u64 rid:13; /** request id in response to pkt sent by host */
+ u64 extra:24;
+ u64 link:8;
+ u64 csum_verified:3; /** checksum verified. */
+ u64 has_hwtstamp:1; /** Has hardware timestamp. 1 = yes. */
+ } r_dh;
+ struct {
+ u64 opcode:4;
+ u64 subcode:8;
+ u64 len:3; /** additional 64-bit words */
+ u64 rid:13; /** request id in response to pkt sent by host */
+ u64 num_gmx_ports:8;
+ u64 max_nic_ports:8;
+ u64 app_cap_flags:4;
+ u64 app_mode:16;
+ } r_core_drv_init;
+ struct {
+ u64 opcode:4;
+ u64 subcode:8;
+ u64 len:3; /** additional 64-bit words */
+ u64 rid:13;
+ u64 reserved:4;
+ u64 extra:25;
+ u64 ifidx:7;
+ } r_nic_info;
+#else
+ u64 u64;
+ struct {
+ u64 ossp:32; /** opcode/subcode specific parameters */
+ u64 reserved:4;
+ u64 rid:13; /** req id in response to pkt sent by host */
+ u64 len:3; /** additional 64-bit words */
+ u64 subcode:8;
+ u64 opcode:4;
+ } r;
+ struct {
+ u64 has_hwtstamp:1; /** 1 = has hwtstamp */
+ u64 csum_verified:3; /** checksum verified. */
+ u64 link:8;
+ u64 extra:24;
+ u64 rid:13; /** req id in response to pkt sent by host */
+ u64 len:3; /** additional 64-bit words */
+ u64 subcode:8;
+ u64 opcode:4;
+ } r_dh;
+ struct {
+ u64 app_mode:16;
+ u64 app_cap_flags:4;
+ u64 max_nic_ports:8;
+ u64 num_gmx_ports:8;
+ u64 rid:13;
+ u64 len:3; /** additional 64-bit words */
+ u64 subcode:8;
+ u64 opcode:4;
+ } r_core_drv_init;
+ struct {
+ u64 ifidx:7;
+ u64 extra:25;
+ u64 reserved:4;
+ u64 rid:13;
+ u64 len:3; /** additional 64-bit words */
+ u64 subcode:8;
+ u64 opcode:4;
+ } r_nic_info;
+#endif
+};
+
+#define OCT_RH_SIZE (sizeof(union octeon_rh))
+
+#define OCT_PKT_PARAM_IPV4OPTS 1
+#define OCT_PKT_PARAM_IPV6EXTHDR 2
+
+union octnic_packet_params {
+ u32 u32;
+ struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u32 reserved:6;
+ u32 tnl_csum:1;
+ u32 ip_csum:1;
+ u32 ipv4opts_ipv6exthdr:2;
+ u32 ipsec_ops:4;
+ u32 tsflag:1;
+ u32 csoffset:9;
+ u32 ifidx:8;
+#else
+ u32 ifidx:8;
+ u32 csoffset:9;
+ u32 tsflag:1;
+ u32 ipsec_ops:4;
+ u32 ipv4opts_ipv6exthdr:2;
+ u32 ip_csum:1;
+ u32 tnl_csum:1;
+ u32 reserved:6;
+#endif
+ } s;
+};
+
+/** Status of a RGMII Link on Octeon as seen by core driver. */
+union oct_link_status {
+ u64 u64;
+
+ struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u64 duplex:8;
+ u64 status:8;
+ u64 mtu:16;
+ u64 speed:16;
+ u64 autoneg:1;
+ u64 interface:4;
+ u64 pause:1;
+ u64 reserved:10;
+#else
+ u64 reserved:10;
+ u64 pause:1;
+ u64 interface:4;
+ u64 autoneg:1;
+ u64 speed:16;
+ u64 mtu:16;
+ u64 status:8;
+ u64 duplex:8;
+#endif
+ } s;
+};
+
+/** Information for a OCTEON ethernet interface shared between core & host. */
+struct oct_link_info {
+ union oct_link_status link;
+ u64 hw_addr;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+ u16 gmxport;
+ u8 rsvd[3];
+ u8 num_txpciq;
+ u8 num_rxpciq;
+ u8 ifidx;
+#else
+ u8 ifidx;
+ u8 num_rxpciq;
+ u8 num_txpciq;
+ u8 rsvd[3];
+ u16 gmxport;
+#endif
+
+ u8 txpciq[MAX_IOQS_PER_NICIF];
+ u8 rxpciq[MAX_IOQS_PER_NICIF];
+};
+
+#define OCT_LINK_INFO_SIZE (sizeof(struct oct_link_info))
+
+struct liquidio_if_cfg_info {
+ u64 ifidx;
+ u64 iqmask; /** mask for IQs enabled for the port */
+ u64 oqmask; /** mask for OQs enabled for the port */
+ struct oct_link_info linfo; /** initial link information */
+};
+
+/** Stats for each NIC port in RX direction. */
+struct nic_rx_stats {
+ /* link-level stats */
+ u64 total_rcvd;
+ u64 bytes_rcvd;
+ u64 total_bcst;
+ u64 total_mcst;
+ u64 runts;
+ u64 ctl_rcvd;
+ u64 fifo_err; /* Accounts for over/under-run of buffers */
+ u64 dmac_drop;
+ u64 fcs_err;
+ u64 jabber_err;
+ u64 l2_err;
+ u64 frame_err;
+
+ /* firmware stats */
+ u64 fw_total_rcvd;
+ u64 fw_total_fwd;
+ u64 fw_err_pko;
+ u64 fw_err_link;
+ u64 fw_err_drop;
+ u64 fw_lro_pkts; /* Number of packets that are LROed */
+ u64 fw_lro_octs; /* Number of octets that are LROed */
+ u64 fw_total_lro; /* Number of LRO packets formed */
+ u64 fw_lro_aborts; /* Number of times lRO of packet aborted */
+ /* intrmod: packet forward rate */
+ u64 fwd_rate;
+};
+
+/** Stats for each NIC port in RX direction. */
+struct nic_tx_stats {
+ /* link-level stats */
+ u64 total_pkts_sent;
+ u64 total_bytes_sent;
+ u64 mcast_pkts_sent;
+ u64 bcast_pkts_sent;
+ u64 ctl_sent;
+ u64 one_collision_sent; /* Packets sent after one collision*/
+ u64 multi_collision_sent; /* Packets sent after multiple collision*/
+ u64 max_collision_fail; /* Packets not sent due to max collisions */
+ u64 max_deferral_fail; /* Packets not sent due to max deferrals */
+ u64 fifo_err; /* Accounts for over/under-run of buffers */
+ u64 runts;
+ u64 total_collisions; /* Total number of collisions detected */
+
+ /* firmware stats */
+ u64 fw_total_sent;
+ u64 fw_total_fwd;
+ u64 fw_err_pko;
+ u64 fw_err_link;
+ u64 fw_err_drop;
+};
+
+struct oct_link_stats {
+ struct nic_rx_stats fromwire;
+ struct nic_tx_stats fromhost;
+
+};
+
+#define LIO68XX_LED_CTRL_ADDR 0x3501
+#define LIO68XX_LED_CTRL_CFGON 0x1f
+#define LIO68XX_LED_CTRL_CFGOFF 0x100
+#define LIO68XX_LED_BEACON_ADDR 0x3508
+#define LIO68XX_LED_BEACON_CFGON 0x47fd
+#define LIO68XX_LED_BEACON_CFGOFF 0x11fc
+#define VITESSE_PHY_GPIO_DRIVEON 0x1
+#define VITESSE_PHY_GPIO_CFG 0x8
+#define VITESSE_PHY_GPIO_DRIVEOFF 0x4
+#define VITESSE_PHY_GPIO_HIGH 0x2
+#define VITESSE_PHY_GPIO_LOW 0x3
+
+struct oct_mdio_cmd {
+ u64 op;
+ u64 mdio_addr;
+ u64 value1;
+ u64 value2;
+ u64 value3;
+};
+
+#define OCT_LINK_STATS_SIZE (sizeof(struct oct_link_stats))
+
+#define LIO_INTRMOD_CHECK_INTERVAL 1
+#define LIO_INTRMOD_MAXPKT_RATETHR 196608 /* max pkt rate threshold */
+#define LIO_INTRMOD_MINPKT_RATETHR 9216 /* min pkt rate threshold */
+#define LIO_INTRMOD_MAXCNT_TRIGGER 384 /* max pkts to trigger interrupt */
+#define LIO_INTRMOD_MINCNT_TRIGGER 1 /* min pkts to trigger interrupt */
+#define LIO_INTRMOD_MAXTMR_TRIGGER 128 /* max time to trigger interrupt */
+#define LIO_INTRMOD_MINTMR_TRIGGER 32 /* min time to trigger interrupt */
+
+struct oct_intrmod_cfg {
+ u64 intrmod_enable;
+ u64 intrmod_check_intrvl;
+ u64 intrmod_maxpkt_ratethr;
+ u64 intrmod_minpkt_ratethr;
+ u64 intrmod_maxcnt_trigger;
+ u64 intrmod_maxtmr_trigger;
+ u64 intrmod_mincnt_trigger;
+ u64 intrmod_mintmr_trigger;
+};
+
+#define BASE_QUEUE_NOT_REQUESTED 65535
+
+union oct_nic_if_cfg {
+ u64 u64;
+ struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u64 base_queue:16;
+ u64 num_iqueues:16;
+ u64 num_oqueues:16;
+ u64 gmx_port_id:8;
+ u64 reserved:8;
+#else
+ u64 reserved:8;
+ u64 gmx_port_id:8;
+ u64 num_oqueues:16;
+ u64 num_iqueues:16;
+ u64 base_queue:16;
+#endif
+ } s;
+};
+
+#endif
diff --git a/drivers/net/ethernet/cavium/liquidio/liquidio_image.h b/drivers/net/ethernet/cavium/liquidio/liquidio_image.h
new file mode 100644
index 000000000000..93819bd8602b
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/liquidio_image.h
@@ -0,0 +1,57 @@
+/**********************************************************************
+* Author: Cavium, Inc.
+*
+* Contact: support@cavium.com
+* Please include "LiquidIO" in the subject.
+*
+* Copyright (c) 2003-2015 Cavium, Inc.
+*
+* This file 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 file is distributed in the hope that it will be useful, but
+* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+* NONINFRINGEMENT. See the GNU General Public License for more
+* details.
+*
+* This file may also be available under a different license from Cavium.
+* Contact Cavium, Inc. for more information
+**********************************************************************/
+#ifndef _LIQUIDIO_IMAGE_H_
+#define _LIQUIDIO_IMAGE_H_
+
+#define LIO_MAX_FW_TYPE_LEN (8)
+#define LIO_MAX_FW_FILENAME_LEN (256)
+#define LIO_FW_DIR "liquidio/"
+#define LIO_FW_BASE_NAME "lio_"
+#define LIO_FW_NAME_SUFFIX ".bin"
+#define LIO_FW_NAME_TYPE_NIC "nic"
+#define LIO_FW_NAME_TYPE_NONE "none"
+#define LIO_MAX_FIRMWARE_VERSION_LEN 16
+
+#define LIO_MAX_BOOTCMD_LEN 1024
+#define LIO_MAX_IMAGES 16
+#define LIO_NIC_MAGIC 0x434E4943 /* "CNIC" */
+struct octeon_firmware_desc {
+ __be64 addr;
+ __be32 len;
+ __be32 crc32; /* crc32 of image */
+};
+
+/* Following the header is a list of 64-bit aligned binary images,
+ * as described by the desc field.
+ * Numeric fields are in network byte order.
+ */
+struct octeon_firmware_file_header {
+ __be32 magic;
+ char version[LIO_MAX_FIRMWARE_VERSION_LEN];
+ char bootcmd[LIO_MAX_BOOTCMD_LEN];
+ __be32 num_images;
+ struct octeon_firmware_desc desc[LIO_MAX_IMAGES];
+ __be32 pad;
+ __be32 crc32; /* header checksum */
+};
+
+#endif /* _LIQUIDIO_IMAGE_H_ */
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_config.h b/drivers/net/ethernet/cavium/liquidio/octeon_config.h
new file mode 100644
index 000000000000..62a8dd5cd3dc
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_config.h
@@ -0,0 +1,424 @@
+/**********************************************************************
+* Author: Cavium, Inc.
+*
+* Contact: support@cavium.com
+* Please include "LiquidIO" in the subject.
+*
+* Copyright (c) 2003-2015 Cavium, Inc.
+*
+* This file 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 file is distributed in the hope that it will be useful, but
+* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+* NONINFRINGEMENT. See the GNU General Public License for more
+* details.
+*
+* This file may also be available under a different license from Cavium.
+* Contact Cavium, Inc. for more information
+**********************************************************************/
+
+/*! \file octeon_config.h
+ * \brief Host Driver: Configuration data structures for the host driver.
+ */
+
+#ifndef __OCTEON_CONFIG_H__
+#define __OCTEON_CONFIG_H__
+
+/*--------------------------CONFIG VALUES------------------------*/
+
+/* The following macros affect the way the driver data structures
+ * are generated for Octeon devices.
+ * They can be modified.
+ */
+
+/* Maximum octeon devices defined as MAX_OCTEON_NICIF to support
+ * multiple(<= MAX_OCTEON_NICIF) Miniports
+ */
+#define MAX_OCTEON_NICIF 32
+#define MAX_OCTEON_DEVICES MAX_OCTEON_NICIF
+#define MAX_OCTEON_LINKS MAX_OCTEON_NICIF
+#define MAX_OCTEON_MULTICAST_ADDR 32
+
+/* CN6xxx IQ configuration macros */
+#define CN6XXX_MAX_INPUT_QUEUES 32
+#define CN6XXX_MAX_IQ_DESCRIPTORS 2048
+#define CN6XXX_DB_MIN 1
+#define CN6XXX_DB_MAX 8
+#define CN6XXX_DB_TIMEOUT 1
+
+/* CN6xxx OQ configuration macros */
+#define CN6XXX_MAX_OUTPUT_QUEUES 32
+#define CN6XXX_MAX_OQ_DESCRIPTORS 2048
+#define CN6XXX_OQ_BUF_SIZE 1536
+#define CN6XXX_OQ_PKTSPER_INTR ((CN6XXX_MAX_OQ_DESCRIPTORS < 512) ? \
+ (CN6XXX_MAX_OQ_DESCRIPTORS / 4) : 128)
+#define CN6XXX_OQ_REFIL_THRESHOLD ((CN6XXX_MAX_OQ_DESCRIPTORS < 512) ? \
+ (CN6XXX_MAX_OQ_DESCRIPTORS / 4) : 128)
+
+#define CN6XXX_OQ_INTR_PKT 64
+#define CN6XXX_OQ_INTR_TIME 100
+#define DEFAULT_NUM_NIC_PORTS_66XX 2
+#define DEFAULT_NUM_NIC_PORTS_68XX 4
+#define DEFAULT_NUM_NIC_PORTS_68XX_210NV 2
+
+/* common OCTEON configuration macros */
+#define CN6XXX_CFG_IO_QUEUES 32
+#define OCTEON_32BYTE_INSTR 32
+#define OCTEON_64BYTE_INSTR 64
+#define OCTEON_MAX_BASE_IOQ 4
+#define OCTEON_OQ_BUFPTR_MODE 0
+#define OCTEON_OQ_INFOPTR_MODE 1
+
+#define OCTEON_DMA_INTR_PKT 64
+#define OCTEON_DMA_INTR_TIME 1000
+
+#define MAX_TXQS_PER_INTF 8
+#define MAX_RXQS_PER_INTF 8
+#define DEF_TXQS_PER_INTF 4
+#define DEF_RXQS_PER_INTF 4
+
+#define INVALID_IOQ_NO 0xff
+
+#define DEFAULT_POW_GRP 0
+
+/* Macros to get octeon config params */
+#define CFG_GET_IQ_CFG(cfg) ((cfg)->iq)
+#define CFG_GET_IQ_MAX_Q(cfg) ((cfg)->iq.max_iqs)
+#define CFG_GET_IQ_PENDING_LIST_SIZE(cfg) ((cfg)->iq.pending_list_size)
+#define CFG_GET_IQ_INSTR_TYPE(cfg) ((cfg)->iq.instr_type)
+#define CFG_GET_IQ_DB_MIN(cfg) ((cfg)->iq.db_min)
+#define CFG_GET_IQ_DB_TIMEOUT(cfg) ((cfg)->iq.db_timeout)
+
+#define CFG_GET_OQ_MAX_Q(cfg) ((cfg)->oq.max_oqs)
+#define CFG_GET_OQ_INFO_PTR(cfg) ((cfg)->oq.info_ptr)
+#define CFG_GET_OQ_PKTS_PER_INTR(cfg) ((cfg)->oq.pkts_per_intr)
+#define CFG_GET_OQ_REFILL_THRESHOLD(cfg) ((cfg)->oq.refill_threshold)
+#define CFG_GET_OQ_INTR_PKT(cfg) ((cfg)->oq.oq_intr_pkt)
+#define CFG_GET_OQ_INTR_TIME(cfg) ((cfg)->oq.oq_intr_time)
+#define CFG_SET_OQ_INTR_PKT(cfg, val) (cfg)->oq.oq_intr_pkt = val
+#define CFG_SET_OQ_INTR_TIME(cfg, val) (cfg)->oq.oq_intr_time = val
+
+#define CFG_GET_DMA_INTR_PKT(cfg) ((cfg)->dma.dma_intr_pkt)
+#define CFG_GET_DMA_INTR_TIME(cfg) ((cfg)->dma.dma_intr_time)
+#define CFG_GET_NUM_NIC_PORTS(cfg) ((cfg)->num_nic_ports)
+#define CFG_GET_NUM_DEF_TX_DESCS(cfg) ((cfg)->num_def_tx_descs)
+#define CFG_GET_NUM_DEF_RX_DESCS(cfg) ((cfg)->num_def_rx_descs)
+#define CFG_GET_DEF_RX_BUF_SIZE(cfg) ((cfg)->def_rx_buf_size)
+
+#define CFG_GET_MAX_TXQS_NIC_IF(cfg, idx) \
+ ((cfg)->nic_if_cfg[idx].max_txqs)
+#define CFG_GET_NUM_TXQS_NIC_IF(cfg, idx) \
+ ((cfg)->nic_if_cfg[idx].num_txqs)
+#define CFG_GET_MAX_RXQS_NIC_IF(cfg, idx) \
+ ((cfg)->nic_if_cfg[idx].max_rxqs)
+#define CFG_GET_NUM_RXQS_NIC_IF(cfg, idx) \
+ ((cfg)->nic_if_cfg[idx].num_rxqs)
+#define CFG_GET_NUM_RX_DESCS_NIC_IF(cfg, idx) \
+ ((cfg)->nic_if_cfg[idx].num_rx_descs)
+#define CFG_GET_NUM_TX_DESCS_NIC_IF(cfg, idx) \
+ ((cfg)->nic_if_cfg[idx].num_tx_descs)
+#define CFG_GET_NUM_RX_BUF_SIZE_NIC_IF(cfg, idx) \
+ ((cfg)->nic_if_cfg[idx].rx_buf_size)
+#define CFG_GET_BASE_QUE_NIC_IF(cfg, idx) \
+ ((cfg)->nic_if_cfg[idx].base_queue)
+#define CFG_GET_GMXID_NIC_IF(cfg, idx) \
+ ((cfg)->nic_if_cfg[idx].gmx_port_id)
+
+#define CFG_GET_CTRL_Q_GRP(cfg) ((cfg)->misc.ctrlq_grp)
+#define CFG_GET_HOST_LINK_QUERY_INTERVAL(cfg) \
+ ((cfg)->misc.host_link_query_interval)
+#define CFG_GET_OCT_LINK_QUERY_INTERVAL(cfg) \
+ ((cfg)->misc.oct_link_query_interval)
+#define CFG_GET_IS_SLI_BP_ON(cfg) ((cfg)->misc.enable_sli_oq_bp)
+
+/* Max IOQs per OCTEON Link */
+#define MAX_IOQS_PER_NICIF 32
+
+enum lio_card_type {
+ LIO_210SV = 0, /* Two port, 66xx */
+ LIO_210NV, /* Two port, 68xx */
+ LIO_410NV /* Four port, 68xx */
+};
+
+#define LIO_210SV_NAME "210sv"
+#define LIO_210NV_NAME "210nv"
+#define LIO_410NV_NAME "410nv"
+
+/** Structure to define the configuration attributes for each Input queue.
+ * Applicable to all Octeon processors
+ **/
+struct octeon_iq_config {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u64 reserved:32;
+
+ /** Minimum ticks to wait before checking for pending instructions. */
+ u64 db_timeout:16;
+
+ /** Minimum number of commands pending to be posted to Octeon
+ * before driver hits the Input queue doorbell.
+ */
+ u64 db_min:8;
+
+ /** Command size - 32 or 64 bytes */
+ u64 instr_type:32;
+
+ /** Pending list size (usually set to the sum of the size of all Input
+ * queues)
+ */
+ u64 pending_list_size:32;
+
+ /* Max number of IQs available */
+ u64 max_iqs:8;
+#else
+ /* Max number of IQs available */
+ u64 max_iqs:8;
+
+ /** Pending list size (usually set to the sum of the size of all Input
+ * queues)
+ */
+ u64 pending_list_size:32;
+
+ /** Command size - 32 or 64 bytes */
+ u64 instr_type:32;
+
+ /** Minimum number of commands pending to be posted to Octeon
+ * before driver hits the Input queue doorbell.
+ */
+ u64 db_min:8;
+
+ /** Minimum ticks to wait before checking for pending instructions. */
+ u64 db_timeout:16;
+
+ u64 reserved:32;
+#endif
+};
+
+/** Structure to define the configuration attributes for each Output queue.
+ * Applicable to all Octeon processors
+ **/
+struct octeon_oq_config {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u64 reserved:16;
+
+ u64 pkts_per_intr:16;
+
+ /** Interrupt Coalescing (Time Interval). Octeon will interrupt the
+ * host if atleast one packet was sent in the time interval specified
+ * by this field. The driver uses time interval interrupt coalescing
+ * by default. The time is specified in microseconds.
+ */
+ u64 oq_intr_time:16;
+
+ /** Interrupt Coalescing (Packet Count). Octeon will interrupt the host
+ * only if it sent as many packets as specified by this field.
+ * The driver
+ * usually does not use packet count interrupt coalescing.
+ */
+ u64 oq_intr_pkt:16;
+
+ /** The number of buffers that were consumed during packet processing by
+ * the driver on this Output queue before the driver attempts to
+ * replenish
+ * the descriptor ring with new buffers.
+ */
+ u64 refill_threshold:16;
+
+ /** If set, the Output queue uses info-pointer mode. (Default: 1 ) */
+ u64 info_ptr:32;
+
+ /* Max number of OQs available */
+ u64 max_oqs:8;
+
+#else
+ /* Max number of OQs available */
+ u64 max_oqs:8;
+
+ /** If set, the Output queue uses info-pointer mode. (Default: 1 ) */
+ u64 info_ptr:32;
+
+ /** The number of buffers that were consumed during packet processing by
+ * the driver on this Output queue before the driver attempts to
+ * replenish
+ * the descriptor ring with new buffers.
+ */
+ u64 refill_threshold:16;
+
+ /** Interrupt Coalescing (Packet Count). Octeon will interrupt the host
+ * only if it sent as many packets as specified by this field.
+ * The driver
+ * usually does not use packet count interrupt coalescing.
+ */
+ u64 oq_intr_pkt:16;
+
+ /** Interrupt Coalescing (Time Interval). Octeon will interrupt the
+ * host if atleast one packet was sent in the time interval specified
+ * by this field. The driver uses time interval interrupt coalescing
+ * by default. The time is specified in microseconds.
+ */
+ u64 oq_intr_time:16;
+
+ u64 pkts_per_intr:16;
+
+ u64 reserved:16;
+#endif
+
+};
+
+/** This structure conatins the NIC link configuration attributes,
+ * common for all the OCTEON Modles.
+ */
+struct octeon_nic_if_config {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u64 reserved:56;
+
+ u64 base_queue:16;
+
+ u64 gmx_port_id:8;
+
+ /* SKB size, We need not change buf size even for Jumbo frames.
+ * Octeon can send jumbo frames in 4 consecutive descriptors,
+ */
+ u64 rx_buf_size:16;
+
+ /* Num of desc for tx rings */
+ u64 num_tx_descs:16;
+
+ /* Num of desc for rx rings */
+ u64 num_rx_descs:16;
+
+ /* Actual configured value. Range could be: 1...max_rxqs */
+ u64 num_rxqs:16;
+
+ /* Max Rxqs: Half for each of the two ports :max_oq/2 */
+ u64 max_rxqs:16;
+
+ /* Actual configured value. Range could be: 1...max_txqs */
+ u64 num_txqs:16;
+
+ /* Max Txqs: Half for each of the two ports :max_iq/2 */
+ u64 max_txqs:16;
+#else
+ /* Max Txqs: Half for each of the two ports :max_iq/2 */
+ u64 max_txqs:16;
+
+ /* Actual configured value. Range could be: 1...max_txqs */
+ u64 num_txqs:16;
+
+ /* Max Rxqs: Half for each of the two ports :max_oq/2 */
+ u64 max_rxqs:16;
+
+ /* Actual configured value. Range could be: 1...max_rxqs */
+ u64 num_rxqs:16;
+
+ /* Num of desc for rx rings */
+ u64 num_rx_descs:16;
+
+ /* Num of desc for tx rings */
+ u64 num_tx_descs:16;
+
+ /* SKB size, We need not change buf size even for Jumbo frames.
+ * Octeon can send jumbo frames in 4 consecutive descriptors,
+ */
+ u64 rx_buf_size:16;
+
+ u64 gmx_port_id:8;
+
+ u64 base_queue:16;
+
+ u64 reserved:56;
+#endif
+
+};
+
+/** Structure to define the configuration attributes for meta data.
+ * Applicable to all Octeon processors.
+ */
+
+struct octeon_misc_config {
+#ifdef __BIG_ENDIAN_BITFIELD
+ /** Host link status polling period */
+ u64 host_link_query_interval:32;
+ /** Oct link status polling period */
+ u64 oct_link_query_interval:32;
+
+ u64 enable_sli_oq_bp:1;
+ /** Control IQ Group */
+ u64 ctrlq_grp:4;
+#else
+ /** Control IQ Group */
+ u64 ctrlq_grp:4;
+ /** BP for SLI OQ */
+ u64 enable_sli_oq_bp:1;
+ /** Host link status polling period */
+ u64 oct_link_query_interval:32;
+ /** Oct link status polling period */
+ u64 host_link_query_interval:32;
+#endif
+};
+
+/** Structure to define the configuration for all OCTEON processors. */
+struct octeon_config {
+ u16 card_type;
+ char *card_name;
+
+ /** Input Queue attributes. */
+ struct octeon_iq_config iq;
+
+ /** Output Queue attributes. */
+ struct octeon_oq_config oq;
+
+ /** NIC Port Configuration */
+ struct octeon_nic_if_config nic_if_cfg[MAX_OCTEON_NICIF];
+
+ /** Miscellaneous attributes */
+ struct octeon_misc_config misc;
+
+ int num_nic_ports;
+
+ int num_def_tx_descs;
+
+ /* Num of desc for rx rings */
+ int num_def_rx_descs;
+
+ int def_rx_buf_size;
+
+};
+
+/* The following config values are fixed and should not be modified. */
+
+/* Maximum address space to be mapped for Octeon's BAR1 index-based access. */
+#define MAX_BAR1_MAP_INDEX 2
+#define OCTEON_BAR1_ENTRY_SIZE (4 * 1024 * 1024)
+
+/* BAR1 Index 0 to (MAX_BAR1_MAP_INDEX - 1) for normal mapped memory access.
+ * Bar1 register at MAX_BAR1_MAP_INDEX used by driver for dynamic access.
+ */
+#define MAX_BAR1_IOREMAP_SIZE ((MAX_BAR1_MAP_INDEX + 1) * \
+ OCTEON_BAR1_ENTRY_SIZE)
+
+/* Response lists - 1 ordered, 1 unordered-blocking, 1 unordered-nonblocking
+ * NoResponse Lists are now maintained with each IQ. (Dec' 2007).
+ */
+#define MAX_RESPONSE_LISTS 4
+
+/* Opcode hash bits. The opcode is hashed on the lower 6-bits to lookup the
+ * dispatch table.
+ */
+#define OPCODE_MASK_BITS 6
+
+/* Mask for the 6-bit lookup hash */
+#define OCTEON_OPCODE_MASK 0x3f
+
+/* Size of the dispatch table. The 6-bit hash can index into 2^6 entries */
+#define DISPATCH_LIST_SIZE BIT(OPCODE_MASK_BITS)
+
+/* Maximum number of Octeon Instruction (command) queues */
+#define MAX_OCTEON_INSTR_QUEUES CN6XXX_MAX_INPUT_QUEUES
+
+/* Maximum number of Octeon Instruction (command) queues */
+#define MAX_OCTEON_OUTPUT_QUEUES CN6XXX_MAX_OUTPUT_QUEUES
+
+#endif /* __OCTEON_CONFIG_H__ */
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_console.c b/drivers/net/ethernet/cavium/liquidio/octeon_console.c
new file mode 100644
index 000000000000..466147e409c9
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_console.c
@@ -0,0 +1,723 @@
+/**********************************************************************
+* Author: Cavium, Inc.
+*
+* Contact: support@cavium.com
+* Please include "LiquidIO" in the subject.
+*
+* Copyright (c) 2003-2015 Cavium, Inc.
+*
+* This file 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 file is distributed in the hope that it will be useful, but
+* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+* NONINFRINGEMENT. See the GNU General Public License for more
+* details.
+*
+* This file may also be available under a different license from Cavium.
+* Contact Cavium, Inc. for more information
+**********************************************************************/
+
+/**
+ * @file octeon_console.c
+ */
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include "octeon_config.h"
+#include "liquidio_common.h"
+#include "octeon_droq.h"
+#include "octeon_iq.h"
+#include "response_manager.h"
+#include "octeon_device.h"
+#include "octeon_nic.h"
+#include "octeon_main.h"
+#include "octeon_network.h"
+#include "cn66xx_regs.h"
+#include "cn66xx_device.h"
+#include "cn68xx_regs.h"
+#include "cn68xx_device.h"
+#include "liquidio_image.h"
+#include "octeon_mem_ops.h"
+
+static void octeon_remote_lock(void);
+static void octeon_remote_unlock(void);
+static u64 cvmx_bootmem_phy_named_block_find(struct octeon_device *oct,
+ const char *name,
+ u32 flags);
+
+#define MIN(a, b) min((a), (b))
+#define CAST_ULL(v) ((u64)(v))
+
+#define BOOTLOADER_PCI_READ_BUFFER_DATA_ADDR 0x0006c008
+#define BOOTLOADER_PCI_READ_BUFFER_LEN_ADDR 0x0006c004
+#define BOOTLOADER_PCI_READ_BUFFER_OWNER_ADDR 0x0006c000
+#define BOOTLOADER_PCI_READ_DESC_ADDR 0x0006c100
+#define BOOTLOADER_PCI_WRITE_BUFFER_STR_LEN 248
+
+#define OCTEON_PCI_IO_BUF_OWNER_OCTEON 0x00000001
+#define OCTEON_PCI_IO_BUF_OWNER_HOST 0x00000002
+
+/** Can change without breaking ABI */
+#define CVMX_BOOTMEM_NUM_NAMED_BLOCKS 64
+
+/** minimum alignment of bootmem alloced blocks */
+#define CVMX_BOOTMEM_ALIGNMENT_SIZE (16ull)
+
+/** CVMX bootmem descriptor major version */
+#define CVMX_BOOTMEM_DESC_MAJ_VER 3
+/* CVMX bootmem descriptor minor version */
+#define CVMX_BOOTMEM_DESC_MIN_VER 0
+
+/* Current versions */
+#define OCTEON_PCI_CONSOLE_MAJOR_VERSION 1
+#define OCTEON_PCI_CONSOLE_MINOR_VERSION 0
+#define OCTEON_PCI_CONSOLE_BLOCK_NAME "__pci_console"
+#define OCTEON_CONSOLE_POLL_INTERVAL_MS 100 /* 10 times per second */
+
+/* First three members of cvmx_bootmem_desc are left in original
+** positions for backwards compatibility.
+** Assumes big endian target
+*/
+struct cvmx_bootmem_desc {
+ /** spinlock to control access to list */
+ u32 lock;
+
+ /** flags for indicating various conditions */
+ u32 flags;
+
+ u64 head_addr;
+
+ /** incremented changed when incompatible changes made */
+ u32 major_version;
+
+ /** incremented changed when compatible changes made,
+ * reset to zero when major incremented
+ */
+ u32 minor_version;
+
+ u64 app_data_addr;
+ u64 app_data_size;
+
+ /** number of elements in named blocks array */
+ u32 nb_num_blocks;
+
+ /** length of name array in bootmem blocks */
+ u32 named_block_name_len;
+
+ /** address of named memory block descriptors */
+ u64 named_block_array_addr;
+};
+
+/* Structure that defines a single console.
+ *
+ * Note: when read_index == write_index, the buffer is empty.
+ * The actual usable size of each console is console_buf_size -1;
+ */
+struct octeon_pci_console {
+ u64 input_base_addr;
+ u32 input_read_index;
+ u32 input_write_index;
+ u64 output_base_addr;
+ u32 output_read_index;
+ u32 output_write_index;
+ u32 lock;
+ u32 buf_size;
+};
+
+/* This is the main container structure that contains all the information
+ * about all PCI consoles. The address of this structure is passed to various
+ * routines that operation on PCI consoles.
+ */
+struct octeon_pci_console_desc {
+ u32 major_version;
+ u32 minor_version;
+ u32 lock;
+ u32 flags;
+ u32 num_consoles;
+ u32 pad;
+ /* must be 64 bit aligned here... */
+ /* Array of addresses of octeon_pci_console structures */
+ u64 console_addr_array[0];
+ /* Implicit storage for console_addr_array */
+};
+
+/**
+ * This macro returns the size of a member of a structure.
+ * Logically it is the same as "sizeof(s::field)" in C++, but
+ * C lacks the "::" operator.
+ */
+#define SIZEOF_FIELD(s, field) sizeof(((s *)NULL)->field)
+
+/**
+ * This macro returns a member of the cvmx_bootmem_desc
+ * structure. These members can't be directly addressed as
+ * they might be in memory not directly reachable. In the case
+ * where bootmem is compiled with LINUX_HOST, the structure
+ * itself might be located on a remote Octeon. The argument
+ * "field" is the member name of the cvmx_bootmem_desc to read.
+ * Regardless of the type of the field, the return type is always
+ * a u64.
+ */
+#define CVMX_BOOTMEM_DESC_GET_FIELD(oct, field) \
+ __cvmx_bootmem_desc_get(oct, oct->bootmem_desc_addr, \
+ offsetof(struct cvmx_bootmem_desc, field), \
+ SIZEOF_FIELD(struct cvmx_bootmem_desc, field))
+
+#define __cvmx_bootmem_lock(flags)
+#define __cvmx_bootmem_unlock(flags)
+
+/**
+ * This macro returns a member of the
+ * cvmx_bootmem_named_block_desc structure. These members can't
+ * be directly addressed as they might be in memory not directly
+ * reachable. In the case where bootmem is compiled with
+ * LINUX_HOST, the structure itself might be located on a remote
+ * Octeon. The argument "field" is the member name of the
+ * cvmx_bootmem_named_block_desc to read. Regardless of the type
+ * of the field, the return type is always a u64. The "addr"
+ * parameter is the physical address of the structure.
+ */
+#define CVMX_BOOTMEM_NAMED_GET_FIELD(oct, addr, field) \
+ __cvmx_bootmem_desc_get(oct, addr, \
+ offsetof(struct cvmx_bootmem_named_block_desc, field), \
+ SIZEOF_FIELD(struct cvmx_bootmem_named_block_desc, field))
+
+/**
+ * This function is the implementation of the get macros defined
+ * for individual structure members. The argument are generated
+ * by the macros inorder to read only the needed memory.
+ *
+ * @param oct Pointer to current octeon device
+ * @param base 64bit physical address of the complete structure
+ * @param offset Offset from the beginning of the structure to the member being
+ * accessed.
+ * @param size Size of the structure member.
+ *
+ * @return Value of the structure member promoted into a u64.
+ */
+static inline u64 __cvmx_bootmem_desc_get(struct octeon_device *oct,
+ u64 base,
+ u32 offset,
+ u32 size)
+{
+ base = (1ull << 63) | (base + offset);
+ switch (size) {
+ case 4:
+ return octeon_read_device_mem32(oct, base);
+ case 8:
+ return octeon_read_device_mem64(oct, base);
+ default:
+ return 0;
+ }
+}
+
+/**
+ * This function retrieves the string name of a named block. It is
+ * more complicated than a simple memcpy() since the named block
+ * descriptor may not be directly accessible.
+ *
+ * @param addr Physical address of the named block descriptor
+ * @param str String to receive the named block string name
+ * @param len Length of the string buffer, which must match the length
+ * stored in the bootmem descriptor.
+ */
+static void CVMX_BOOTMEM_NAMED_GET_NAME(struct octeon_device *oct,
+ u64 addr,
+ char *str,
+ u32 len)
+{
+ addr += offsetof(struct cvmx_bootmem_named_block_desc, name);
+ octeon_pci_read_core_mem(oct, addr, str, len);
+ str[len] = 0;
+}
+
+/* See header file for descriptions of functions */
+
+/**
+ * Check the version information on the bootmem descriptor
+ *
+ * @param exact_match
+ * Exact major version to check against. A zero means
+ * check that the version supports named blocks.
+ *
+ * @return Zero if the version is correct. Negative if the version is
+ * incorrect. Failures also cause a message to be displayed.
+ */
+static int __cvmx_bootmem_check_version(struct octeon_device *oct,
+ u32 exact_match)
+{
+ u32 major_version;
+ u32 minor_version;
+
+ if (!oct->bootmem_desc_addr)
+ oct->bootmem_desc_addr =
+ octeon_read_device_mem64(oct,
+ BOOTLOADER_PCI_READ_DESC_ADDR);
+ major_version =
+ (u32)CVMX_BOOTMEM_DESC_GET_FIELD(oct, major_version);
+ minor_version =
+ (u32)CVMX_BOOTMEM_DESC_GET_FIELD(oct, minor_version);
+ dev_dbg(&oct->pci_dev->dev, "%s: major_version=%d\n", __func__,
+ major_version);
+ if ((major_version > 3) ||
+ (exact_match && major_version != exact_match)) {
+ dev_err(&oct->pci_dev->dev, "bootmem ver mismatch %d.%d addr:0x%llx\n",
+ major_version, minor_version,
+ CAST_ULL(oct->bootmem_desc_addr));
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+static const struct cvmx_bootmem_named_block_desc
+*__cvmx_bootmem_find_named_block_flags(struct octeon_device *oct,
+ const char *name, u32 flags)
+{
+ struct cvmx_bootmem_named_block_desc *desc =
+ &oct->bootmem_named_block_desc;
+ u64 named_addr = cvmx_bootmem_phy_named_block_find(oct, name, flags);
+
+ if (named_addr) {
+ desc->base_addr = CVMX_BOOTMEM_NAMED_GET_FIELD(oct, named_addr,
+ base_addr);
+ desc->size =
+ CVMX_BOOTMEM_NAMED_GET_FIELD(oct, named_addr, size);
+ strncpy(desc->name, name, sizeof(desc->name));
+ desc->name[sizeof(desc->name) - 1] = 0;
+ return &oct->bootmem_named_block_desc;
+ } else {
+ return NULL;
+ }
+}
+
+static u64 cvmx_bootmem_phy_named_block_find(struct octeon_device *oct,
+ const char *name,
+ u32 flags)
+{
+ u64 result = 0;
+
+ __cvmx_bootmem_lock(flags);
+ if (!__cvmx_bootmem_check_version(oct, 3)) {
+ u32 i;
+ u64 named_block_array_addr =
+ CVMX_BOOTMEM_DESC_GET_FIELD(oct,
+ named_block_array_addr);
+ u32 num_blocks = (u32)
+ CVMX_BOOTMEM_DESC_GET_FIELD(oct, nb_num_blocks);
+ u32 name_length = (u32)
+ CVMX_BOOTMEM_DESC_GET_FIELD(oct, named_block_name_len);
+ u64 named_addr = named_block_array_addr;
+
+ for (i = 0; i < num_blocks; i++) {
+ u64 named_size =
+ CVMX_BOOTMEM_NAMED_GET_FIELD(oct, named_addr,
+ size);
+ if (name && named_size) {
+ char *name_tmp =
+ kmalloc(name_length + 1, GFP_KERNEL);
+ CVMX_BOOTMEM_NAMED_GET_NAME(oct, named_addr,
+ name_tmp,
+ name_length);
+ if (!strncmp(name, name_tmp, name_length)) {
+ result = named_addr;
+ kfree(name_tmp);
+ break;
+ }
+ kfree(name_tmp);
+ } else if (!name && !named_size) {
+ result = named_addr;
+ break;
+ }
+
+ named_addr +=
+ sizeof(struct cvmx_bootmem_named_block_desc);
+ }
+ }
+ __cvmx_bootmem_unlock(flags);
+ return result;
+}
+
+/**
+ * Find a named block on the remote Octeon
+ *
+ * @param name Name of block to find
+ * @param base_addr Address the block is at (OUTPUT)
+ * @param size The size of the block (OUTPUT)
+ *
+ * @return Zero on success, One on failure.
+ */
+static int octeon_named_block_find(struct octeon_device *oct, const char *name,
+ u64 *base_addr, u64 *size)
+{
+ const struct cvmx_bootmem_named_block_desc *named_block;
+
+ octeon_remote_lock();
+ named_block = __cvmx_bootmem_find_named_block_flags(oct, name, 0);
+ octeon_remote_unlock();
+ if (named_block) {
+ *base_addr = named_block->base_addr;
+ *size = named_block->size;
+ return 0;
+ }
+ return 1;
+}
+
+static void octeon_remote_lock(void)
+{
+ /* fill this in if any sharing is needed */
+}
+
+static void octeon_remote_unlock(void)
+{
+ /* fill this in if any sharing is needed */
+}
+
+int octeon_console_send_cmd(struct octeon_device *oct, char *cmd_str,
+ u32 wait_hundredths)
+{
+ u32 len = strlen(cmd_str);
+
+ dev_dbg(&oct->pci_dev->dev, "sending \"%s\" to bootloader\n", cmd_str);
+
+ if (len > BOOTLOADER_PCI_WRITE_BUFFER_STR_LEN - 1) {
+ dev_err(&oct->pci_dev->dev, "Command string too long, max length is: %d\n",
+ BOOTLOADER_PCI_WRITE_BUFFER_STR_LEN - 1);
+ return -1;
+ }
+
+ if (octeon_wait_for_bootloader(oct, wait_hundredths) != 0) {
+ dev_err(&oct->pci_dev->dev, "Bootloader not ready for command.\n");
+ return -1;
+ }
+
+ /* Write command to bootloader */
+ octeon_remote_lock();
+ octeon_pci_write_core_mem(oct, BOOTLOADER_PCI_READ_BUFFER_DATA_ADDR,
+ (u8 *)cmd_str, len);
+ octeon_write_device_mem32(oct, BOOTLOADER_PCI_READ_BUFFER_LEN_ADDR,
+ len);
+ octeon_write_device_mem32(oct, BOOTLOADER_PCI_READ_BUFFER_OWNER_ADDR,
+ OCTEON_PCI_IO_BUF_OWNER_OCTEON);
+
+ /* Bootloader should accept command very quickly
+ * if it really was ready
+ */
+ if (octeon_wait_for_bootloader(oct, 200) != 0) {
+ octeon_remote_unlock();
+ dev_err(&oct->pci_dev->dev, "Bootloader did not accept command.\n");
+ return -1;
+ }
+ octeon_remote_unlock();
+ return 0;
+}
+
+int octeon_wait_for_bootloader(struct octeon_device *oct,
+ u32 wait_time_hundredths)
+{
+ dev_dbg(&oct->pci_dev->dev, "waiting %d0 ms for bootloader\n",
+ wait_time_hundredths);
+
+ if (octeon_mem_access_ok(oct))
+ return -1;
+
+ while (wait_time_hundredths > 0 &&
+ octeon_read_device_mem32(oct,
+ BOOTLOADER_PCI_READ_BUFFER_OWNER_ADDR)
+ != OCTEON_PCI_IO_BUF_OWNER_HOST) {
+ if (--wait_time_hundredths <= 0)
+ return -1;
+ schedule_timeout_uninterruptible(HZ / 100);
+ }
+ return 0;
+}
+
+static void octeon_console_handle_result(struct octeon_device *oct,
+ size_t console_num,
+ char *buffer, s32 bytes_read)
+{
+ struct octeon_console *console;
+
+ console = &oct->console[console_num];
+
+ console->waiting = 0;
+}
+
+static char console_buffer[OCTEON_CONSOLE_MAX_READ_BYTES];
+
+static void output_console_line(struct octeon_device *oct,
+ struct octeon_console *console,
+ size_t console_num,
+ char *console_buffer,
+ s32 bytes_read)
+{
+ char *line;
+ s32 i;
+
+ line = console_buffer;
+ for (i = 0; i < bytes_read; i++) {
+ /* Output a line at a time, prefixed */
+ if (console_buffer[i] == '\n') {
+ console_buffer[i] = '\0';
+ if (console->leftover[0]) {
+ dev_info(&oct->pci_dev->dev, "%lu: %s%s\n",
+ console_num, console->leftover,
+ line);
+ console->leftover[0] = '\0';
+ } else {
+ dev_info(&oct->pci_dev->dev, "%lu: %s\n",
+ console_num, line);
+ }
+ line = &console_buffer[i + 1];
+ }
+ }
+
+ /* Save off any leftovers */
+ if (line != &console_buffer[bytes_read]) {
+ console_buffer[bytes_read] = '\0';
+ strcpy(console->leftover, line);
+ }
+}
+
+static void check_console(struct work_struct *work)
+{
+ s32 bytes_read, tries, total_read;
+ struct octeon_console *console;
+ struct cavium_wk *wk = (struct cavium_wk *)work;
+ struct octeon_device *oct = (struct octeon_device *)wk->ctxptr;
+ size_t console_num = wk->ctxul;
+ u32 delay;
+
+ console = &oct->console[console_num];
+ tries = 0;
+ total_read = 0;
+
+ do {
+ /* Take console output regardless of whether it will
+ * be logged
+ */
+ bytes_read =
+ octeon_console_read(oct, console_num, console_buffer,
+ sizeof(console_buffer) - 1, 0);
+ if (bytes_read > 0) {
+ total_read += bytes_read;
+ if (console->waiting) {
+ octeon_console_handle_result(oct, console_num,
+ console_buffer,
+ bytes_read);
+ }
+ if (octeon_console_debug_enabled(console_num)) {
+ output_console_line(oct, console, console_num,
+ console_buffer, bytes_read);
+ }
+ } else if (bytes_read < 0) {
+ dev_err(&oct->pci_dev->dev, "Error reading console %lu, ret=%d\n",
+ console_num, bytes_read);
+ }
+
+ tries++;
+ } while ((bytes_read > 0) && (tries < 16));
+
+ /* If nothing is read after polling the console,
+ * output any leftovers if any
+ */
+ if (octeon_console_debug_enabled(console_num) &&
+ (total_read == 0) && (console->leftover[0])) {
+ dev_info(&oct->pci_dev->dev, "%lu: %s\n",
+ console_num, console->leftover);
+ console->leftover[0] = '\0';
+ }
+
+ delay = OCTEON_CONSOLE_POLL_INTERVAL_MS;
+
+ schedule_delayed_work(&wk->work, msecs_to_jiffies(delay));
+}
+
+int octeon_init_consoles(struct octeon_device *oct)
+{
+ int ret = 0;
+ u64 addr, size;
+
+ ret = octeon_mem_access_ok(oct);
+ if (ret) {
+ dev_err(&oct->pci_dev->dev, "Memory access not okay'\n");
+ return ret;
+ }
+
+ ret = octeon_named_block_find(oct, OCTEON_PCI_CONSOLE_BLOCK_NAME, &addr,
+ &size);
+ if (ret) {
+ dev_err(&oct->pci_dev->dev, "Could not find console '%s'\n",
+ OCTEON_PCI_CONSOLE_BLOCK_NAME);
+ return ret;
+ }
+
+ /* num_consoles > 0, is an indication that the consoles
+ * are accessible
+ */
+ oct->num_consoles = octeon_read_device_mem32(oct,
+ addr + offsetof(struct octeon_pci_console_desc,
+ num_consoles));
+ oct->console_desc_addr = addr;
+
+ dev_dbg(&oct->pci_dev->dev, "Initialized consoles. %d available\n",
+ oct->num_consoles);
+
+ return ret;
+}
+
+int octeon_add_console(struct octeon_device *oct, u32 console_num)
+{
+ int ret = 0;
+ u32 delay;
+ u64 coreaddr;
+ struct delayed_work *work;
+ struct octeon_console *console;
+
+ if (console_num >= oct->num_consoles) {
+ dev_err(&oct->pci_dev->dev,
+ "trying to read from console number %d when only 0 to %d exist\n",
+ console_num, oct->num_consoles);
+ } else {
+ console = &oct->console[console_num];
+
+ console->waiting = 0;
+
+ coreaddr = oct->console_desc_addr + console_num * 8 +
+ offsetof(struct octeon_pci_console_desc,
+ console_addr_array);
+ console->addr = octeon_read_device_mem64(oct, coreaddr);
+ coreaddr = console->addr + offsetof(struct octeon_pci_console,
+ buf_size);
+ console->buffer_size = octeon_read_device_mem32(oct, coreaddr);
+ coreaddr = console->addr + offsetof(struct octeon_pci_console,
+ input_base_addr);
+ console->input_base_addr =
+ octeon_read_device_mem64(oct, coreaddr);
+ coreaddr = console->addr + offsetof(struct octeon_pci_console,
+ output_base_addr);
+ console->output_base_addr =
+ octeon_read_device_mem64(oct, coreaddr);
+ console->leftover[0] = '\0';
+
+ work = &oct->console_poll_work[console_num].work;
+
+ INIT_DELAYED_WORK(work, check_console);
+ oct->console_poll_work[console_num].ctxptr = (void *)oct;
+ oct->console_poll_work[console_num].ctxul = console_num;
+ delay = OCTEON_CONSOLE_POLL_INTERVAL_MS;
+ schedule_delayed_work(work, msecs_to_jiffies(delay));
+
+ if (octeon_console_debug_enabled(console_num)) {
+ ret = octeon_console_send_cmd(oct,
+ "setenv pci_console_active 1",
+ 2000);
+ }
+
+ console->active = 1;
+ }
+
+ return ret;
+}
+
+/**
+ * Removes all consoles
+ *
+ * @param oct octeon device
+ */
+void octeon_remove_consoles(struct octeon_device *oct)
+{
+ u32 i;
+ struct octeon_console *console;
+
+ for (i = 0; i < oct->num_consoles; i++) {
+ console = &oct->console[i];
+
+ if (!console->active)
+ continue;
+
+ cancel_delayed_work_sync(&oct->console_poll_work[i].
+ work);
+ console->addr = 0;
+ console->buffer_size = 0;
+ console->input_base_addr = 0;
+ console->output_base_addr = 0;
+ }
+
+ oct->num_consoles = 0;
+}
+
+static inline int octeon_console_free_bytes(u32 buffer_size,
+ u32 wr_idx,
+ u32 rd_idx)
+{
+ if (rd_idx >= buffer_size || wr_idx >= buffer_size)
+ return -1;
+
+ return ((buffer_size - 1) - (wr_idx - rd_idx)) % buffer_size;
+}
+
+static inline int octeon_console_avail_bytes(u32 buffer_size,
+ u32 wr_idx,
+ u32 rd_idx)
+{
+ if (rd_idx >= buffer_size || wr_idx >= buffer_size)
+ return -1;
+
+ return buffer_size - 1 -
+ octeon_console_free_bytes(buffer_size, wr_idx, rd_idx);
+}
+
+int octeon_console_read(struct octeon_device *oct, u32 console_num,
+ char *buffer, u32 buf_size, u32 flags)
+{
+ int bytes_to_read;
+ u32 rd_idx, wr_idx;
+ struct octeon_console *console;
+
+ if (console_num >= oct->num_consoles) {
+ dev_err(&oct->pci_dev->dev, "Attempted to read from disabled console %d\n",
+ console_num);
+ return 0;
+ }
+
+ console = &oct->console[console_num];
+
+ /* Check to see if any data is available.
+ * Maybe optimize this with 64-bit read.
+ */
+ rd_idx = octeon_read_device_mem32(oct, console->addr +
+ offsetof(struct octeon_pci_console, output_read_index));
+ wr_idx = octeon_read_device_mem32(oct, console->addr +
+ offsetof(struct octeon_pci_console, output_write_index));
+
+ bytes_to_read = octeon_console_avail_bytes(console->buffer_size,
+ wr_idx, rd_idx);
+ if (bytes_to_read <= 0)
+ return bytes_to_read;
+
+ bytes_to_read = MIN(bytes_to_read, (s32)buf_size);
+
+ /* Check to see if what we want to read is not contiguous, and limit
+ * ourselves to the contiguous block
+ */
+ if (rd_idx + bytes_to_read >= console->buffer_size)
+ bytes_to_read = console->buffer_size - rd_idx;
+
+ octeon_pci_read_core_mem(oct, console->output_base_addr + rd_idx,
+ buffer, bytes_to_read);
+ octeon_write_device_mem32(oct, console->addr +
+ offsetof(struct octeon_pci_console,
+ output_read_index),
+ (rd_idx + bytes_to_read) %
+ console->buffer_size);
+
+ return bytes_to_read;
+}
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.c b/drivers/net/ethernet/cavium/liquidio/octeon_device.c
new file mode 100644
index 000000000000..0d3106b464b2
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.c
@@ -0,0 +1,1309 @@
+/**********************************************************************
+* Author: Cavium, Inc.
+*
+* Contact: support@cavium.com
+* Please include "LiquidIO" in the subject.
+*
+* Copyright (c) 2003-2015 Cavium, Inc.
+*
+* This file 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 file is distributed in the hope that it will be useful, but
+* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+* NONINFRINGEMENT. See the GNU General Public License for more
+* details.
+*
+* This file may also be available under a different license from Cavium.
+* Contact Cavium, Inc. for more information
+**********************************************************************/
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/crc32.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include "octeon_config.h"
+#include "liquidio_common.h"
+#include "octeon_droq.h"
+#include "octeon_iq.h"
+#include "response_manager.h"
+#include "octeon_device.h"
+#include "octeon_nic.h"
+#include "octeon_main.h"
+#include "octeon_network.h"
+#include "cn66xx_regs.h"
+#include "cn66xx_device.h"
+#include "cn68xx_regs.h"
+#include "cn68xx_device.h"
+#include "liquidio_image.h"
+#include "octeon_mem_ops.h"
+
+/** Default configuration
+ * for CN66XX OCTEON Models.
+ */
+static struct octeon_config default_cn66xx_conf = {
+ .card_type = LIO_210SV,
+ .card_name = LIO_210SV_NAME,
+
+ /** IQ attributes */
+ .iq = {
+ .max_iqs = CN6XXX_CFG_IO_QUEUES,
+ .pending_list_size =
+ (CN6XXX_MAX_IQ_DESCRIPTORS * CN6XXX_CFG_IO_QUEUES),
+ .instr_type = OCTEON_64BYTE_INSTR,
+ .db_min = CN6XXX_DB_MIN,
+ .db_timeout = CN6XXX_DB_TIMEOUT,
+ }
+ ,
+
+ /** OQ attributes */
+ .oq = {
+ .max_oqs = CN6XXX_CFG_IO_QUEUES,
+ .info_ptr = OCTEON_OQ_INFOPTR_MODE,
+ .refill_threshold = CN6XXX_OQ_REFIL_THRESHOLD,
+ .oq_intr_pkt = CN6XXX_OQ_INTR_PKT,
+ .oq_intr_time = CN6XXX_OQ_INTR_TIME,
+ .pkts_per_intr = CN6XXX_OQ_PKTSPER_INTR,
+ }
+ ,
+
+ .num_nic_ports = DEFAULT_NUM_NIC_PORTS_66XX,
+ .num_def_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
+ .num_def_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
+ .def_rx_buf_size = CN6XXX_OQ_BUF_SIZE,
+
+ /* For ethernet interface 0: Port cfg Attributes */
+ .nic_if_cfg[0] = {
+ /* Max Txqs: Half for each of the two ports :max_iq/2 */
+ .max_txqs = MAX_TXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_txqs */
+ .num_txqs = DEF_TXQS_PER_INTF,
+
+ /* Max Rxqs: Half for each of the two ports :max_oq/2 */
+ .max_rxqs = MAX_RXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_rxqs */
+ .num_rxqs = DEF_RXQS_PER_INTF,
+
+ /* Num of desc for rx rings */
+ .num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
+
+ /* Num of desc for tx rings */
+ .num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
+
+ /* SKB size, We need not change buf size even for Jumbo frames.
+ * Octeon can send jumbo frames in 4 consecutive descriptors,
+ */
+ .rx_buf_size = CN6XXX_OQ_BUF_SIZE,
+
+ .base_queue = BASE_QUEUE_NOT_REQUESTED,
+
+ .gmx_port_id = 0,
+ },
+
+ .nic_if_cfg[1] = {
+ /* Max Txqs: Half for each of the two ports :max_iq/2 */
+ .max_txqs = MAX_TXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_txqs */
+ .num_txqs = DEF_TXQS_PER_INTF,
+
+ /* Max Rxqs: Half for each of the two ports :max_oq/2 */
+ .max_rxqs = MAX_RXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_rxqs */
+ .num_rxqs = DEF_RXQS_PER_INTF,
+
+ /* Num of desc for rx rings */
+ .num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
+
+ /* Num of desc for tx rings */
+ .num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
+
+ /* SKB size, We need not change buf size even for Jumbo frames.
+ * Octeon can send jumbo frames in 4 consecutive descriptors,
+ */
+ .rx_buf_size = CN6XXX_OQ_BUF_SIZE,
+
+ .base_queue = BASE_QUEUE_NOT_REQUESTED,
+
+ .gmx_port_id = 1,
+ },
+
+ /** Miscellaneous attributes */
+ .misc = {
+ /* Host driver link query interval */
+ .oct_link_query_interval = 100,
+
+ /* Octeon link query interval */
+ .host_link_query_interval = 500,
+
+ .enable_sli_oq_bp = 0,
+
+ /* Control queue group */
+ .ctrlq_grp = 1,
+ }
+ ,
+};
+
+/** Default configuration
+ * for CN68XX OCTEON Model.
+ */
+
+static struct octeon_config default_cn68xx_conf = {
+ .card_type = LIO_410NV,
+ .card_name = LIO_410NV_NAME,
+
+ /** IQ attributes */
+ .iq = {
+ .max_iqs = CN6XXX_CFG_IO_QUEUES,
+ .pending_list_size =
+ (CN6XXX_MAX_IQ_DESCRIPTORS * CN6XXX_CFG_IO_QUEUES),
+ .instr_type = OCTEON_64BYTE_INSTR,
+ .db_min = CN6XXX_DB_MIN,
+ .db_timeout = CN6XXX_DB_TIMEOUT,
+ }
+ ,
+
+ /** OQ attributes */
+ .oq = {
+ .max_oqs = CN6XXX_CFG_IO_QUEUES,
+ .info_ptr = OCTEON_OQ_INFOPTR_MODE,
+ .refill_threshold = CN6XXX_OQ_REFIL_THRESHOLD,
+ .oq_intr_pkt = CN6XXX_OQ_INTR_PKT,
+ .oq_intr_time = CN6XXX_OQ_INTR_TIME,
+ .pkts_per_intr = CN6XXX_OQ_PKTSPER_INTR,
+ }
+ ,
+
+ .num_nic_ports = DEFAULT_NUM_NIC_PORTS_68XX,
+ .num_def_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
+ .num_def_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
+ .def_rx_buf_size = CN6XXX_OQ_BUF_SIZE,
+
+ .nic_if_cfg[0] = {
+ /* Max Txqs: Half for each of the two ports :max_iq/2 */
+ .max_txqs = MAX_TXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_txqs */
+ .num_txqs = DEF_TXQS_PER_INTF,
+
+ /* Max Rxqs: Half for each of the two ports :max_oq/2 */
+ .max_rxqs = MAX_RXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_rxqs */
+ .num_rxqs = DEF_RXQS_PER_INTF,
+
+ /* Num of desc for rx rings */
+ .num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
+
+ /* Num of desc for tx rings */
+ .num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
+
+ /* SKB size, We need not change buf size even for Jumbo frames.
+ * Octeon can send jumbo frames in 4 consecutive descriptors,
+ */
+ .rx_buf_size = CN6XXX_OQ_BUF_SIZE,
+
+ .base_queue = BASE_QUEUE_NOT_REQUESTED,
+
+ .gmx_port_id = 0,
+ },
+
+ .nic_if_cfg[1] = {
+ /* Max Txqs: Half for each of the two ports :max_iq/2 */
+ .max_txqs = MAX_TXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_txqs */
+ .num_txqs = DEF_TXQS_PER_INTF,
+
+ /* Max Rxqs: Half for each of the two ports :max_oq/2 */
+ .max_rxqs = MAX_RXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_rxqs */
+ .num_rxqs = DEF_RXQS_PER_INTF,
+
+ /* Num of desc for rx rings */
+ .num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
+
+ /* Num of desc for tx rings */
+ .num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
+
+ /* SKB size, We need not change buf size even for Jumbo frames.
+ * Octeon can send jumbo frames in 4 consecutive descriptors,
+ */
+ .rx_buf_size = CN6XXX_OQ_BUF_SIZE,
+
+ .base_queue = BASE_QUEUE_NOT_REQUESTED,
+
+ .gmx_port_id = 1,
+ },
+
+ .nic_if_cfg[2] = {
+ /* Max Txqs: Half for each of the two ports :max_iq/2 */
+ .max_txqs = MAX_TXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_txqs */
+ .num_txqs = DEF_TXQS_PER_INTF,
+
+ /* Max Rxqs: Half for each of the two ports :max_oq/2 */
+ .max_rxqs = MAX_RXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_rxqs */
+ .num_rxqs = DEF_RXQS_PER_INTF,
+
+ /* Num of desc for rx rings */
+ .num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
+
+ /* Num of desc for tx rings */
+ .num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
+
+ /* SKB size, We need not change buf size even for Jumbo frames.
+ * Octeon can send jumbo frames in 4 consecutive descriptors,
+ */
+ .rx_buf_size = CN6XXX_OQ_BUF_SIZE,
+
+ .base_queue = BASE_QUEUE_NOT_REQUESTED,
+
+ .gmx_port_id = 2,
+ },
+
+ .nic_if_cfg[3] = {
+ /* Max Txqs: Half for each of the two ports :max_iq/2 */
+ .max_txqs = MAX_TXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_txqs */
+ .num_txqs = DEF_TXQS_PER_INTF,
+
+ /* Max Rxqs: Half for each of the two ports :max_oq/2 */
+ .max_rxqs = MAX_RXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_rxqs */
+ .num_rxqs = DEF_RXQS_PER_INTF,
+
+ /* Num of desc for rx rings */
+ .num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
+
+ /* Num of desc for tx rings */
+ .num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
+
+ /* SKB size, We need not change buf size even for Jumbo frames.
+ * Octeon can send jumbo frames in 4 consecutive descriptors,
+ */
+ .rx_buf_size = CN6XXX_OQ_BUF_SIZE,
+
+ .base_queue = BASE_QUEUE_NOT_REQUESTED,
+
+ .gmx_port_id = 3,
+ },
+
+ /** Miscellaneous attributes */
+ .misc = {
+ /* Host driver link query interval */
+ .oct_link_query_interval = 100,
+
+ /* Octeon link query interval */
+ .host_link_query_interval = 500,
+
+ .enable_sli_oq_bp = 0,
+
+ /* Control queue group */
+ .ctrlq_grp = 1,
+ }
+ ,
+};
+
+/** Default configuration
+ * for CN68XX OCTEON Model.
+ */
+static struct octeon_config default_cn68xx_210nv_conf = {
+ .card_type = LIO_210NV,
+ .card_name = LIO_210NV_NAME,
+
+ /** IQ attributes */
+
+ .iq = {
+ .max_iqs = CN6XXX_CFG_IO_QUEUES,
+ .pending_list_size =
+ (CN6XXX_MAX_IQ_DESCRIPTORS * CN6XXX_CFG_IO_QUEUES),
+ .instr_type = OCTEON_64BYTE_INSTR,
+ .db_min = CN6XXX_DB_MIN,
+ .db_timeout = CN6XXX_DB_TIMEOUT,
+ }
+ ,
+
+ /** OQ attributes */
+ .oq = {
+ .max_oqs = CN6XXX_CFG_IO_QUEUES,
+ .info_ptr = OCTEON_OQ_INFOPTR_MODE,
+ .refill_threshold = CN6XXX_OQ_REFIL_THRESHOLD,
+ .oq_intr_pkt = CN6XXX_OQ_INTR_PKT,
+ .oq_intr_time = CN6XXX_OQ_INTR_TIME,
+ .pkts_per_intr = CN6XXX_OQ_PKTSPER_INTR,
+ }
+ ,
+
+ .num_nic_ports = DEFAULT_NUM_NIC_PORTS_68XX_210NV,
+ .num_def_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
+ .num_def_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
+ .def_rx_buf_size = CN6XXX_OQ_BUF_SIZE,
+
+ .nic_if_cfg[0] = {
+ /* Max Txqs: Half for each of the two ports :max_iq/2 */
+ .max_txqs = MAX_TXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_txqs */
+ .num_txqs = DEF_TXQS_PER_INTF,
+
+ /* Max Rxqs: Half for each of the two ports :max_oq/2 */
+ .max_rxqs = MAX_RXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_rxqs */
+ .num_rxqs = DEF_RXQS_PER_INTF,
+
+ /* Num of desc for rx rings */
+ .num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
+
+ /* Num of desc for tx rings */
+ .num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
+
+ /* SKB size, We need not change buf size even for Jumbo frames.
+ * Octeon can send jumbo frames in 4 consecutive descriptors,
+ */
+ .rx_buf_size = CN6XXX_OQ_BUF_SIZE,
+
+ .base_queue = BASE_QUEUE_NOT_REQUESTED,
+
+ .gmx_port_id = 0,
+ },
+
+ .nic_if_cfg[1] = {
+ /* Max Txqs: Half for each of the two ports :max_iq/2 */
+ .max_txqs = MAX_TXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_txqs */
+ .num_txqs = DEF_TXQS_PER_INTF,
+
+ /* Max Rxqs: Half for each of the two ports :max_oq/2 */
+ .max_rxqs = MAX_RXQS_PER_INTF,
+
+ /* Actual configured value. Range could be: 1...max_rxqs */
+ .num_rxqs = DEF_RXQS_PER_INTF,
+
+ /* Num of desc for rx rings */
+ .num_rx_descs = CN6XXX_MAX_OQ_DESCRIPTORS,
+
+ /* Num of desc for tx rings */
+ .num_tx_descs = CN6XXX_MAX_IQ_DESCRIPTORS,
+
+ /* SKB size, We need not change buf size even for Jumbo frames.
+ * Octeon can send jumbo frames in 4 consecutive descriptors,
+ */
+ .rx_buf_size = CN6XXX_OQ_BUF_SIZE,
+
+ .base_queue = BASE_QUEUE_NOT_REQUESTED,
+
+ .gmx_port_id = 1,
+ },
+
+ /** Miscellaneous attributes */
+ .misc = {
+ /* Host driver link query interval */
+ .oct_link_query_interval = 100,
+
+ /* Octeon link query interval */
+ .host_link_query_interval = 500,
+
+ .enable_sli_oq_bp = 0,
+
+ /* Control queue group */
+ .ctrlq_grp = 1,
+ }
+ ,
+};
+
+enum {
+ OCTEON_CONFIG_TYPE_DEFAULT = 0,
+ NUM_OCTEON_CONFS,
+};
+
+static struct octeon_config_ptr {
+ u32 conf_type;
+} oct_conf_info[MAX_OCTEON_DEVICES] = {
+ {
+ OCTEON_CONFIG_TYPE_DEFAULT,
+ }, {
+ OCTEON_CONFIG_TYPE_DEFAULT,
+ }, {
+ OCTEON_CONFIG_TYPE_DEFAULT,
+ }, {
+ OCTEON_CONFIG_TYPE_DEFAULT,
+ },
+};
+
+static char oct_dev_state_str[OCT_DEV_STATES + 1][32] = {
+ "BEGIN", "PCI-MAP-DONE", "DISPATCH-INIT-DONE",
+ "IQ-INIT-DONE", "SCBUFF-POOL-INIT-DONE", "RESPLIST-INIT-DONE",
+ "DROQ-INIT-DONE", "IO-QUEUES-INIT-DONE", "CONSOLE-INIT-DONE",
+ "HOST-READY", "CORE-READY", "RUNNING", "IN-RESET",
+ "INVALID"
+};
+
+static char oct_dev_app_str[CVM_DRV_APP_COUNT + 1][32] = {
+ "BASE", "NIC", "UNKNOWN"};
+
+static struct octeon_device *octeon_device[MAX_OCTEON_DEVICES];
+static u32 octeon_device_count;
+
+static struct octeon_core_setup core_setup[MAX_OCTEON_DEVICES];
+
+static void oct_set_config_info(int oct_id, int conf_type)
+{
+ if (conf_type < 0 || conf_type > (NUM_OCTEON_CONFS - 1))
+ conf_type = OCTEON_CONFIG_TYPE_DEFAULT;
+ oct_conf_info[oct_id].conf_type = conf_type;
+}
+
+void octeon_init_device_list(int conf_type)
+{
+ int i;
+
+ memset(octeon_device, 0, (sizeof(void *) * MAX_OCTEON_DEVICES));
+ for (i = 0; i < MAX_OCTEON_DEVICES; i++)
+ oct_set_config_info(i, conf_type);
+}
+
+static void *__retrieve_octeon_config_info(struct octeon_device *oct,
+ u16 card_type)
+{
+ u32 oct_id = oct->octeon_id;
+ void *ret = NULL;
+
+ switch (oct_conf_info[oct_id].conf_type) {
+ case OCTEON_CONFIG_TYPE_DEFAULT:
+ if (oct->chip_id == OCTEON_CN66XX) {
+ ret = (void *)&default_cn66xx_conf;
+ } else if ((oct->chip_id == OCTEON_CN68XX) &&
+ (card_type == LIO_210NV)) {
+ ret = (void *)&default_cn68xx_210nv_conf;
+ } else if ((oct->chip_id == OCTEON_CN68XX) &&
+ (card_type == LIO_410NV)) {
+ ret = (void *)&default_cn68xx_conf;
+ }
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+static int __verify_octeon_config_info(struct octeon_device *oct, void *conf)
+{
+ switch (oct->chip_id) {
+ case OCTEON_CN66XX:
+ case OCTEON_CN68XX:
+ return lio_validate_cn6xxx_config_info(oct, conf);
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+void *oct_get_config_info(struct octeon_device *oct, u16 card_type)
+{
+ void *conf = NULL;
+
+ conf = __retrieve_octeon_config_info(oct, card_type);
+ if (!conf)
+ return NULL;
+
+ if (__verify_octeon_config_info(oct, conf)) {
+ dev_err(&oct->pci_dev->dev, "Configuration verification failed\n");
+ return NULL;
+ }
+
+ return conf;
+}
+
+char *lio_get_state_string(atomic_t *state_ptr)
+{
+ s32 istate = (s32)atomic_read(state_ptr);
+
+ if (istate > OCT_DEV_STATES || istate < 0)
+ return oct_dev_state_str[OCT_DEV_STATE_INVALID];
+ return oct_dev_state_str[istate];
+}
+
+static char *get_oct_app_string(u32 app_mode)
+{
+ if (app_mode <= CVM_DRV_APP_END)
+ return oct_dev_app_str[app_mode - CVM_DRV_APP_START];
+ return oct_dev_app_str[CVM_DRV_INVALID_APP - CVM_DRV_APP_START];
+}
+
+int octeon_download_firmware(struct octeon_device *oct, const u8 *data,
+ size_t size)
+{
+ int ret = 0;
+ u8 *p;
+ u8 *buffer;
+ u32 crc32_result;
+ u64 load_addr;
+ u32 image_len;
+ struct octeon_firmware_file_header *h;
+ u32 i;
+
+ if (size < sizeof(struct octeon_firmware_file_header)) {
+ dev_err(&oct->pci_dev->dev, "Firmware file too small (%d < %d).\n",
+ (u32)size,
+ (u32)sizeof(struct octeon_firmware_file_header));
+ return -EINVAL;
+ }
+
+ h = (struct octeon_firmware_file_header *)data;
+
+ if (be32_to_cpu(h->magic) != LIO_NIC_MAGIC) {
+ dev_err(&oct->pci_dev->dev, "Unrecognized firmware file.\n");
+ return -EINVAL;
+ }
+
+ crc32_result =
+ crc32(~0, data,
+ sizeof(struct octeon_firmware_file_header) -
+ sizeof(u32)) ^ ~0U;
+ if (crc32_result != be32_to_cpu(h->crc32)) {
+ dev_err(&oct->pci_dev->dev, "Firmware CRC mismatch (0x%08x != 0x%08x).\n",
+ crc32_result, be32_to_cpu(h->crc32));
+ return -EINVAL;
+ }
+
+ if (memcmp(LIQUIDIO_VERSION, h->version, strlen(LIQUIDIO_VERSION))) {
+ dev_err(&oct->pci_dev->dev, "Unmatched firmware version. Expected %s, got %s.\n",
+ LIQUIDIO_VERSION, h->version);
+ return -EINVAL;
+ }
+
+ if (be32_to_cpu(h->num_images) > LIO_MAX_IMAGES) {
+ dev_err(&oct->pci_dev->dev, "Too many images in firmware file (%d).\n",
+ be32_to_cpu(h->num_images));
+ return -EINVAL;
+ }
+
+ dev_info(&oct->pci_dev->dev, "Firmware version: %s\n", h->version);
+ snprintf(oct->fw_info.liquidio_firmware_version, 32, "LIQUIDIO: %s",
+ h->version);
+
+ buffer = kmalloc(size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ memcpy(buffer, data, size);
+
+ p = buffer + sizeof(struct octeon_firmware_file_header);
+
+ /* load all images */
+ for (i = 0; i < be32_to_cpu(h->num_images); i++) {
+ load_addr = be64_to_cpu(h->desc[i].addr);
+ image_len = be32_to_cpu(h->desc[i].len);
+
+ /* validate the image */
+ crc32_result = crc32(~0, p, image_len) ^ ~0U;
+ if (crc32_result != be32_to_cpu(h->desc[i].crc32)) {
+ dev_err(&oct->pci_dev->dev,
+ "Firmware CRC mismatch in image %d (0x%08x != 0x%08x).\n",
+ i, crc32_result,
+ be32_to_cpu(h->desc[i].crc32));
+ ret = -EINVAL;
+ goto done_downloading;
+ }
+
+ /* download the image */
+ octeon_pci_write_core_mem(oct, load_addr, p, image_len);
+
+ p += image_len;
+ dev_dbg(&oct->pci_dev->dev,
+ "Downloaded image %d (%d bytes) to address 0x%016llx\n",
+ i, image_len, load_addr);
+ }
+
+ /* Invoke the bootcmd */
+ ret = octeon_console_send_cmd(oct, h->bootcmd, 50);
+
+done_downloading:
+ kfree(buffer);
+
+ return ret;
+}
+
+void octeon_free_device_mem(struct octeon_device *oct)
+{
+ u32 i;
+
+ for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) {
+ /* could check mask as well */
+ if (oct->droq[i])
+ vfree(oct->droq[i]);
+ }
+
+ for (i = 0; i < MAX_OCTEON_INSTR_QUEUES; i++) {
+ /* could check mask as well */
+ if (oct->instr_queue[i])
+ vfree(oct->instr_queue[i]);
+ }
+
+ i = oct->octeon_id;
+ vfree(oct);
+
+ octeon_device[i] = NULL;
+ octeon_device_count--;
+}
+
+static struct octeon_device *octeon_allocate_device_mem(u32 pci_id,
+ u32 priv_size)
+{
+ struct octeon_device *oct;
+ u8 *buf = NULL;
+ u32 octdevsize = 0, configsize = 0, size;
+
+ switch (pci_id) {
+ case OCTEON_CN68XX:
+ case OCTEON_CN66XX:
+ configsize = sizeof(struct octeon_cn6xxx);
+ break;
+
+ default:
+ pr_err("%s: Unknown PCI Device: 0x%x\n",
+ __func__,
+ pci_id);
+ return NULL;
+ }
+
+ if (configsize & 0x7)
+ configsize += (8 - (configsize & 0x7));
+
+ octdevsize = sizeof(struct octeon_device);
+ if (octdevsize & 0x7)
+ octdevsize += (8 - (octdevsize & 0x7));
+
+ if (priv_size & 0x7)
+ priv_size += (8 - (priv_size & 0x7));
+
+ size = octdevsize + priv_size + configsize +
+ (sizeof(struct octeon_dispatch) * DISPATCH_LIST_SIZE);
+
+ buf = vmalloc(size);
+ if (!buf)
+ return NULL;
+
+ memset(buf, 0, size);
+
+ oct = (struct octeon_device *)buf;
+ oct->priv = (void *)(buf + octdevsize);
+ oct->chip = (void *)(buf + octdevsize + priv_size);
+ oct->dispatch.dlist = (struct octeon_dispatch *)
+ (buf + octdevsize + priv_size + configsize);
+
+ return oct;
+}
+
+struct octeon_device *octeon_allocate_device(u32 pci_id,
+ u32 priv_size)
+{
+ u32 oct_idx = 0;
+ struct octeon_device *oct = NULL;
+
+ for (oct_idx = 0; oct_idx < MAX_OCTEON_DEVICES; oct_idx++)
+ if (!octeon_device[oct_idx])
+ break;
+
+ if (oct_idx == MAX_OCTEON_DEVICES)
+ return NULL;
+
+ oct = octeon_allocate_device_mem(pci_id, priv_size);
+ if (!oct)
+ return NULL;
+
+ spin_lock_init(&oct->pci_win_lock);
+ spin_lock_init(&oct->mem_access_lock);
+
+ octeon_device_count++;
+ octeon_device[oct_idx] = oct;
+
+ oct->octeon_id = oct_idx;
+ snprintf((oct->device_name), sizeof(oct->device_name),
+ "LiquidIO%d", (oct->octeon_id));
+
+ return oct;
+}
+
+int octeon_setup_instr_queues(struct octeon_device *oct)
+{
+ u32 i, num_iqs = 0;
+ u32 num_descs = 0;
+
+ /* this causes queue 0 to be default queue */
+ if (OCTEON_CN6XXX(oct)) {
+ num_iqs = 1;
+ num_descs =
+ CFG_GET_NUM_DEF_TX_DESCS(CHIP_FIELD(oct, cn6xxx, conf));
+ }
+
+ oct->num_iqs = 0;
+
+ for (i = 0; i < num_iqs; i++) {
+ oct->instr_queue[i] =
+ vmalloc(sizeof(struct octeon_instr_queue));
+ if (!oct->instr_queue[i])
+ return 1;
+
+ memset(oct->instr_queue[i], 0,
+ sizeof(struct octeon_instr_queue));
+
+ oct->instr_queue[i]->app_ctx = (void *)(size_t)i;
+ if (octeon_init_instr_queue(oct, i, num_descs))
+ return 1;
+
+ oct->num_iqs++;
+ }
+
+ return 0;
+}
+
+int octeon_setup_output_queues(struct octeon_device *oct)
+{
+ u32 i, num_oqs = 0;
+ u32 num_descs = 0;
+ u32 desc_size = 0;
+
+ /* this causes queue 0 to be default queue */
+ if (OCTEON_CN6XXX(oct)) {
+ /* CFG_GET_OQ_MAX_BASE_Q(CHIP_FIELD(oct, cn6xxx, conf)); */
+ num_oqs = 1;
+ num_descs =
+ CFG_GET_NUM_DEF_RX_DESCS(CHIP_FIELD(oct, cn6xxx, conf));
+ desc_size =
+ CFG_GET_DEF_RX_BUF_SIZE(CHIP_FIELD(oct, cn6xxx, conf));
+ }
+
+ oct->num_oqs = 0;
+
+ for (i = 0; i < num_oqs; i++) {
+ oct->droq[i] = vmalloc(sizeof(*oct->droq[i]));
+ if (!oct->droq[i])
+ return 1;
+
+ memset(oct->droq[i], 0, sizeof(struct octeon_droq));
+
+ if (octeon_init_droq(oct, i, num_descs, desc_size, NULL))
+ return 1;
+
+ oct->num_oqs++;
+ }
+
+ return 0;
+}
+
+void octeon_set_io_queues_off(struct octeon_device *oct)
+{
+ /* Disable the i/p and o/p queues for this Octeon. */
+
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB, 0);
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_OUT_ENB, 0);
+}
+
+void octeon_set_droq_pkt_op(struct octeon_device *oct,
+ u32 q_no,
+ u32 enable)
+{
+ u32 reg_val = 0;
+
+ /* Disable the i/p and o/p queues for this Octeon. */
+ reg_val = octeon_read_csr(oct, CN6XXX_SLI_PKT_OUT_ENB);
+
+ if (enable)
+ reg_val = reg_val | (1 << q_no);
+ else
+ reg_val = reg_val & (~(1 << q_no));
+
+ octeon_write_csr(oct, CN6XXX_SLI_PKT_OUT_ENB, reg_val);
+}
+
+int octeon_init_dispatch_list(struct octeon_device *oct)
+{
+ u32 i;
+
+ oct->dispatch.count = 0;
+
+ for (i = 0; i < DISPATCH_LIST_SIZE; i++) {
+ oct->dispatch.dlist[i].opcode = 0;
+ INIT_LIST_HEAD(&oct->dispatch.dlist[i].list);
+ }
+
+ for (i = 0; i <= REQTYPE_LAST; i++)
+ octeon_register_reqtype_free_fn(oct, i, NULL);
+
+ spin_lock_init(&oct->dispatch.lock);
+
+ return 0;
+}
+
+void octeon_delete_dispatch_list(struct octeon_device *oct)
+{
+ u32 i;
+ struct list_head freelist, *temp, *tmp2;
+
+ INIT_LIST_HEAD(&freelist);
+
+ spin_lock_bh(&oct->dispatch.lock);
+
+ for (i = 0; i < DISPATCH_LIST_SIZE; i++) {
+ struct list_head *dispatch;
+
+ dispatch = &oct->dispatch.dlist[i].list;
+ while (dispatch->next != dispatch) {
+ temp = dispatch->next;
+ list_del(temp);
+ list_add_tail(temp, &freelist);
+ }
+
+ oct->dispatch.dlist[i].opcode = 0;
+ }
+
+ oct->dispatch.count = 0;
+
+ spin_unlock_bh(&oct->dispatch.lock);
+
+ list_for_each_safe(temp, tmp2, &freelist) {
+ list_del(temp);
+ vfree(temp);
+ }
+}
+
+octeon_dispatch_fn_t
+octeon_get_dispatch(struct octeon_device *octeon_dev, u16 opcode,
+ u16 subcode)
+{
+ u32 idx;
+ struct list_head *dispatch;
+ octeon_dispatch_fn_t fn = NULL;
+ u16 combined_opcode = OPCODE_SUBCODE(opcode, subcode);
+
+ idx = combined_opcode & OCTEON_OPCODE_MASK;
+
+ spin_lock_bh(&octeon_dev->dispatch.lock);
+
+ if (octeon_dev->dispatch.count == 0) {
+ spin_unlock_bh(&octeon_dev->dispatch.lock);
+ return NULL;
+ }
+
+ if (!(octeon_dev->dispatch.dlist[idx].opcode)) {
+ spin_unlock_bh(&octeon_dev->dispatch.lock);
+ return NULL;
+ }
+
+ if (octeon_dev->dispatch.dlist[idx].opcode == combined_opcode) {
+ fn = octeon_dev->dispatch.dlist[idx].dispatch_fn;
+ } else {
+ list_for_each(dispatch,
+ &octeon_dev->dispatch.dlist[idx].list) {
+ if (((struct octeon_dispatch *)dispatch)->opcode ==
+ combined_opcode) {
+ fn = ((struct octeon_dispatch *)
+ dispatch)->dispatch_fn;
+ break;
+ }
+ }
+ }
+
+ spin_unlock_bh(&octeon_dev->dispatch.lock);
+ return fn;
+}
+
+/* octeon_register_dispatch_fn
+ * Parameters:
+ * octeon_id - id of the octeon device.
+ * opcode - opcode for which driver should call the registered function
+ * subcode - subcode for which driver should call the registered function
+ * fn - The function to call when a packet with "opcode" arrives in
+ * octeon output queues.
+ * fn_arg - The argument to be passed when calling function "fn".
+ * Description:
+ * Registers a function and its argument to be called when a packet
+ * arrives in Octeon output queues with "opcode".
+ * Returns:
+ * Success: 0
+ * Failure: 1
+ * Locks:
+ * No locks are held.
+ */
+int
+octeon_register_dispatch_fn(struct octeon_device *oct,
+ u16 opcode,
+ u16 subcode,
+ octeon_dispatch_fn_t fn, void *fn_arg)
+{
+ u32 idx;
+ octeon_dispatch_fn_t pfn;
+ u16 combined_opcode = OPCODE_SUBCODE(opcode, subcode);
+
+ idx = combined_opcode & OCTEON_OPCODE_MASK;
+
+ spin_lock_bh(&oct->dispatch.lock);
+ /* Add dispatch function to first level of lookup table */
+ if (oct->dispatch.dlist[idx].opcode == 0) {
+ oct->dispatch.dlist[idx].opcode = combined_opcode;
+ oct->dispatch.dlist[idx].dispatch_fn = fn;
+ oct->dispatch.dlist[idx].arg = fn_arg;
+ oct->dispatch.count++;
+ spin_unlock_bh(&oct->dispatch.lock);
+ return 0;
+ }
+
+ spin_unlock_bh(&oct->dispatch.lock);
+
+ /* Check if there was a function already registered for this
+ * opcode/subcode.
+ */
+ pfn = octeon_get_dispatch(oct, opcode, subcode);
+ if (!pfn) {
+ struct octeon_dispatch *dispatch;
+
+ dev_dbg(&oct->pci_dev->dev,
+ "Adding opcode to dispatch list linked list\n");
+ dispatch = (struct octeon_dispatch *)
+ vmalloc(sizeof(struct octeon_dispatch));
+ if (!dispatch) {
+ dev_err(&oct->pci_dev->dev,
+ "No memory to add dispatch function\n");
+ return 1;
+ }
+ dispatch->opcode = combined_opcode;
+ dispatch->dispatch_fn = fn;
+ dispatch->arg = fn_arg;
+
+ /* Add dispatch function to linked list of fn ptrs
+ * at the hashed index.
+ */
+ spin_lock_bh(&oct->dispatch.lock);
+ list_add(&dispatch->list, &oct->dispatch.dlist[idx].list);
+ oct->dispatch.count++;
+ spin_unlock_bh(&oct->dispatch.lock);
+
+ } else {
+ dev_err(&oct->pci_dev->dev,
+ "Found previously registered dispatch fn for opcode/subcode: %x/%x\n",
+ opcode, subcode);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* octeon_unregister_dispatch_fn
+ * Parameters:
+ * oct - octeon device
+ * opcode - driver should unregister the function for this opcode
+ * subcode - driver should unregister the function for this subcode
+ * Description:
+ * Unregister the function set for this opcode+subcode.
+ * Returns:
+ * Success: 0
+ * Failure: 1
+ * Locks:
+ * No locks are held.
+ */
+int
+octeon_unregister_dispatch_fn(struct octeon_device *oct, u16 opcode,
+ u16 subcode)
+{
+ int retval = 0;
+ u32 idx;
+ struct list_head *dispatch, *dfree = NULL, *tmp2;
+ u16 combined_opcode = OPCODE_SUBCODE(opcode, subcode);
+
+ idx = combined_opcode & OCTEON_OPCODE_MASK;
+
+ spin_lock_bh(&oct->dispatch.lock);
+
+ if (oct->dispatch.count == 0) {
+ spin_unlock_bh(&oct->dispatch.lock);
+ dev_err(&oct->pci_dev->dev,
+ "No dispatch functions registered for this device\n");
+ return 1;
+ }
+
+ if (oct->dispatch.dlist[idx].opcode == combined_opcode) {
+ dispatch = &oct->dispatch.dlist[idx].list;
+ if (dispatch->next != dispatch) {
+ dispatch = dispatch->next;
+ oct->dispatch.dlist[idx].opcode =
+ ((struct octeon_dispatch *)dispatch)->opcode;
+ oct->dispatch.dlist[idx].dispatch_fn =
+ ((struct octeon_dispatch *)
+ dispatch)->dispatch_fn;
+ oct->dispatch.dlist[idx].arg =
+ ((struct octeon_dispatch *)dispatch)->arg;
+ list_del(dispatch);
+ dfree = dispatch;
+ } else {
+ oct->dispatch.dlist[idx].opcode = 0;
+ oct->dispatch.dlist[idx].dispatch_fn = NULL;
+ oct->dispatch.dlist[idx].arg = NULL;
+ }
+ } else {
+ retval = 1;
+ list_for_each_safe(dispatch, tmp2,
+ &(oct->dispatch.dlist[idx].
+ list)) {
+ if (((struct octeon_dispatch *)dispatch)->opcode ==
+ combined_opcode) {
+ list_del(dispatch);
+ dfree = dispatch;
+ retval = 0;
+ }
+ }
+ }
+
+ if (!retval)
+ oct->dispatch.count--;
+
+ spin_unlock_bh(&oct->dispatch.lock);
+
+ if (dfree)
+ vfree(dfree);
+
+ return retval;
+}
+
+int octeon_core_drv_init(struct octeon_recv_info *recv_info, void *buf)
+{
+ u32 i;
+ char app_name[16];
+ struct octeon_device *oct = (struct octeon_device *)buf;
+ struct octeon_recv_pkt *recv_pkt = recv_info->recv_pkt;
+ struct octeon_core_setup *cs = NULL;
+ u32 num_nic_ports = 0;
+
+ if (OCTEON_CN6XXX(oct))
+ num_nic_ports =
+ CFG_GET_NUM_NIC_PORTS(CHIP_FIELD(oct, cn6xxx, conf));
+
+ if (atomic_read(&oct->status) >= OCT_DEV_RUNNING) {
+ dev_err(&oct->pci_dev->dev, "Received CORE OK when device state is 0x%x\n",
+ atomic_read(&oct->status));
+ goto core_drv_init_err;
+ }
+
+ strncpy(app_name,
+ get_oct_app_string(
+ (u32)recv_pkt->rh.r_core_drv_init.app_mode),
+ sizeof(app_name) - 1);
+ oct->app_mode = (u32)recv_pkt->rh.r_core_drv_init.app_mode;
+ if (recv_pkt->rh.r_core_drv_init.app_mode == CVM_DRV_NIC_APP) {
+ oct->fw_info.max_nic_ports =
+ (u32)recv_pkt->rh.r_core_drv_init.max_nic_ports;
+ oct->fw_info.num_gmx_ports =
+ (u32)recv_pkt->rh.r_core_drv_init.num_gmx_ports;
+ }
+
+ if (oct->fw_info.max_nic_ports < num_nic_ports) {
+ dev_err(&oct->pci_dev->dev,
+ "Config has more ports than firmware allows (%d > %d).\n",
+ num_nic_ports, oct->fw_info.max_nic_ports);
+ goto core_drv_init_err;
+ }
+ oct->fw_info.app_cap_flags = recv_pkt->rh.r_core_drv_init.app_cap_flags;
+ oct->fw_info.app_mode = (u32)recv_pkt->rh.r_core_drv_init.app_mode;
+
+ atomic_set(&oct->status, OCT_DEV_CORE_OK);
+
+ cs = &core_setup[oct->octeon_id];
+
+ if (recv_pkt->buffer_size[0] != sizeof(*cs)) {
+ dev_dbg(&oct->pci_dev->dev, "Core setup bytes expected %u found %d\n",
+ (u32)sizeof(*cs),
+ recv_pkt->buffer_size[0]);
+ }
+
+ memcpy(cs, get_rbd(recv_pkt->buffer_ptr[0]), sizeof(*cs));
+ strncpy(oct->boardinfo.name, cs->boardname, OCT_BOARD_NAME);
+ strncpy(oct->boardinfo.serial_number, cs->board_serial_number,
+ OCT_SERIAL_LEN);
+
+ octeon_swap_8B_data((u64 *)cs, (sizeof(*cs) >> 3));
+
+ oct->boardinfo.major = cs->board_rev_major;
+ oct->boardinfo.minor = cs->board_rev_minor;
+
+ dev_info(&oct->pci_dev->dev,
+ "Running %s (%llu Hz)\n",
+ app_name, CVM_CAST64(cs->corefreq));
+
+core_drv_init_err:
+ for (i = 0; i < recv_pkt->buffer_count; i++)
+ recv_buffer_free(recv_pkt->buffer_ptr[i]);
+ octeon_free_recv_info(recv_info);
+ return 0;
+}
+
+int octeon_get_tx_qsize(struct octeon_device *oct, u32 q_no)
+
+{
+ if (oct && (q_no < MAX_OCTEON_INSTR_QUEUES) &&
+ (oct->io_qmask.iq & (1UL << q_no)))
+ return oct->instr_queue[q_no]->max_count;
+
+ return -1;
+}
+
+int octeon_get_rx_qsize(struct octeon_device *oct, u32 q_no)
+{
+ if (oct && (q_no < MAX_OCTEON_OUTPUT_QUEUES) &&
+ (oct->io_qmask.oq & (1UL << q_no)))
+ return oct->droq[q_no]->max_count;
+ return -1;
+}
+
+/* Retruns the host firmware handshake OCTEON specific configuration */
+struct octeon_config *octeon_get_conf(struct octeon_device *oct)
+{
+ struct octeon_config *default_oct_conf = NULL;
+
+ /* check the OCTEON Device model & return the corresponding octeon
+ * configuration
+ */
+
+ if (OCTEON_CN6XXX(oct)) {
+ default_oct_conf =
+ (struct octeon_config *)(CHIP_FIELD(oct, cn6xxx, conf));
+ }
+
+ return default_oct_conf;
+}
+
+/* scratch register address is same in all the OCT-II and CN70XX models */
+#define CNXX_SLI_SCRATCH1 0x3C0
+
+/** Get the octeon device pointer.
+ * @param octeon_id - The id for which the octeon device pointer is required.
+ * @return Success: Octeon device pointer.
+ * @return Failure: NULL.
+ */
+struct octeon_device *lio_get_device(u32 octeon_id)
+{
+ if (octeon_id >= MAX_OCTEON_DEVICES)
+ return NULL;
+ else
+ return octeon_device[octeon_id];
+}
+
+u64 lio_pci_readq(struct octeon_device *oct, u64 addr)
+{
+ u64 val64;
+ unsigned long flags;
+ u32 val32, addrhi;
+
+ spin_lock_irqsave(&oct->pci_win_lock, flags);
+
+ /* The windowed read happens when the LSB of the addr is written.
+ * So write MSB first
+ */
+ addrhi = (addr >> 32);
+ if ((oct->chip_id == OCTEON_CN66XX) || (oct->chip_id == OCTEON_CN68XX))
+ addrhi |= 0x00060000;
+ writel(addrhi, oct->reg_list.pci_win_rd_addr_hi);
+
+ /* Read back to preserve ordering of writes */
+ val32 = readl(oct->reg_list.pci_win_rd_addr_hi);
+
+ writel(addr & 0xffffffff, oct->reg_list.pci_win_rd_addr_lo);
+ val32 = readl(oct->reg_list.pci_win_rd_addr_lo);
+
+ val64 = readq(oct->reg_list.pci_win_rd_data);
+
+ spin_unlock_irqrestore(&oct->pci_win_lock, flags);
+
+ return val64;
+}
+
+void lio_pci_writeq(struct octeon_device *oct,
+ u64 val,
+ u64 addr)
+{
+ u32 val32;
+ unsigned long flags;
+
+ spin_lock_irqsave(&oct->pci_win_lock, flags);
+
+ writeq(addr, oct->reg_list.pci_win_wr_addr);
+
+ /* The write happens when the LSB is written. So write MSB first. */
+ writel(val >> 32, oct->reg_list.pci_win_wr_data_hi);
+ /* Read the MSB to ensure ordering of writes. */
+ val32 = readl(oct->reg_list.pci_win_wr_data_hi);
+
+ writel(val & 0xffffffff, oct->reg_list.pci_win_wr_data_lo);
+
+ spin_unlock_irqrestore(&oct->pci_win_lock, flags);
+}
+
+int octeon_mem_access_ok(struct octeon_device *oct)
+{
+ u64 access_okay = 0;
+
+ /* Check to make sure a DDR interface is enabled */
+ u64 lmc0_reset_ctl = lio_pci_readq(oct, CN6XXX_LMC0_RESET_CTL);
+
+ access_okay = (lmc0_reset_ctl & CN6XXX_LMC0_RESET_CTL_DDR3RST_MASK);
+
+ return access_okay ? 0 : 1;
+}
+
+int octeon_wait_for_ddr_init(struct octeon_device *oct, u32 *timeout)
+{
+ int ret = 1;
+ u32 ms;
+
+ if (!timeout)
+ return ret;
+
+ while (*timeout == 0)
+ schedule_timeout_uninterruptible(HZ / 10);
+
+ for (ms = 0; (ret != 0) && ((*timeout == 0) || (ms <= *timeout));
+ ms += HZ / 10) {
+ ret = octeon_mem_access_ok(oct);
+
+ /* wait 100 ms */
+ if (ret)
+ schedule_timeout_uninterruptible(HZ / 10);
+ }
+
+ return ret;
+}
+
+/** Get the octeon id assigned to the octeon device passed as argument.
+ * This function is exported to other modules.
+ * @param dev - octeon device pointer passed as a void *.
+ * @return octeon device id
+ */
+int lio_get_device_id(void *dev)
+{
+ struct octeon_device *octeon_dev = (struct octeon_device *)dev;
+ u32 i;
+
+ for (i = 0; i < MAX_OCTEON_DEVICES; i++)
+ if (octeon_device[i] == octeon_dev)
+ return octeon_dev->octeon_id;
+ return -1;
+}
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.h b/drivers/net/ethernet/cavium/liquidio/octeon_device.h
new file mode 100644
index 000000000000..36e1f85df8c4
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.h
@@ -0,0 +1,649 @@
+/**********************************************************************
+* Author: Cavium, Inc.
+*
+* Contact: support@cavium.com
+* Please include "LiquidIO" in the subject.
+*
+* Copyright (c) 2003-2015 Cavium, Inc.
+*
+* This file 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 file is distributed in the hope that it will be useful, but
+* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+* NONINFRINGEMENT. See the GNU General Public License for more
+* details.
+*
+* This file may also be available under a different license from Cavium.
+* Contact Cavium, Inc. for more information
+**********************************************************************/
+
+/*! \file octeon_device.h
+ * \brief Host Driver: This file defines the octeon device structure.
+ */
+
+#ifndef _OCTEON_DEVICE_H_
+#define _OCTEON_DEVICE_H_
+
+/** PCI VendorId Device Id */
+#define OCTEON_CN68XX_PCIID 0x91177d
+#define OCTEON_CN66XX_PCIID 0x92177d
+
+/** Driver identifies chips by these Ids, created by clubbing together
+ * DeviceId+RevisionId; Where Revision Id is not used to distinguish
+ * between chips, a value of 0 is used for revision id.
+ */
+#define OCTEON_CN68XX 0x0091
+#define OCTEON_CN66XX 0x0092
+
+/** Endian-swap modes supported by Octeon. */
+enum octeon_pci_swap_mode {
+ OCTEON_PCI_PASSTHROUGH = 0,
+ OCTEON_PCI_64BIT_SWAP = 1,
+ OCTEON_PCI_32BIT_BYTE_SWAP = 2,
+ OCTEON_PCI_32BIT_LW_SWAP = 3
+};
+
+/*--------------- PCI BAR1 index registers -------------*/
+
+/* BAR1 Mask */
+#define PCI_BAR1_ENABLE_CA 1
+#define PCI_BAR1_ENDIAN_MODE OCTEON_PCI_64BIT_SWAP
+#define PCI_BAR1_ENTRY_VALID 1
+#define PCI_BAR1_MASK ((PCI_BAR1_ENABLE_CA << 3) \
+ | (PCI_BAR1_ENDIAN_MODE << 1) \
+ | PCI_BAR1_ENTRY_VALID)
+
+/** Octeon Device state.
+ * Each octeon device goes through each of these states
+ * as it is initialized.
+ */
+#define OCT_DEV_BEGIN_STATE 0x0
+#define OCT_DEV_PCI_MAP_DONE 0x1
+#define OCT_DEV_DISPATCH_INIT_DONE 0x2
+#define OCT_DEV_INSTR_QUEUE_INIT_DONE 0x3
+#define OCT_DEV_SC_BUFF_POOL_INIT_DONE 0x4
+#define OCT_DEV_RESP_LIST_INIT_DONE 0x5
+#define OCT_DEV_DROQ_INIT_DONE 0x6
+#define OCT_DEV_IO_QUEUES_DONE 0x7
+#define OCT_DEV_CONSOLE_INIT_DONE 0x8
+#define OCT_DEV_HOST_OK 0x9
+#define OCT_DEV_CORE_OK 0xa
+#define OCT_DEV_RUNNING 0xb
+#define OCT_DEV_IN_RESET 0xc
+#define OCT_DEV_STATE_INVALID 0xd
+
+#define OCT_DEV_STATES OCT_DEV_STATE_INVALID
+
+/** Octeon Device interrupts
+ * These interrupt bits are set in int_status filed of
+ * octeon_device structure
+ */
+#define OCT_DEV_INTR_DMA0_FORCE 0x01
+#define OCT_DEV_INTR_DMA1_FORCE 0x02
+#define OCT_DEV_INTR_PKT_DATA 0x04
+
+#define LIO_RESET_SECS (3)
+
+/*---------------------------DISPATCH LIST-------------------------------*/
+
+/** The dispatch list entry.
+ * The driver keeps a record of functions registered for each
+ * response header opcode in this structure. Since the opcode is
+ * hashed to index into the driver's list, more than one opcode
+ * can hash to the same entry, in which case the list field points
+ * to a linked list with the other entries.
+ */
+struct octeon_dispatch {
+ /** List head for this entry */
+ struct list_head list;
+
+ /** The opcode for which the dispatch function & arg should be used */
+ u16 opcode;
+
+ /** The function to be called for a packet received by the driver */
+ octeon_dispatch_fn_t dispatch_fn;
+
+ /* The application specified argument to be passed to the above
+ * function along with the received packet
+ */
+ void *arg;
+};
+
+/** The dispatch list structure. */
+struct octeon_dispatch_list {
+ /** access to dispatch list must be atomic */
+ spinlock_t lock;
+
+ /** Count of dispatch functions currently registered */
+ u32 count;
+
+ /** The list of dispatch functions */
+ struct octeon_dispatch *dlist;
+};
+
+/*----------------------- THE OCTEON DEVICE ---------------------------*/
+
+#define OCT_MEM_REGIONS 3
+/** PCI address space mapping information.
+ * Each of the 3 address spaces given by BAR0, BAR2 and BAR4 of
+ * Octeon gets mapped to different physical address spaces in
+ * the kernel.
+ */
+struct octeon_mmio {
+ /** PCI address to which the BAR is mapped. */
+ u64 start;
+
+ /** Length of this PCI address space. */
+ u32 len;
+
+ /** Length that has been mapped to phys. address space. */
+ u32 mapped_len;
+
+ /** The physical address to which the PCI address space is mapped. */
+ u8 __iomem *hw_addr;
+
+ /** Flag indicating the mapping was successful. */
+ u32 done;
+};
+
+#define MAX_OCTEON_MAPS 32
+
+struct octeon_io_enable {
+ u32 iq;
+ u32 oq;
+ u32 iq64B;
+};
+
+struct octeon_reg_list {
+ u32 __iomem *pci_win_wr_addr_hi;
+ u32 __iomem *pci_win_wr_addr_lo;
+ u64 __iomem *pci_win_wr_addr;
+
+ u32 __iomem *pci_win_rd_addr_hi;
+ u32 __iomem *pci_win_rd_addr_lo;
+ u64 __iomem *pci_win_rd_addr;
+
+ u32 __iomem *pci_win_wr_data_hi;
+ u32 __iomem *pci_win_wr_data_lo;
+ u64 __iomem *pci_win_wr_data;
+
+ u32 __iomem *pci_win_rd_data_hi;
+ u32 __iomem *pci_win_rd_data_lo;
+ u64 __iomem *pci_win_rd_data;
+};
+
+#define OCTEON_CONSOLE_MAX_READ_BYTES 512
+struct octeon_console {
+ u32 active;
+ u32 waiting;
+ u64 addr;
+ u32 buffer_size;
+ u64 input_base_addr;
+ u64 output_base_addr;
+ char leftover[OCTEON_CONSOLE_MAX_READ_BYTES];
+};
+
+struct octeon_board_info {
+ char name[OCT_BOARD_NAME];
+ char serial_number[OCT_SERIAL_LEN];
+ u64 major;
+ u64 minor;
+};
+
+struct octeon_fn_list {
+ void (*setup_iq_regs)(struct octeon_device *, u32);
+ void (*setup_oq_regs)(struct octeon_device *, u32);
+
+ irqreturn_t (*process_interrupt_regs)(void *);
+ int (*soft_reset)(struct octeon_device *);
+ int (*setup_device_regs)(struct octeon_device *);
+ void (*reinit_regs)(struct octeon_device *);
+ void (*bar1_idx_setup)(struct octeon_device *, u64, u32, int);
+ void (*bar1_idx_write)(struct octeon_device *, u32, u32);
+ u32 (*bar1_idx_read)(struct octeon_device *, u32);
+ u32 (*update_iq_read_idx)(struct octeon_device *,
+ struct octeon_instr_queue *);
+
+ void (*enable_oq_pkt_time_intr)(struct octeon_device *, u32);
+ void (*disable_oq_pkt_time_intr)(struct octeon_device *, u32);
+
+ void (*enable_interrupt)(void *);
+ void (*disable_interrupt)(void *);
+
+ void (*enable_io_queues)(struct octeon_device *);
+ void (*disable_io_queues)(struct octeon_device *);
+};
+
+/* Must be multiple of 8, changing breaks ABI */
+#define CVMX_BOOTMEM_NAME_LEN 128
+
+/* Structure for named memory blocks
+ * Number of descriptors
+ * available can be changed without affecting compatiblity,
+ * but name length changes require a bump in the bootmem
+ * descriptor version
+ * Note: This structure must be naturally 64 bit aligned, as a single
+ * memory image will be used by both 32 and 64 bit programs.
+ */
+struct cvmx_bootmem_named_block_desc {
+ /** Base address of named block */
+ u64 base_addr;
+
+ /** Size actually allocated for named block */
+ u64 size;
+
+ /** name of named block */
+ char name[CVMX_BOOTMEM_NAME_LEN];
+};
+
+struct oct_fw_info {
+ u32 max_nic_ports; /** max nic ports for the device */
+ u32 num_gmx_ports; /** num gmx ports */
+ u64 app_cap_flags; /** firmware cap flags */
+
+ /** The core application is running in this mode.
+ * See octeon-drv-opcodes.h for values.
+ */
+ u32 app_mode;
+ char liquidio_firmware_version[32];
+};
+
+/* wrappers around work structs */
+struct cavium_wk {
+ struct delayed_work work;
+ void *ctxptr;
+ size_t ctxul;
+};
+
+struct cavium_wq {
+ struct workqueue_struct *wq;
+ struct cavium_wk wk;
+};
+
+struct octdev_props {
+ /* Each interface in the Octeon device has a network
+ * device pointer (used for OS specific calls).
+ */
+ struct net_device *netdev;
+};
+
+/** The Octeon device.
+ * Each Octeon device has this structure to represent all its
+ * components.
+ */
+struct octeon_device {
+ /** Lock for PCI window configuration accesses */
+ spinlock_t pci_win_lock;
+
+ /** Lock for memory accesses */
+ spinlock_t mem_access_lock;
+
+ /** PCI device pointer */
+ struct pci_dev *pci_dev;
+
+ /** Chip specific information. */
+ void *chip;
+
+ /** Number of interfaces detected in this octeon device. */
+ u32 ifcount;
+
+ struct octdev_props props[MAX_OCTEON_LINKS];
+
+ /** Octeon Chip type. */
+ u16 chip_id;
+ u16 rev_id;
+
+ /** This device's id - set by the driver. */
+ u32 octeon_id;
+
+ /** This device's PCIe port used for traffic. */
+ u16 pcie_port;
+
+ u16 flags;
+#define LIO_FLAG_MSI_ENABLED (u32)(1 << 1)
+#define LIO_FLAG_MSIX_ENABLED (u32)(1 << 2)
+
+ /** The state of this device */
+ atomic_t status;
+
+ /** memory mapped io range */
+ struct octeon_mmio mmio[OCT_MEM_REGIONS];
+
+ struct octeon_reg_list reg_list;
+
+ struct octeon_fn_list fn_list;
+
+ struct octeon_board_info boardinfo;
+
+ u32 num_iqs;
+
+ /* The pool containing pre allocated buffers used for soft commands */
+ struct octeon_sc_buffer_pool sc_buf_pool;
+
+ /** The input instruction queues */
+ struct octeon_instr_queue *instr_queue[MAX_OCTEON_INSTR_QUEUES];
+
+ /** The doubly-linked list of instruction response */
+ struct octeon_response_list response_list[MAX_RESPONSE_LISTS];
+
+ u32 num_oqs;
+
+ /** The DROQ output queues */
+ struct octeon_droq *droq[MAX_OCTEON_OUTPUT_QUEUES];
+
+ struct octeon_io_enable io_qmask;
+
+ /** List of dispatch functions */
+ struct octeon_dispatch_list dispatch;
+
+ /* Interrupt Moderation */
+ struct oct_intrmod_cfg intrmod;
+
+ u32 int_status;
+
+ u64 droq_intr;
+
+ /** Physical location of the cvmx_bootmem_desc_t in octeon memory */
+ u64 bootmem_desc_addr;
+
+ /** Placeholder memory for named blocks.
+ * Assumes single-threaded access
+ */
+ struct cvmx_bootmem_named_block_desc bootmem_named_block_desc;
+
+ /** Address of consoles descriptor */
+ u64 console_desc_addr;
+
+ /** Number of consoles available. 0 means they are inaccessible */
+ u32 num_consoles;
+
+ /* Console caches */
+ struct octeon_console console[MAX_OCTEON_MAPS];
+
+ /* Coprocessor clock rate. */
+ u64 coproc_clock_rate;
+
+ /** The core application is running in this mode. See liquidio_common.h
+ * for values.
+ */
+ u32 app_mode;
+
+ struct oct_fw_info fw_info;
+
+ /** The name given to this device. */
+ char device_name[32];
+
+ /** Application Context */
+ void *app_ctx;
+
+ struct cavium_wq dma_comp_wq;
+
+ struct cavium_wq check_db_wq[MAX_OCTEON_INSTR_QUEUES];
+
+ struct cavium_wk nic_poll_work;
+
+ struct cavium_wk console_poll_work[MAX_OCTEON_MAPS];
+
+ void *priv;
+};
+
+#define OCTEON_CN6XXX(oct) ((oct->chip_id == OCTEON_CN66XX) || \
+ (oct->chip_id == OCTEON_CN68XX))
+#define CHIP_FIELD(oct, TYPE, field) \
+ (((struct octeon_ ## TYPE *)(oct->chip))->field)
+
+struct oct_intrmod_cmd {
+ struct octeon_device *oct_dev;
+ struct octeon_soft_command *sc;
+ struct oct_intrmod_cfg *cfg;
+};
+
+/*------------------ Function Prototypes ----------------------*/
+
+/** Initialize device list memory */
+void octeon_init_device_list(int conf_type);
+
+/** Free memory for Input and Output queue structures for a octeon device */
+void octeon_free_device_mem(struct octeon_device *);
+
+/* Look up a free entry in the octeon_device table and allocate resources
+ * for the octeon_device structure for an octeon device. Called at init
+ * time.
+ */
+struct octeon_device *octeon_allocate_device(u32 pci_id,
+ u32 priv_size);
+
+/** Initialize the driver's dispatch list which is a mix of a hash table
+ * and a linked list. This is done at driver load time.
+ * @param octeon_dev - pointer to the octeon device structure.
+ * @return 0 on success, else -ve error value
+ */
+int octeon_init_dispatch_list(struct octeon_device *octeon_dev);
+
+/** Delete the driver's dispatch list and all registered entries.
+ * This is done at driver unload time.
+ * @param octeon_dev - pointer to the octeon device structure.
+ */
+void octeon_delete_dispatch_list(struct octeon_device *octeon_dev);
+
+/** Initialize the core device fields with the info returned by the FW.
+ * @param recv_info - Receive info structure
+ * @param buf - Receive buffer
+ */
+int octeon_core_drv_init(struct octeon_recv_info *recv_info, void *buf);
+
+/** Gets the dispatch function registered to receive packets with a
+ * given opcode/subcode.
+ * @param octeon_dev - the octeon device pointer.
+ * @param opcode - the opcode for which the dispatch function
+ * is to checked.
+ * @param subcode - the subcode for which the dispatch function
+ * is to checked.
+ *
+ * @return Success: octeon_dispatch_fn_t (dispatch function pointer)
+ * @return Failure: NULL
+ *
+ * Looks up the dispatch list to get the dispatch function for a
+ * given opcode.
+ */
+octeon_dispatch_fn_t
+octeon_get_dispatch(struct octeon_device *octeon_dev, u16 opcode,
+ u16 subcode);
+
+/** Get the octeon device pointer.
+ * @param octeon_id - The id for which the octeon device pointer is required.
+ * @return Success: Octeon device pointer.
+ * @return Failure: NULL.
+ */
+struct octeon_device *lio_get_device(u32 octeon_id);
+
+/** Get the octeon id assigned to the octeon device passed as argument.
+ * This function is exported to other modules.
+ * @param dev - octeon device pointer passed as a void *.
+ * @return octeon device id
+ */
+int lio_get_device_id(void *dev);
+
+static inline u16 OCTEON_MAJOR_REV(struct octeon_device *oct)
+{
+ u16 rev = (oct->rev_id & 0xC) >> 2;
+
+ return (rev == 0) ? 1 : rev;
+}
+
+static inline u16 OCTEON_MINOR_REV(struct octeon_device *oct)
+{
+ return oct->rev_id & 0x3;
+}
+
+/** Read windowed register.
+ * @param oct - pointer to the Octeon device.
+ * @param addr - Address of the register to read.
+ *
+ * This routine is called to read from the indirectly accessed
+ * Octeon registers that are visible through a PCI BAR0 mapped window
+ * register.
+ * @return - 64 bit value read from the register.
+ */
+
+u64 lio_pci_readq(struct octeon_device *oct, u64 addr);
+
+/** Write windowed register.
+ * @param oct - pointer to the Octeon device.
+ * @param val - Value to write
+ * @param addr - Address of the register to write
+ *
+ * This routine is called to write to the indirectly accessed
+ * Octeon registers that are visible through a PCI BAR0 mapped window
+ * register.
+ * @return Nothing.
+ */
+void lio_pci_writeq(struct octeon_device *oct, u64 val, u64 addr);
+
+/* Routines for reading and writing CSRs */
+#define octeon_write_csr(oct_dev, reg_off, value) \
+ writel(value, oct_dev->mmio[0].hw_addr + reg_off)
+
+#define octeon_write_csr64(oct_dev, reg_off, val64) \
+ writeq(val64, oct_dev->mmio[0].hw_addr + reg_off)
+
+#define octeon_read_csr(oct_dev, reg_off) \
+ readl(oct_dev->mmio[0].hw_addr + reg_off)
+
+#define octeon_read_csr64(oct_dev, reg_off) \
+ readq(oct_dev->mmio[0].hw_addr + reg_off)
+
+/**
+ * Checks if memory access is okay
+ *
+ * @param oct which octeon to send to
+ * @return Zero on success, negative on failure.
+ */
+int octeon_mem_access_ok(struct octeon_device *oct);
+
+/**
+ * Waits for DDR initialization.
+ *
+ * @param oct which octeon to send to
+ * @param timeout_in_ms pointer to how long to wait until DDR is initialized
+ * in ms.
+ * If contents are 0, it waits until contents are non-zero
+ * before starting to check.
+ * @return Zero on success, negative on failure.
+ */
+int octeon_wait_for_ddr_init(struct octeon_device *oct,
+ u32 *timeout_in_ms);
+
+/**
+ * Wait for u-boot to boot and be waiting for a command.
+ *
+ * @param wait_time_hundredths
+ * Maximum time to wait
+ *
+ * @return Zero on success, negative on failure.
+ */
+int octeon_wait_for_bootloader(struct octeon_device *oct,
+ u32 wait_time_hundredths);
+
+/**
+ * Initialize console access
+ *
+ * @param oct which octeon initialize
+ * @return Zero on success, negative on failure.
+ */
+int octeon_init_consoles(struct octeon_device *oct);
+
+/**
+ * Adds access to a console to the device.
+ *
+ * @param oct which octeon to add to
+ * @param console_num which console
+ * @return Zero on success, negative on failure.
+ */
+int octeon_add_console(struct octeon_device *oct, u32 console_num);
+
+/** write or read from a console */
+int octeon_console_write(struct octeon_device *oct, u32 console_num,
+ char *buffer, u32 write_request_size, u32 flags);
+int octeon_console_write_avail(struct octeon_device *oct, u32 console_num);
+int octeon_console_read(struct octeon_device *oct, u32 console_num,
+ char *buffer, u32 buf_size, u32 flags);
+int octeon_console_read_avail(struct octeon_device *oct, u32 console_num);
+
+/** Removes all attached consoles. */
+void octeon_remove_consoles(struct octeon_device *oct);
+
+/**
+ * Send a string to u-boot on console 0 as a command.
+ *
+ * @param oct which octeon to send to
+ * @param cmd_str String to send
+ * @param wait_hundredths Time to wait for u-boot to accept the command.
+ *
+ * @return Zero on success, negative on failure.
+ */
+int octeon_console_send_cmd(struct octeon_device *oct, char *cmd_str,
+ u32 wait_hundredths);
+
+/** Parses, validates, and downloads firmware, then boots associated cores.
+ * @param oct which octeon to download firmware to
+ * @param data - The complete firmware file image
+ * @param size - The size of the data
+ *
+ * @return 0 if success.
+ * -EINVAL if file is incompatible or badly formatted.
+ * -ENODEV if no handler was found for the application type or an
+ * invalid octeon id was passed.
+ */
+int octeon_download_firmware(struct octeon_device *oct, const u8 *data,
+ size_t size);
+
+char *lio_get_state_string(atomic_t *state_ptr);
+
+/** Sets up instruction queues for the device
+ * @param oct which octeon to setup
+ *
+ * @return 0 if success. 1 if fails
+ */
+int octeon_setup_instr_queues(struct octeon_device *oct);
+
+/** Sets up output queues for the device
+ * @param oct which octeon to setup
+ *
+ * @return 0 if success. 1 if fails
+ */
+int octeon_setup_output_queues(struct octeon_device *oct);
+
+int octeon_get_tx_qsize(struct octeon_device *oct, u32 q_no);
+
+int octeon_get_rx_qsize(struct octeon_device *oct, u32 q_no);
+
+/** Turns off the input and output queues for the device
+ * @param oct which octeon to disable
+ */
+void octeon_set_io_queues_off(struct octeon_device *oct);
+
+/** Turns on or off the given output queue for the device
+ * @param oct which octeon to change
+ * @param q_no which queue
+ * @param enable 1 to enable, 0 to disable
+ */
+void octeon_set_droq_pkt_op(struct octeon_device *oct, u32 q_no, u32 enable);
+
+/** Retrieve the config for the device
+ * @param oct which octeon
+ * @param card_type type of card
+ *
+ * @returns pointer to configuration
+ */
+void *oct_get_config_info(struct octeon_device *oct, u16 card_type);
+
+/** Gets the octeon device configuration
+ * @return - pointer to the octeon configuration struture
+ */
+struct octeon_config *octeon_get_conf(struct octeon_device *oct);
+
+#endif
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c
new file mode 100644
index 000000000000..94b502a0cf33
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c
@@ -0,0 +1,989 @@
+/**********************************************************************
+* Author: Cavium, Inc.
+*
+* Contact: support@cavium.com
+* Please include "LiquidIO" in the subject.
+*
+* Copyright (c) 2003-2015 Cavium, Inc.
+*
+* This file 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 file is distributed in the hope that it will be useful, but
+* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+* NONINFRINGEMENT. See the GNU General Public License for more
+* details.
+*
+* This file may also be available under a different license from Cavium.
+* Contact Cavium, Inc. for more information
+**********************************************************************/
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include "octeon_config.h"
+#include "liquidio_common.h"
+#include "octeon_droq.h"
+#include "octeon_iq.h"
+#include "response_manager.h"
+#include "octeon_device.h"
+#include "octeon_nic.h"
+#include "octeon_main.h"
+#include "octeon_network.h"
+#include "cn66xx_regs.h"
+#include "cn66xx_device.h"
+#include "cn68xx_regs.h"
+#include "cn68xx_device.h"
+#include "liquidio_image.h"
+#include "octeon_mem_ops.h"
+
+/* #define CAVIUM_ONLY_PERF_MODE */
+
+#define CVM_MIN(d1, d2) (((d1) < (d2)) ? (d1) : (d2))
+#define CVM_MAX(d1, d2) (((d1) > (d2)) ? (d1) : (d2))
+
+struct niclist {
+ struct list_head list;
+ void *ptr;
+};
+
+struct __dispatch {
+ struct list_head list;
+ struct octeon_recv_info *rinfo;
+ octeon_dispatch_fn_t disp_fn;
+};
+
+/** Get the argument that the user set when registering dispatch
+ * function for a given opcode/subcode.
+ * @param octeon_dev - the octeon device pointer.
+ * @param opcode - the opcode for which the dispatch argument
+ * is to be checked.
+ * @param subcode - the subcode for which the dispatch argument
+ * is to be checked.
+ * @return Success: void * (argument to the dispatch function)
+ * @return Failure: NULL
+ *
+ */
+static inline void *octeon_get_dispatch_arg(struct octeon_device *octeon_dev,
+ u16 opcode, u16 subcode)
+{
+ int idx;
+ struct list_head *dispatch;
+ void *fn_arg = NULL;
+ u16 combined_opcode = OPCODE_SUBCODE(opcode, subcode);
+
+ idx = combined_opcode & OCTEON_OPCODE_MASK;
+
+ spin_lock_bh(&octeon_dev->dispatch.lock);
+
+ if (octeon_dev->dispatch.count == 0) {
+ spin_unlock_bh(&octeon_dev->dispatch.lock);
+ return NULL;
+ }
+
+ if (octeon_dev->dispatch.dlist[idx].opcode == combined_opcode) {
+ fn_arg = octeon_dev->dispatch.dlist[idx].arg;
+ } else {
+ list_for_each(dispatch,
+ &octeon_dev->dispatch.dlist[idx].list) {
+ if (((struct octeon_dispatch *)dispatch)->opcode ==
+ combined_opcode) {
+ fn_arg = ((struct octeon_dispatch *)
+ dispatch)->arg;
+ break;
+ }
+ }
+ }
+
+ spin_unlock_bh(&octeon_dev->dispatch.lock);
+ return fn_arg;
+}
+
+u32 octeon_droq_check_hw_for_pkts(struct octeon_device *oct,
+ struct octeon_droq *droq)
+{
+ u32 pkt_count = 0;
+
+ pkt_count = readl(droq->pkts_sent_reg);
+ if (pkt_count) {
+ atomic_add(pkt_count, &droq->pkts_pending);
+ writel(pkt_count, droq->pkts_sent_reg);
+ }
+
+ return pkt_count;
+}
+
+static void octeon_droq_compute_max_packet_bufs(struct octeon_droq *droq)
+{
+ u32 count = 0;
+
+ /* max_empty_descs is the max. no. of descs that can have no buffers.
+ * If the empty desc count goes beyond this value, we cannot safely
+ * read in a 64K packet sent by Octeon
+ * (64K is max pkt size from Octeon)
+ */
+ droq->max_empty_descs = 0;
+
+ do {
+ droq->max_empty_descs++;
+ count += droq->buffer_size;
+ } while (count < (64 * 1024));
+
+ droq->max_empty_descs = droq->max_count - droq->max_empty_descs;
+}
+
+static void octeon_droq_reset_indices(struct octeon_droq *droq)
+{
+ droq->read_idx = 0;
+ droq->write_idx = 0;
+ droq->refill_idx = 0;
+ droq->refill_count = 0;
+ atomic_set(&droq->pkts_pending, 0);
+}
+
+static void
+octeon_droq_destroy_ring_buffers(struct octeon_device *oct,
+ struct octeon_droq *droq)
+{
+ u32 i;
+
+ for (i = 0; i < droq->max_count; i++) {
+ if (droq->recv_buf_list[i].buffer) {
+ if (droq->desc_ring) {
+ lio_unmap_ring_info(oct->pci_dev,
+ (u64)droq->
+ desc_ring[i].info_ptr,
+ OCT_DROQ_INFO_SIZE);
+ lio_unmap_ring(oct->pci_dev,
+ (u64)droq->desc_ring[i].
+ buffer_ptr,
+ droq->buffer_size);
+ }
+ recv_buffer_free(droq->recv_buf_list[i].buffer);
+ droq->recv_buf_list[i].buffer = NULL;
+ }
+ }
+
+ octeon_droq_reset_indices(droq);
+}
+
+static int
+octeon_droq_setup_ring_buffers(struct octeon_device *oct,
+ struct octeon_droq *droq)
+{
+ u32 i;
+ void *buf;
+ struct octeon_droq_desc *desc_ring = droq->desc_ring;
+
+ for (i = 0; i < droq->max_count; i++) {
+ buf = recv_buffer_alloc(oct, droq->q_no, droq->buffer_size);
+
+ if (!buf) {
+ dev_err(&oct->pci_dev->dev, "%s buffer alloc failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ droq->recv_buf_list[i].buffer = buf;
+ droq->recv_buf_list[i].data = get_rbd(buf);
+
+ droq->info_list[i].length = 0;
+
+ /* map ring buffers into memory */
+ desc_ring[i].info_ptr = lio_map_ring_info(droq, i);
+ desc_ring[i].buffer_ptr =
+ lio_map_ring(oct->pci_dev,
+ droq->recv_buf_list[i].buffer,
+ droq->buffer_size);
+ }
+
+ octeon_droq_reset_indices(droq);
+
+ octeon_droq_compute_max_packet_bufs(droq);
+
+ return 0;
+}
+
+int octeon_delete_droq(struct octeon_device *oct, u32 q_no)
+{
+ struct octeon_droq *droq = oct->droq[q_no];
+
+ dev_dbg(&oct->pci_dev->dev, "%s[%d]\n", __func__, q_no);
+
+ octeon_droq_destroy_ring_buffers(oct, droq);
+
+ if (droq->recv_buf_list)
+ vfree(droq->recv_buf_list);
+
+ if (droq->info_base_addr)
+ cnnic_free_aligned_dma(oct->pci_dev, droq->info_list,
+ droq->info_alloc_size,
+ droq->info_base_addr,
+ droq->info_list_dma);
+
+ if (droq->desc_ring)
+ lio_dma_free(oct, (droq->max_count * OCT_DROQ_DESC_SIZE),
+ droq->desc_ring, droq->desc_ring_dma);
+
+ memset(droq, 0, OCT_DROQ_SIZE);
+
+ return 0;
+}
+
+int octeon_init_droq(struct octeon_device *oct,
+ u32 q_no,
+ u32 num_descs,
+ u32 desc_size,
+ void *app_ctx)
+{
+ struct octeon_droq *droq;
+ u32 desc_ring_size = 0, c_num_descs = 0, c_buf_size = 0;
+ u32 c_pkts_per_intr = 0, c_refill_threshold = 0;
+
+ dev_dbg(&oct->pci_dev->dev, "%s[%d]\n", __func__, q_no);
+
+ droq = oct->droq[q_no];
+ memset(droq, 0, OCT_DROQ_SIZE);
+
+ droq->oct_dev = oct;
+ droq->q_no = q_no;
+ if (app_ctx)
+ droq->app_ctx = app_ctx;
+ else
+ droq->app_ctx = (void *)(size_t)q_no;
+
+ c_num_descs = num_descs;
+ c_buf_size = desc_size;
+ if (OCTEON_CN6XXX(oct)) {
+ struct octeon_config *conf6x = CHIP_FIELD(oct, cn6xxx, conf);
+
+ c_pkts_per_intr = (u32)CFG_GET_OQ_PKTS_PER_INTR(conf6x);
+ c_refill_threshold = (u32)CFG_GET_OQ_REFILL_THRESHOLD(conf6x);
+ }
+
+ droq->max_count = c_num_descs;
+ droq->buffer_size = c_buf_size;
+
+ desc_ring_size = droq->max_count * OCT_DROQ_DESC_SIZE;
+ droq->desc_ring = lio_dma_alloc(oct, desc_ring_size,
+ (dma_addr_t *)&droq->desc_ring_dma);
+
+ if (!droq->desc_ring) {
+ dev_err(&oct->pci_dev->dev,
+ "Output queue %d ring alloc failed\n", q_no);
+ return 1;
+ }
+
+ dev_dbg(&oct->pci_dev->dev, "droq[%d]: desc_ring: virt: 0x%p, dma: %lx\n",
+ q_no, droq->desc_ring, droq->desc_ring_dma);
+ dev_dbg(&oct->pci_dev->dev, "droq[%d]: num_desc: %d\n", q_no,
+ droq->max_count);
+
+ droq->info_list =
+ cnnic_alloc_aligned_dma(oct->pci_dev,
+ (droq->max_count * OCT_DROQ_INFO_SIZE),
+ &droq->info_alloc_size,
+ &droq->info_base_addr,
+ &droq->info_list_dma);
+
+ if (!droq->info_list) {
+ dev_err(&oct->pci_dev->dev, "Cannot allocate memory for info list.\n");
+ lio_dma_free(oct, (droq->max_count * OCT_DROQ_DESC_SIZE),
+ droq->desc_ring, droq->desc_ring_dma);
+ return 1;
+ }
+
+ droq->recv_buf_list = (struct octeon_recv_buffer *)
+ vmalloc(droq->max_count *
+ OCT_DROQ_RECVBUF_SIZE);
+ if (!droq->recv_buf_list) {
+ dev_err(&oct->pci_dev->dev, "Output queue recv buf list alloc failed\n");
+ goto init_droq_fail;
+ }
+
+ if (octeon_droq_setup_ring_buffers(oct, droq))
+ goto init_droq_fail;
+
+ droq->pkts_per_intr = c_pkts_per_intr;
+ droq->refill_threshold = c_refill_threshold;
+
+ dev_dbg(&oct->pci_dev->dev, "DROQ INIT: max_empty_descs: %d\n",
+ droq->max_empty_descs);
+
+ spin_lock_init(&droq->lock);
+
+ INIT_LIST_HEAD(&droq->dispatch_list);
+
+ /* For 56xx Pass1, this function won't be called, so no checks. */
+ oct->fn_list.setup_oq_regs(oct, q_no);
+
+ oct->io_qmask.oq |= (1 << q_no);
+
+ return 0;
+
+init_droq_fail:
+ octeon_delete_droq(oct, q_no);
+ return 1;
+}
+
+/* octeon_create_recv_info
+ * Parameters:
+ * octeon_dev - pointer to the octeon device structure
+ * droq - droq in which the packet arrived.
+ * buf_cnt - no. of buffers used by the packet.
+ * idx - index in the descriptor for the first buffer in the packet.
+ * Description:
+ * Allocates a recv_info_t and copies the buffer addresses for packet data
+ * into the recv_pkt space which starts at an 8B offset from recv_info_t.
+ * Flags the descriptors for refill later. If available descriptors go
+ * below the threshold to receive a 64K pkt, new buffers are first allocated
+ * before the recv_pkt_t is created.
+ * This routine will be called in interrupt context.
+ * Returns:
+ * Success: Pointer to recv_info_t
+ * Failure: NULL.
+ * Locks:
+ * The droq->lock is held when this routine is called.
+ */
+static inline struct octeon_recv_info *octeon_create_recv_info(
+ struct octeon_device *octeon_dev,
+ struct octeon_droq *droq,
+ u32 buf_cnt,
+ u32 idx)
+{
+ struct octeon_droq_info *info;
+ struct octeon_recv_pkt *recv_pkt;
+ struct octeon_recv_info *recv_info;
+ u32 i, bytes_left;
+
+ info = &droq->info_list[idx];
+
+ recv_info = octeon_alloc_recv_info(sizeof(struct __dispatch));
+ if (!recv_info)
+ return NULL;
+
+ recv_pkt = recv_info->recv_pkt;
+ recv_pkt->rh = info->rh;
+ recv_pkt->length = (u32)info->length;
+ recv_pkt->buffer_count = (u16)buf_cnt;
+ recv_pkt->octeon_id = (u16)octeon_dev->octeon_id;
+
+ i = 0;
+ bytes_left = (u32)info->length;
+
+ while (buf_cnt) {
+ lio_unmap_ring(octeon_dev->pci_dev,
+ (u64)droq->desc_ring[idx].buffer_ptr,
+ droq->buffer_size);
+
+ recv_pkt->buffer_size[i] =
+ (bytes_left >=
+ droq->buffer_size) ? droq->buffer_size : bytes_left;
+
+ recv_pkt->buffer_ptr[i] = droq->recv_buf_list[idx].buffer;
+ droq->recv_buf_list[idx].buffer = NULL;
+
+ INCR_INDEX_BY1(idx, droq->max_count);
+ bytes_left -= droq->buffer_size;
+ i++;
+ buf_cnt--;
+ }
+
+ return recv_info;
+}
+
+/* If we were not able to refill all buffers, try to move around
+ * the buffers that were not dispatched.
+ */
+static inline u32
+octeon_droq_refill_pullup_descs(struct octeon_droq *droq,
+ struct octeon_droq_desc *desc_ring)
+{
+ u32 desc_refilled = 0;
+
+ u32 refill_index = droq->refill_idx;
+
+ while (refill_index != droq->read_idx) {
+ if (droq->recv_buf_list[refill_index].buffer) {
+ droq->recv_buf_list[droq->refill_idx].buffer =
+ droq->recv_buf_list[refill_index].buffer;
+ droq->recv_buf_list[droq->refill_idx].data =
+ droq->recv_buf_list[refill_index].data;
+ desc_ring[droq->refill_idx].buffer_ptr =
+ desc_ring[refill_index].buffer_ptr;
+ droq->recv_buf_list[refill_index].buffer = NULL;
+ desc_ring[refill_index].buffer_ptr = 0;
+ do {
+ INCR_INDEX_BY1(droq->refill_idx,
+ droq->max_count);
+ desc_refilled++;
+ droq->refill_count--;
+ } while (droq->recv_buf_list[droq->refill_idx].
+ buffer);
+ }
+ INCR_INDEX_BY1(refill_index, droq->max_count);
+ } /* while */
+ return desc_refilled;
+}
+
+/* octeon_droq_refill
+ * Parameters:
+ * droq - droq in which descriptors require new buffers.
+ * Description:
+ * Called during normal DROQ processing in interrupt mode or by the poll
+ * thread to refill the descriptors from which buffers were dispatched
+ * to upper layers. Attempts to allocate new buffers. If that fails, moves
+ * up buffers (that were not dispatched) to form a contiguous ring.
+ * Returns:
+ * No of descriptors refilled.
+ * Locks:
+ * This routine is called with droq->lock held.
+ */
+static u32
+octeon_droq_refill(struct octeon_device *octeon_dev, struct octeon_droq *droq)
+{
+ struct octeon_droq_desc *desc_ring;
+ void *buf = NULL;
+ u8 *data;
+ u32 desc_refilled = 0;
+
+ desc_ring = droq->desc_ring;
+
+ while (droq->refill_count && (desc_refilled < droq->max_count)) {
+ /* If a valid buffer exists (happens if there is no dispatch),
+ * reuse
+ * the buffer, else allocate.
+ */
+ if (!droq->recv_buf_list[droq->refill_idx].buffer) {
+ buf = recv_buffer_alloc(octeon_dev, droq->q_no,
+ droq->buffer_size);
+ /* If a buffer could not be allocated, no point in
+ * continuing
+ */
+ if (!buf)
+ break;
+ droq->recv_buf_list[droq->refill_idx].buffer =
+ buf;
+ data = get_rbd(buf);
+ } else {
+ data = get_rbd(droq->recv_buf_list
+ [droq->refill_idx].buffer);
+ }
+
+ droq->recv_buf_list[droq->refill_idx].data = data;
+
+ desc_ring[droq->refill_idx].buffer_ptr =
+ lio_map_ring(octeon_dev->pci_dev,
+ droq->recv_buf_list[droq->
+ refill_idx].buffer,
+ droq->buffer_size);
+
+ /* Reset any previous values in the length field. */
+ droq->info_list[droq->refill_idx].length = 0;
+
+ INCR_INDEX_BY1(droq->refill_idx, droq->max_count);
+ desc_refilled++;
+ droq->refill_count--;
+ }
+
+ if (droq->refill_count)
+ desc_refilled +=
+ octeon_droq_refill_pullup_descs(droq, desc_ring);
+
+ /* if droq->refill_count
+ * The refill count would not change in pass two. We only moved buffers
+ * to close the gap in the ring, but we would still have the same no. of
+ * buffers to refill.
+ */
+ return desc_refilled;
+}
+
+static inline u32
+octeon_droq_get_bufcount(u32 buf_size, u32 total_len)
+{
+ u32 buf_cnt = 0;
+
+ while (total_len > (buf_size * buf_cnt))
+ buf_cnt++;
+ return buf_cnt;
+}
+
+static int
+octeon_droq_dispatch_pkt(struct octeon_device *oct,
+ struct octeon_droq *droq,
+ union octeon_rh *rh,
+ struct octeon_droq_info *info)
+{
+ u32 cnt;
+ octeon_dispatch_fn_t disp_fn;
+ struct octeon_recv_info *rinfo;
+
+ cnt = octeon_droq_get_bufcount(droq->buffer_size, (u32)info->length);
+
+ disp_fn = octeon_get_dispatch(oct, (u16)rh->r.opcode,
+ (u16)rh->r.subcode);
+ if (disp_fn) {
+ rinfo = octeon_create_recv_info(oct, droq, cnt, droq->read_idx);
+ if (rinfo) {
+ struct __dispatch *rdisp = rinfo->rsvd;
+
+ rdisp->rinfo = rinfo;
+ rdisp->disp_fn = disp_fn;
+ rinfo->recv_pkt->rh = *rh;
+ list_add_tail(&rdisp->list,
+ &droq->dispatch_list);
+ } else {
+ droq->stats.dropped_nomem++;
+ }
+ } else {
+ dev_err(&oct->pci_dev->dev, "DROQ: No dispatch function\n");
+ droq->stats.dropped_nodispatch++;
+ } /* else (dispatch_fn ... */
+
+ return cnt;
+}
+
+static inline void octeon_droq_drop_packets(struct octeon_device *oct,
+ struct octeon_droq *droq,
+ u32 cnt)
+{
+ u32 i = 0, buf_cnt;
+ struct octeon_droq_info *info;
+
+ for (i = 0; i < cnt; i++) {
+ info = &droq->info_list[droq->read_idx];
+ octeon_swap_8B_data((u64 *)info, 2);
+
+ if (info->length) {
+ info->length -= OCT_RH_SIZE;
+ droq->stats.bytes_received += info->length;
+ buf_cnt = octeon_droq_get_bufcount(droq->buffer_size,
+ (u32)info->length);
+ } else {
+ dev_err(&oct->pci_dev->dev, "DROQ: In drop: pkt with len 0\n");
+ buf_cnt = 1;
+ }
+
+ INCR_INDEX(droq->read_idx, buf_cnt, droq->max_count);
+ droq->refill_count += buf_cnt;
+ }
+}
+
+static u32
+octeon_droq_fast_process_packets(struct octeon_device *oct,
+ struct octeon_droq *droq,
+ u32 pkts_to_process)
+{
+ struct octeon_droq_info *info;
+ union octeon_rh *rh;
+ u32 pkt, total_len = 0, pkt_count;
+
+ pkt_count = pkts_to_process;
+
+ for (pkt = 0; pkt < pkt_count; pkt++) {
+ u32 pkt_len = 0;
+ struct sk_buff *nicbuf = NULL;
+
+ info = &droq->info_list[droq->read_idx];
+ octeon_swap_8B_data((u64 *)info, 2);
+
+ if (!info->length) {
+ dev_err(&oct->pci_dev->dev,
+ "DROQ[%d] idx: %d len:0, pkt_cnt: %d\n",
+ droq->q_no, droq->read_idx, pkt_count);
+ print_hex_dump_bytes("", DUMP_PREFIX_ADDRESS,
+ (u8 *)info,
+ OCT_DROQ_INFO_SIZE);
+ break;
+ }
+
+ /* Len of resp hdr in included in the received data len. */
+ info->length -= OCT_RH_SIZE;
+ rh = &info->rh;
+
+ total_len += (u32)info->length;
+
+ if (OPCODE_SLOW_PATH(rh)) {
+ u32 buf_cnt;
+
+ buf_cnt = octeon_droq_dispatch_pkt(oct, droq, rh, info);
+ INCR_INDEX(droq->read_idx, buf_cnt, droq->max_count);
+ droq->refill_count += buf_cnt;
+ } else {
+ if (info->length <= droq->buffer_size) {
+ lio_unmap_ring(oct->pci_dev,
+ (u64)droq->desc_ring[
+ droq->read_idx].buffer_ptr,
+ droq->buffer_size);
+ pkt_len = (u32)info->length;
+ nicbuf = droq->recv_buf_list[
+ droq->read_idx].buffer;
+ droq->recv_buf_list[droq->read_idx].buffer =
+ NULL;
+ INCR_INDEX_BY1(droq->read_idx, droq->max_count);
+ skb_put(nicbuf, pkt_len);
+ droq->refill_count++;
+ } else {
+ nicbuf = octeon_fast_packet_alloc(oct, droq,
+ droq->q_no,
+ (u32)
+ info->length);
+ pkt_len = 0;
+ /* nicbuf allocation can fail. We'll handle it
+ * inside the loop.
+ */
+ while (pkt_len < info->length) {
+ int cpy_len;
+
+ cpy_len = ((pkt_len +
+ droq->buffer_size) >
+ info->length) ?
+ ((u32)info->length - pkt_len) :
+ droq->buffer_size;
+
+ if (nicbuf) {
+ lio_unmap_ring(oct->pci_dev,
+ (u64)
+ droq->desc_ring
+ [droq->read_idx].
+ buffer_ptr,
+ droq->
+ buffer_size);
+ octeon_fast_packet_next(droq,
+ nicbuf,
+ cpy_len,
+ droq->
+ read_idx
+ );
+ }
+
+ pkt_len += cpy_len;
+ INCR_INDEX_BY1(droq->read_idx,
+ droq->max_count);
+ droq->refill_count++;
+ }
+ }
+
+ if (nicbuf) {
+ if (droq->ops.fptr)
+ droq->ops.fptr(oct->octeon_id,
+ nicbuf, pkt_len,
+ rh, &droq->napi);
+ else
+ recv_buffer_free(nicbuf);
+ }
+ }
+
+ if (droq->refill_count >= droq->refill_threshold) {
+ int desc_refilled = octeon_droq_refill(oct, droq);
+
+ /* Flush the droq descriptor data to memory to be sure
+ * that when we update the credits the data in memory
+ * is accurate.
+ */
+ wmb();
+ writel((desc_refilled), droq->pkts_credit_reg);
+ /* make sure mmio write completes */
+ mmiowb();
+ }
+
+ } /* for ( each packet )... */
+
+ /* Increment refill_count by the number of buffers processed. */
+ droq->stats.pkts_received += pkt;
+ droq->stats.bytes_received += total_len;
+
+ if ((droq->ops.drop_on_max) && (pkts_to_process - pkt)) {
+ octeon_droq_drop_packets(oct, droq, (pkts_to_process - pkt));
+
+ droq->stats.dropped_toomany += (pkts_to_process - pkt);
+ return pkts_to_process;
+ }
+
+ return pkt;
+}
+
+int
+octeon_droq_process_packets(struct octeon_device *oct,
+ struct octeon_droq *droq,
+ u32 budget)
+{
+ u32 pkt_count = 0, pkts_processed = 0;
+ struct list_head *tmp, *tmp2;
+
+ pkt_count = atomic_read(&droq->pkts_pending);
+ if (!pkt_count)
+ return 0;
+
+ if (pkt_count > budget)
+ pkt_count = budget;
+
+ /* Grab the lock */
+ spin_lock(&droq->lock);
+
+ pkts_processed = octeon_droq_fast_process_packets(oct, droq, pkt_count);
+
+ atomic_sub(pkts_processed, &droq->pkts_pending);
+
+ /* Release the spin lock */
+ spin_unlock(&droq->lock);
+
+ list_for_each_safe(tmp, tmp2, &droq->dispatch_list) {
+ struct __dispatch *rdisp = (struct __dispatch *)tmp;
+
+ list_del(tmp);
+ rdisp->disp_fn(rdisp->rinfo,
+ octeon_get_dispatch_arg
+ (oct,
+ (u16)rdisp->rinfo->recv_pkt->rh.r.opcode,
+ (u16)rdisp->rinfo->recv_pkt->rh.r.subcode));
+ }
+
+ /* If there are packets pending. schedule tasklet again */
+ if (atomic_read(&droq->pkts_pending))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * Utility function to poll for packets. check_hw_for_packets must be
+ * called before calling this routine.
+ */
+
+static int
+octeon_droq_process_poll_pkts(struct octeon_device *oct,
+ struct octeon_droq *droq, u32 budget)
+{
+ struct list_head *tmp, *tmp2;
+ u32 pkts_available = 0, pkts_processed = 0;
+ u32 total_pkts_processed = 0;
+
+ if (budget > droq->max_count)
+ budget = droq->max_count;
+
+ spin_lock(&droq->lock);
+
+ while (total_pkts_processed < budget) {
+ pkts_available =
+ CVM_MIN((budget - total_pkts_processed),
+ (u32)(atomic_read(&droq->pkts_pending)));
+
+ if (pkts_available == 0)
+ break;
+
+ pkts_processed =
+ octeon_droq_fast_process_packets(oct, droq,
+ pkts_available);
+
+ atomic_sub(pkts_processed, &droq->pkts_pending);
+
+ total_pkts_processed += pkts_processed;
+
+ octeon_droq_check_hw_for_pkts(oct, droq);
+ }
+
+ spin_unlock(&droq->lock);
+
+ list_for_each_safe(tmp, tmp2, &droq->dispatch_list) {
+ struct __dispatch *rdisp = (struct __dispatch *)tmp;
+
+ list_del(tmp);
+ rdisp->disp_fn(rdisp->rinfo,
+ octeon_get_dispatch_arg
+ (oct,
+ (u16)rdisp->rinfo->recv_pkt->rh.r.opcode,
+ (u16)rdisp->rinfo->recv_pkt->rh.r.subcode));
+ }
+
+ return total_pkts_processed;
+}
+
+int
+octeon_process_droq_poll_cmd(struct octeon_device *oct, u32 q_no, int cmd,
+ u32 arg)
+{
+ struct octeon_droq *droq;
+ struct octeon_config *oct_cfg = NULL;
+
+ oct_cfg = octeon_get_conf(oct);
+
+ if (!oct_cfg)
+ return -EINVAL;
+
+ if (q_no >= CFG_GET_OQ_MAX_Q(oct_cfg)) {
+ dev_err(&oct->pci_dev->dev, "%s: droq id (%d) exceeds MAX (%d)\n",
+ __func__, q_no, (oct->num_oqs - 1));
+ return -EINVAL;
+ }
+
+ droq = oct->droq[q_no];
+
+ if (cmd == POLL_EVENT_PROCESS_PKTS)
+ return octeon_droq_process_poll_pkts(oct, droq, arg);
+
+ if (cmd == POLL_EVENT_PENDING_PKTS) {
+ u32 pkt_cnt = atomic_read(&droq->pkts_pending);
+
+ return octeon_droq_process_packets(oct, droq, pkt_cnt);
+ }
+
+ if (cmd == POLL_EVENT_ENABLE_INTR) {
+ u32 value;
+ unsigned long flags;
+
+ /* Enable Pkt Interrupt */
+ switch (oct->chip_id) {
+ case OCTEON_CN66XX:
+ case OCTEON_CN68XX: {
+ struct octeon_cn6xxx *cn6xxx =
+ (struct octeon_cn6xxx *)oct->chip;
+ spin_lock_irqsave
+ (&cn6xxx->lock_for_droq_int_enb_reg, flags);
+ value =
+ octeon_read_csr(oct,
+ CN6XXX_SLI_PKT_TIME_INT_ENB);
+ value |= (1 << q_no);
+ octeon_write_csr(oct,
+ CN6XXX_SLI_PKT_TIME_INT_ENB,
+ value);
+ value =
+ octeon_read_csr(oct,
+ CN6XXX_SLI_PKT_CNT_INT_ENB);
+ value |= (1 << q_no);
+ octeon_write_csr(oct,
+ CN6XXX_SLI_PKT_CNT_INT_ENB,
+ value);
+
+ /* don't bother flushing the enables */
+
+ spin_unlock_irqrestore
+ (&cn6xxx->lock_for_droq_int_enb_reg, flags);
+ return 0;
+ }
+ break;
+ }
+
+ return 0;
+ }
+
+ dev_err(&oct->pci_dev->dev, "%s Unknown command: %d\n", __func__, cmd);
+ return -EINVAL;
+}
+
+int octeon_register_droq_ops(struct octeon_device *oct, u32 q_no,
+ struct octeon_droq_ops *ops)
+{
+ struct octeon_droq *droq;
+ unsigned long flags;
+ struct octeon_config *oct_cfg = NULL;
+
+ oct_cfg = octeon_get_conf(oct);
+
+ if (!oct_cfg)
+ return -EINVAL;
+
+ if (!(ops)) {
+ dev_err(&oct->pci_dev->dev, "%s: droq_ops pointer is NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (q_no >= CFG_GET_OQ_MAX_Q(oct_cfg)) {
+ dev_err(&oct->pci_dev->dev, "%s: droq id (%d) exceeds MAX (%d)\n",
+ __func__, q_no, (oct->num_oqs - 1));
+ return -EINVAL;
+ }
+
+ droq = oct->droq[q_no];
+
+ spin_lock_irqsave(&droq->lock, flags);
+
+ memcpy(&droq->ops, ops, sizeof(struct octeon_droq_ops));
+
+ spin_unlock_irqrestore(&droq->lock, flags);
+
+ return 0;
+}
+
+int octeon_unregister_droq_ops(struct octeon_device *oct, u32 q_no)
+{
+ unsigned long flags;
+ struct octeon_droq *droq;
+ struct octeon_config *oct_cfg = NULL;
+
+ oct_cfg = octeon_get_conf(oct);
+
+ if (!oct_cfg)
+ return -EINVAL;
+
+ if (q_no >= CFG_GET_OQ_MAX_Q(oct_cfg)) {
+ dev_err(&oct->pci_dev->dev, "%s: droq id (%d) exceeds MAX (%d)\n",
+ __func__, q_no, oct->num_oqs - 1);
+ return -EINVAL;
+ }
+
+ droq = oct->droq[q_no];
+
+ if (!droq) {
+ dev_info(&oct->pci_dev->dev,
+ "Droq id (%d) not available.\n", q_no);
+ return 0;
+ }
+
+ spin_lock_irqsave(&droq->lock, flags);
+
+ droq->ops.fptr = NULL;
+ droq->ops.drop_on_max = 0;
+
+ spin_unlock_irqrestore(&droq->lock, flags);
+
+ return 0;
+}
+
+int octeon_create_droq(struct octeon_device *oct,
+ u32 q_no, u32 num_descs,
+ u32 desc_size, void *app_ctx)
+{
+ struct octeon_droq *droq;
+
+ if (oct->droq[q_no]) {
+ dev_dbg(&oct->pci_dev->dev, "Droq already in use. Cannot create droq %d again\n",
+ q_no);
+ return 1;
+ }
+
+ /* Allocate the DS for the new droq. */
+ droq = vmalloc(sizeof(*droq));
+ if (!droq)
+ goto create_droq_fail;
+ memset(droq, 0, sizeof(struct octeon_droq));
+
+ /*Disable the pkt o/p for this Q */
+ octeon_set_droq_pkt_op(oct, q_no, 0);
+ oct->droq[q_no] = droq;
+
+ /* Initialize the Droq */
+ octeon_init_droq(oct, q_no, num_descs, desc_size, app_ctx);
+
+ oct->num_oqs++;
+
+ dev_dbg(&oct->pci_dev->dev, "%s: Total number of OQ: %d\n", __func__,
+ oct->num_oqs);
+
+ /* Global Droq register settings */
+
+ /* As of now not required, as setting are done for all 32 Droqs at
+ * the same time.
+ */
+ return 0;
+
+create_droq_fail:
+ octeon_delete_droq(oct, q_no);
+ return -1;
+}
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.h b/drivers/net/ethernet/cavium/liquidio/octeon_droq.h
new file mode 100644
index 000000000000..7940ccee12d9
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.h
@@ -0,0 +1,426 @@
+/**********************************************************************
+ * Author: Cavium, Inc.
+ *
+ * Contact: support@cavium.com
+ * Please include "LiquidIO" in the subject.
+ *
+ * Copyright (c) 2003-2015 Cavium, Inc.
+ *
+ * This file 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 file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium, Inc. for more information
+ **********************************************************************/
+
+/*! \file octeon_droq.h
+ * \brief Implementation of Octeon Output queues. "Output" is with
+ * respect to the Octeon device on the NIC. From this driver's point of
+ * view they are ingress queues.
+ */
+
+#ifndef __OCTEON_DROQ_H__
+#define __OCTEON_DROQ_H__
+
+/* Default number of packets that will be processed in one iteration. */
+#define MAX_PACKET_BUDGET 0xFFFFFFFF
+
+/** Octeon descriptor format.
+ * The descriptor ring is made of descriptors which have 2 64-bit values:
+ * -# Physical (bus) address of the data buffer.
+ * -# Physical (bus) address of a octeon_droq_info structure.
+ * The Octeon device DMA's incoming packets and its information at the address
+ * given by these descriptor fields.
+ */
+struct octeon_droq_desc {
+ /** The buffer pointer */
+ u64 buffer_ptr;
+
+ /** The Info pointer */
+ u64 info_ptr;
+};
+
+#define OCT_DROQ_DESC_SIZE (sizeof(struct octeon_droq_desc))
+
+/** Information about packet DMA'ed by Octeon.
+ * The format of the information available at Info Pointer after Octeon
+ * has posted a packet. Not all descriptors have valid information. Only
+ * the Info field of the first descriptor for a packet has information
+ * about the packet.
+ */
+struct octeon_droq_info {
+ /** The Output Receive Header. */
+ union octeon_rh rh;
+
+ /** The Length of the packet. */
+ u64 length;
+};
+
+#define OCT_DROQ_INFO_SIZE (sizeof(struct octeon_droq_info))
+
+/** Pointer to data buffer.
+ * Driver keeps a pointer to the data buffer that it made available to
+ * the Octeon device. Since the descriptor ring keeps physical (bus)
+ * addresses, this field is required for the driver to keep track of
+ * the virtual address pointers.
+*/
+struct octeon_recv_buffer {
+ /** Packet buffer, including metadata. */
+ void *buffer;
+
+ /** Data in the packet buffer. */
+ u8 *data;
+};
+
+#define OCT_DROQ_RECVBUF_SIZE (sizeof(struct octeon_recv_buffer))
+
+/** Output Queue statistics. Each output queue has four stats fields. */
+struct oct_droq_stats {
+ /** Number of packets received in this queue. */
+ u64 pkts_received;
+
+ /** Bytes received by this queue. */
+ u64 bytes_received;
+
+ /** Packets dropped due to no dispatch function. */
+ u64 dropped_nodispatch;
+
+ /** Packets dropped due to no memory available. */
+ u64 dropped_nomem;
+
+ /** Packets dropped due to large number of pkts to process. */
+ u64 dropped_toomany;
+
+ /** Number of packets sent to stack from this queue. */
+ u64 rx_pkts_received;
+
+ /** Number of Bytes sent to stack from this queue. */
+ u64 rx_bytes_received;
+
+ /** Num of Packets dropped due to receive path failures. */
+ u64 rx_dropped;
+};
+
+#define POLL_EVENT_INTR_ARRIVED 1
+#define POLL_EVENT_PROCESS_PKTS 2
+#define POLL_EVENT_PENDING_PKTS 3
+#define POLL_EVENT_ENABLE_INTR 4
+
+/* The maximum number of buffers that can be dispatched from the
+ * output/dma queue. Set to 64 assuming 1K buffers in DROQ and the fact that
+ * max packet size from DROQ is 64K.
+ */
+#define MAX_RECV_BUFS 64
+
+/** Receive Packet format used when dispatching output queue packets
+ * with non-raw opcodes.
+ * The received packet will be sent to the upper layers using this
+ * structure which is passed as a parameter to the dispatch function
+ */
+struct octeon_recv_pkt {
+ /** Number of buffers in this received packet */
+ u16 buffer_count;
+
+ /** Id of the device that is sending the packet up */
+ u16 octeon_id;
+
+ /** Length of data in the packet buffer */
+ u32 length;
+
+ /** The receive header */
+ union octeon_rh rh;
+
+ /** Pointer to the OS-specific packet buffer */
+ void *buffer_ptr[MAX_RECV_BUFS];
+
+ /** Size of the buffers pointed to by ptr's in buffer_ptr */
+ u32 buffer_size[MAX_RECV_BUFS];
+};
+
+#define OCT_RECV_PKT_SIZE (sizeof(struct octeon_recv_pkt))
+
+/** The first parameter of a dispatch function.
+ * For a raw mode opcode, the driver dispatches with the device
+ * pointer in this structure.
+ * For non-raw mode opcode, the driver dispatches the recv_pkt
+ * created to contain the buffers with data received from Octeon.
+ * ---------------------
+ * | *recv_pkt ----|---
+ * |-------------------| |
+ * | 0 or more bytes | |
+ * | reserved by driver| |
+ * |-------------------|<-/
+ * | octeon_recv_pkt |
+ * | |
+ * |___________________|
+ */
+struct octeon_recv_info {
+ void *rsvd;
+ struct octeon_recv_pkt *recv_pkt;
+};
+
+#define OCT_RECV_INFO_SIZE (sizeof(struct octeon_recv_info))
+
+/** Allocate a recv_info structure. The recv_pkt pointer in the recv_info
+ * structure is filled in before this call returns.
+ * @param extra_bytes - extra bytes to be allocated at the end of the recv info
+ * structure.
+ * @return - pointer to a newly allocated recv_info structure.
+ */
+static inline struct octeon_recv_info *octeon_alloc_recv_info(int extra_bytes)
+{
+ struct octeon_recv_info *recv_info;
+ u8 *buf;
+
+ buf = kmalloc(OCT_RECV_PKT_SIZE + OCT_RECV_INFO_SIZE +
+ extra_bytes, GFP_ATOMIC);
+ if (!buf)
+ return NULL;
+
+ recv_info = (struct octeon_recv_info *)buf;
+ recv_info->recv_pkt =
+ (struct octeon_recv_pkt *)(buf + OCT_RECV_INFO_SIZE);
+ recv_info->rsvd = NULL;
+ if (extra_bytes)
+ recv_info->rsvd = buf + OCT_RECV_INFO_SIZE + OCT_RECV_PKT_SIZE;
+
+ return recv_info;
+}
+
+/** Free a recv_info structure.
+ * @param recv_info - Pointer to receive_info to be freed
+ */
+static inline void octeon_free_recv_info(struct octeon_recv_info *recv_info)
+{
+ kfree(recv_info);
+}
+
+typedef int (*octeon_dispatch_fn_t)(struct octeon_recv_info *, void *);
+
+/** Used by NIC module to register packet handler and to get device
+ * information for each octeon device.
+ */
+struct octeon_droq_ops {
+ /** This registered function will be called by the driver with
+ * the octeon id, pointer to buffer from droq and length of
+ * data in the buffer. The receive header gives the port
+ * number to the caller. Function pointer is set by caller.
+ */
+ void (*fptr)(u32, void *, u32, union octeon_rh *, void *);
+
+ /* This function will be called by the driver for all NAPI related
+ * events. The first param is the octeon id. The second param is the
+ * output queue number. The third is the NAPI event that occurred.
+ */
+ void (*napi_fn)(void *);
+
+ u32 poll_mode;
+
+ /** Flag indicating if the DROQ handler should drop packets that
+ * it cannot handle in one iteration. Set by caller.
+ */
+ u32 drop_on_max;
+};
+
+/** The Descriptor Ring Output Queue structure.
+ * This structure has all the information required to implement a
+ * Octeon DROQ.
+ */
+struct octeon_droq {
+ /** A spinlock to protect access to this ring. */
+ spinlock_t lock;
+
+ u32 q_no;
+
+ struct octeon_droq_ops ops;
+
+ struct octeon_device *oct_dev;
+
+ /** The 8B aligned descriptor ring starts at this address. */
+ struct octeon_droq_desc *desc_ring;
+
+ /** Index in the ring where the driver should read the next packet */
+ u32 read_idx;
+
+ /** Index in the ring where Octeon will write the next packet */
+ u32 write_idx;
+
+ /** Index in the ring where the driver will refill the descriptor's
+ * buffer
+ */
+ u32 refill_idx;
+
+ /** Packets pending to be processed */
+ atomic_t pkts_pending;
+
+ /** Number of descriptors in this ring. */
+ u32 max_count;
+
+ /** The number of descriptors pending refill. */
+ u32 refill_count;
+
+ u32 pkts_per_intr;
+ u32 refill_threshold;
+
+ /** The max number of descriptors in DROQ without a buffer.
+ * This field is used to keep track of empty space threshold. If the
+ * refill_count reaches this value, the DROQ cannot accept a max-sized
+ * (64K) packet.
+ */
+ u32 max_empty_descs;
+
+ /** The 8B aligned info ptrs begin from this address. */
+ struct octeon_droq_info *info_list;
+
+ /** The receive buffer list. This list has the virtual addresses of the
+ * buffers.
+ */
+ struct octeon_recv_buffer *recv_buf_list;
+
+ /** The size of each buffer pointed by the buffer pointer. */
+ u32 buffer_size;
+
+ /** Pointer to the mapped packet credit register.
+ * Host writes number of info/buffer ptrs available to this register
+ */
+ void __iomem *pkts_credit_reg;
+
+ /** Pointer to the mapped packet sent register.
+ * Octeon writes the number of packets DMA'ed to host memory
+ * in this register.
+ */
+ void __iomem *pkts_sent_reg;
+
+ struct list_head dispatch_list;
+
+ /** Statistics for this DROQ. */
+ struct oct_droq_stats stats;
+
+ /** DMA mapped address of the DROQ descriptor ring. */
+ size_t desc_ring_dma;
+
+ /** Info ptr list are allocated at this virtual address. */
+ size_t info_base_addr;
+
+ /** DMA mapped address of the info list */
+ size_t info_list_dma;
+
+ /** Allocated size of info list. */
+ u32 info_alloc_size;
+
+ /** application context */
+ void *app_ctx;
+
+ struct napi_struct napi;
+
+ u32 cpu_id;
+
+ struct call_single_data csd;
+};
+
+#define OCT_DROQ_SIZE (sizeof(struct octeon_droq))
+
+/**
+ * Allocates space for the descriptor ring for the droq and sets the
+ * base addr, num desc etc in Octeon registers.
+ *
+ * @param oct_dev - pointer to the octeon device structure
+ * @param q_no - droq no. ranges from 0 - 3.
+ * @param app_ctx - pointer to application context
+ * @return Success: 0 Failure: 1
+*/
+int octeon_init_droq(struct octeon_device *oct_dev,
+ u32 q_no,
+ u32 num_descs,
+ u32 desc_size,
+ void *app_ctx);
+
+/**
+ * Frees the space for descriptor ring for the droq.
+ *
+ * @param oct_dev - pointer to the octeon device structure
+ * @param q_no - droq no. ranges from 0 - 3.
+ * @return: Success: 0 Failure: 1
+*/
+int octeon_delete_droq(struct octeon_device *oct_dev, u32 q_no);
+
+/** Register a change in droq operations. The ops field has a pointer to a
+ * function which will called by the DROQ handler for all packets arriving
+ * on output queues given by q_no irrespective of the type of packet.
+ * The ops field also has a flag which if set tells the DROQ handler to
+ * drop packets if it receives more than what it can process in one
+ * invocation of the handler.
+ * @param oct - octeon device
+ * @param q_no - octeon output queue number (0 <= q_no <= MAX_OCTEON_DROQ-1
+ * @param ops - the droq_ops settings for this queue
+ * @return - 0 on success, -ENODEV or -EINVAL on error.
+ */
+int
+octeon_register_droq_ops(struct octeon_device *oct,
+ u32 q_no,
+ struct octeon_droq_ops *ops);
+
+/** Resets the function pointer and flag settings made by
+ * octeon_register_droq_ops(). After this routine is called, the DROQ handler
+ * will lookup dispatch function for each arriving packet on the output queue
+ * given by q_no.
+ * @param oct - octeon device
+ * @param q_no - octeon output queue number (0 <= q_no <= MAX_OCTEON_DROQ-1
+ * @return - 0 on success, -ENODEV or -EINVAL on error.
+ */
+int octeon_unregister_droq_ops(struct octeon_device *oct, u32 q_no);
+
+/** Register a dispatch function for a opcode/subcode. The driver will call
+ * this dispatch function when it receives a packet with the given
+ * opcode/subcode in its output queues along with the user specified
+ * argument.
+ * @param oct - the octeon device to register with.
+ * @param opcode - the opcode for which the dispatch will be registered.
+ * @param subcode - the subcode for which the dispatch will be registered
+ * @param fn - the dispatch function.
+ * @param fn_arg - user specified that will be passed along with the
+ * dispatch function by the driver.
+ * @return Success: 0; Failure: 1
+ */
+int octeon_register_dispatch_fn(struct octeon_device *oct,
+ u16 opcode,
+ u16 subcode,
+ octeon_dispatch_fn_t fn, void *fn_arg);
+
+/** Remove registration for an opcode/subcode. This will delete the mapping for
+ * an opcode/subcode. The dispatch function will be unregistered and will no
+ * longer be called if a packet with the opcode/subcode arrives in the driver
+ * output queues.
+ * @param oct - the octeon device to unregister from.
+ * @param opcode - the opcode to be unregistered.
+ * @param subcode - the subcode to be unregistered.
+ *
+ * @return Success: 0; Failure: 1
+ */
+int octeon_unregister_dispatch_fn(struct octeon_device *oct,
+ u16 opcode,
+ u16 subcode);
+
+void octeon_droq_print_stats(void);
+
+u32 octeon_droq_check_hw_for_pkts(struct octeon_device *oct,
+ struct octeon_droq *droq);
+
+int octeon_create_droq(struct octeon_device *oct, u32 q_no,
+ u32 num_descs, u32 desc_size, void *app_ctx);
+
+int octeon_droq_process_packets(struct octeon_device *oct,
+ struct octeon_droq *droq,
+ u32 budget);
+
+int octeon_process_droq_poll_cmd(struct octeon_device *oct, u32 q_no,
+ int cmd, u32 arg);
+
+#endif /*__OCTEON_DROQ_H__ */
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_iq.h b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h
new file mode 100644
index 000000000000..592fe49b589d
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h
@@ -0,0 +1,319 @@
+/**********************************************************************
+ * Author: Cavium, Inc.
+ *
+ * Contact: support@cavium.com
+ * Please include "LiquidIO" in the subject.
+ *
+ * Copyright (c) 2003-2015 Cavium, Inc.
+ *
+ * This file 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 file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium, Inc. for more information
+ **********************************************************************/
+
+/*! \file octeon_iq.h
+ * \brief Host Driver: Implementation of Octeon input queues. "Input" is
+ * with respect to the Octeon device on the NIC. From this driver's
+ * point of view they are egress queues.
+ */
+
+#ifndef __OCTEON_IQ_H__
+#define __OCTEON_IQ_H__
+
+#define IQ_STATUS_RUNNING 1
+
+#define IQ_SEND_OK 0
+#define IQ_SEND_STOP 1
+#define IQ_SEND_FAILED -1
+
+/*------------------------- INSTRUCTION QUEUE --------------------------*/
+
+/* \cond */
+
+#define REQTYPE_NONE 0
+#define REQTYPE_NORESP_NET 1
+#define REQTYPE_NORESP_NET_SG 2
+#define REQTYPE_RESP_NET 3
+#define REQTYPE_RESP_NET_SG 4
+#define REQTYPE_SOFT_COMMAND 5
+#define REQTYPE_LAST 5
+
+struct octeon_request_list {
+ u32 reqtype;
+ void *buf;
+};
+
+/* \endcond */
+
+/** Input Queue statistics. Each input queue has four stats fields. */
+struct oct_iq_stats {
+ u64 instr_posted; /**< Instructions posted to this queue. */
+ u64 instr_processed; /**< Instructions processed in this queue. */
+ u64 instr_dropped; /**< Instructions that could not be processed */
+ u64 bytes_sent; /**< Bytes sent through this queue. */
+ u64 sgentry_sent;/**< Gather entries sent through this queue. */
+ u64 tx_done;/**< Num of packets sent to network. */
+ u64 tx_iq_busy;/**< Numof times this iq was found to be full. */
+ u64 tx_dropped;/**< Numof pkts dropped dueto xmitpath errors. */
+ u64 tx_tot_bytes;/**< Total count of bytes sento to network. */
+};
+
+#define OCT_IQ_STATS_SIZE (sizeof(struct oct_iq_stats))
+
+/** The instruction (input) queue.
+ * The input queue is used to post raw (instruction) mode data or packet
+ * data to Octeon device from the host. Each input queue (upto 4) for
+ * a Octeon device has one such structure to represent it.
+*/
+struct octeon_instr_queue {
+ /** A spinlock to protect access to the input ring. */
+ spinlock_t lock;
+
+ /** Flag that indicates if the queue uses 64 byte commands. */
+ u32 iqcmd_64B:1;
+
+ /** Queue Number. */
+ u32 iq_no:5;
+
+ u32 rsvd:17;
+
+ /* Controls the periodic flushing of iq */
+ u32 do_auto_flush:1;
+
+ u32 status:8;
+
+ /** Maximum no. of instructions in this queue. */
+ u32 max_count;
+
+ /** Index in input ring where the driver should write the next packet */
+ u32 host_write_index;
+
+ /** Index in input ring where Octeon is expected to read the next
+ * packet.
+ */
+ u32 octeon_read_index;
+
+ /** This index aids in finding the window in the queue where Octeon
+ * has read the commands.
+ */
+ u32 flush_index;
+
+ /** This field keeps track of the instructions pending in this queue. */
+ atomic_t instr_pending;
+
+ u32 reset_instr_cnt;
+
+ /** Pointer to the Virtual Base addr of the input ring. */
+ u8 *base_addr;
+
+ struct octeon_request_list *request_list;
+
+ /** Octeon doorbell register for the ring. */
+ void __iomem *doorbell_reg;
+
+ /** Octeon instruction count register for this ring. */
+ void __iomem *inst_cnt_reg;
+
+ /** Number of instructions pending to be posted to Octeon. */
+ u32 fill_cnt;
+
+ /** The max. number of instructions that can be held pending by the
+ * driver.
+ */
+ u32 fill_threshold;
+
+ /** The last time that the doorbell was rung. */
+ u64 last_db_time;
+
+ /** The doorbell timeout. If the doorbell was not rung for this time and
+ * fill_cnt is non-zero, ring the doorbell again.
+ */
+ u32 db_timeout;
+
+ /** Statistics for this input queue. */
+ struct oct_iq_stats stats;
+
+ /** DMA mapped base address of the input descriptor ring. */
+ u64 base_addr_dma;
+
+ /** Application context */
+ void *app_ctx;
+};
+
+/*---------------------- INSTRUCTION FORMAT ----------------------------*/
+
+/** 32-byte instruction format.
+ * Format of instruction for a 32-byte mode input queue.
+ */
+struct octeon_instr_32B {
+ /** Pointer where the input data is available. */
+ u64 dptr;
+
+ /** Instruction Header. */
+ u64 ih;
+
+ /** Pointer where the response for a RAW mode packet will be written
+ * by Octeon.
+ */
+ u64 rptr;
+
+ /** Input Request Header. Additional info about the input. */
+ u64 irh;
+
+};
+
+#define OCT_32B_INSTR_SIZE (sizeof(struct octeon_instr_32B))
+
+/** 64-byte instruction format.
+ * Format of instruction for a 64-byte mode input queue.
+ */
+struct octeon_instr_64B {
+ /** Pointer where the input data is available. */
+ u64 dptr;
+
+ /** Instruction Header. */
+ u64 ih;
+
+ /** Input Request Header. */
+ u64 irh;
+
+ /** opcode/subcode specific parameters */
+ u64 ossp[2];
+
+ /** Return Data Parameters */
+ u64 rdp;
+
+ /** Pointer where the response for a RAW mode packet will be written
+ * by Octeon.
+ */
+ u64 rptr;
+
+ u64 reserved;
+
+};
+
+#define OCT_64B_INSTR_SIZE (sizeof(struct octeon_instr_64B))
+
+/** The size of each buffer in soft command buffer pool
+ */
+#define SOFT_COMMAND_BUFFER_SIZE 1024
+
+struct octeon_soft_command {
+ /** Soft command buffer info. */
+ struct list_head node;
+ u64 dma_addr;
+ u32 size;
+
+ /** Command and return status */
+ struct octeon_instr_64B cmd;
+#define COMPLETION_WORD_INIT 0xffffffffffffffffULL
+ u64 *status_word;
+
+ /** Data buffer info */
+ void *virtdptr;
+ u64 dmadptr;
+ u32 datasize;
+
+ /** Return buffer info */
+ void *virtrptr;
+ u64 dmarptr;
+ u32 rdatasize;
+
+ /** Context buffer info */
+ void *ctxptr;
+ u32 ctxsize;
+
+ /** Time out and callback */
+ size_t wait_time;
+ size_t timeout;
+ u32 iq_no;
+ void (*callback)(struct octeon_device *, u32, void *);
+ void *callback_arg;
+};
+
+/** Maximum number of buffers to allocate into soft command buffer pool
+ */
+#define MAX_SOFT_COMMAND_BUFFERS 16
+
+/** Head of a soft command buffer pool.
+ */
+struct octeon_sc_buffer_pool {
+ /** List structure to add delete pending entries to */
+ struct list_head head;
+
+ /** A lock for this response list */
+ spinlock_t lock;
+
+ atomic_t alloc_buf_count;
+};
+
+int octeon_setup_sc_buffer_pool(struct octeon_device *oct);
+int octeon_free_sc_buffer_pool(struct octeon_device *oct);
+struct octeon_soft_command *
+ octeon_alloc_soft_command(struct octeon_device *oct,
+ u32 datasize, u32 rdatasize,
+ u32 ctxsize);
+void octeon_free_soft_command(struct octeon_device *oct,
+ struct octeon_soft_command *sc);
+
+/**
+ * octeon_init_instr_queue()
+ * @param octeon_dev - pointer to the octeon device structure.
+ * @param iq_no - queue to be initialized (0 <= q_no <= 3).
+ *
+ * Called at driver init time for each input queue. iq_conf has the
+ * configuration parameters for the queue.
+ *
+ * @return Success: 0 Failure: 1
+ */
+int octeon_init_instr_queue(struct octeon_device *octeon_dev, u32 iq_no,
+ u32 num_descs);
+
+/**
+ * octeon_delete_instr_queue()
+ * @param octeon_dev - pointer to the octeon device structure.
+ * @param iq_no - queue to be deleted (0 <= q_no <= 3).
+ *
+ * Called at driver unload time for each input queue. Deletes all
+ * allocated resources for the input queue.
+ *
+ * @return Success: 0 Failure: 1
+ */
+int octeon_delete_instr_queue(struct octeon_device *octeon_dev, u32 iq_no);
+
+int lio_wait_for_instr_fetch(struct octeon_device *oct);
+
+int
+octeon_register_reqtype_free_fn(struct octeon_device *oct, int reqtype,
+ void (*fn)(void *));
+
+int
+lio_process_iq_request_list(struct octeon_device *oct,
+ struct octeon_instr_queue *iq);
+
+int octeon_send_command(struct octeon_device *oct, u32 iq_no,
+ u32 force_db, void *cmd, void *buf,
+ u32 datasize, u32 reqtype);
+
+void octeon_prepare_soft_command(struct octeon_device *oct,
+ struct octeon_soft_command *sc,
+ u8 opcode, u8 subcode,
+ u32 irh_ossp, u64 ossp0,
+ u64 ossp1);
+
+int octeon_send_soft_command(struct octeon_device *oct,
+ struct octeon_soft_command *sc);
+
+int octeon_setup_iq(struct octeon_device *oct, u32 iq_no,
+ u32 num_descs, void *app_ctx);
+
+#endif /* __OCTEON_IQ_H__ */
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_main.h b/drivers/net/ethernet/cavium/liquidio/octeon_main.h
new file mode 100644
index 000000000000..cbd081981180
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_main.h
@@ -0,0 +1,237 @@
+/**********************************************************************
+ * Author: Cavium, Inc.
+ *
+ * Contact: support@cavium.com
+ * Please include "LiquidIO" in the subject.
+ *
+ * Copyright (c) 2003-2015 Cavium, Inc.
+ *
+ * This file 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 file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium, Inc. for more information
+ **********************************************************************/
+
+/*! \file octeon_main.h
+ * \brief Host Driver: This file is included by all host driver source files
+ * to include common definitions.
+ */
+
+#ifndef _OCTEON_MAIN_H_
+#define _OCTEON_MAIN_H_
+
+#if BITS_PER_LONG == 32
+#define CVM_CAST64(v) ((long long)(v))
+#elif BITS_PER_LONG == 64
+#define CVM_CAST64(v) ((long long)(long)(v))
+#else
+#error "Unknown system architecture"
+#endif
+
+#define DRV_NAME "LiquidIO"
+
+/**
+ * \brief determines if a given console has debug enabled.
+ * @param console console to check
+ * @returns 1 = enabled. 0 otherwise
+ */
+int octeon_console_debug_enabled(u32 console);
+
+/* BQL-related functions */
+void octeon_report_sent_bytes_to_bql(void *buf, int reqtype);
+void octeon_update_tx_completion_counters(void *buf, int reqtype,
+ unsigned int *pkts_compl,
+ unsigned int *bytes_compl);
+void octeon_report_tx_completion_to_bql(void *txq, unsigned int pkts_compl,
+ unsigned int bytes_compl);
+
+/** Swap 8B blocks */
+static inline void octeon_swap_8B_data(u64 *data, u32 blocks)
+{
+ while (blocks) {
+ cpu_to_be64s(data);
+ blocks--;
+ data++;
+ }
+}
+
+/**
+ * \brief unmaps a PCI BAR
+ * @param oct Pointer to Octeon device
+ * @param baridx bar index
+ */
+static inline void octeon_unmap_pci_barx(struct octeon_device *oct, int baridx)
+{
+ dev_dbg(&oct->pci_dev->dev, "Freeing PCI mapped regions for Bar%d\n",
+ baridx);
+
+ if (oct->mmio[baridx].done)
+ iounmap(oct->mmio[baridx].hw_addr);
+
+ if (oct->mmio[baridx].start)
+ pci_release_region(oct->pci_dev, baridx * 2);
+}
+
+/**
+ * \brief maps a PCI BAR
+ * @param oct Pointer to Octeon device
+ * @param baridx bar index
+ * @param max_map_len maximum length of mapped memory
+ */
+static inline int octeon_map_pci_barx(struct octeon_device *oct,
+ int baridx, int max_map_len)
+{
+ u32 mapped_len = 0;
+
+ if (pci_request_region(oct->pci_dev, baridx * 2, DRV_NAME)) {
+ dev_err(&oct->pci_dev->dev, "pci_request_region failed for bar %d\n",
+ baridx);
+ return 1;
+ }
+
+ oct->mmio[baridx].start = pci_resource_start(oct->pci_dev, baridx * 2);
+ oct->mmio[baridx].len = pci_resource_len(oct->pci_dev, baridx * 2);
+
+ mapped_len = oct->mmio[baridx].len;
+ if (!mapped_len)
+ return 1;
+
+ if (max_map_len && (mapped_len > max_map_len))
+ mapped_len = max_map_len;
+
+ oct->mmio[baridx].hw_addr =
+ ioremap(oct->mmio[baridx].start, mapped_len);
+ oct->mmio[baridx].mapped_len = mapped_len;
+
+ dev_dbg(&oct->pci_dev->dev, "BAR%d start: 0x%llx mapped %u of %u bytes\n",
+ baridx, oct->mmio[baridx].start, mapped_len,
+ oct->mmio[baridx].len);
+
+ if (!oct->mmio[baridx].hw_addr) {
+ dev_err(&oct->pci_dev->dev, "error ioremap for bar %d\n",
+ baridx);
+ return 1;
+ }
+ oct->mmio[baridx].done = 1;
+
+ return 0;
+}
+
+static inline void *
+cnnic_alloc_aligned_dma(struct pci_dev *pci_dev,
+ u32 size,
+ u32 *alloc_size,
+ size_t *orig_ptr,
+ size_t *dma_addr __attribute__((unused)))
+{
+ int retries = 0;
+ void *ptr = NULL;
+
+#define OCTEON_MAX_ALLOC_RETRIES 1
+ do {
+ ptr =
+ (void *)__get_free_pages(GFP_KERNEL,
+ get_order(size));
+ if ((unsigned long)ptr & 0x07) {
+ free_pages((unsigned long)ptr, get_order(size));
+ ptr = NULL;
+ /* Increment the size required if the first
+ * attempt failed.
+ */
+ if (!retries)
+ size += 7;
+ }
+ retries++;
+ } while ((retries <= OCTEON_MAX_ALLOC_RETRIES) && !ptr);
+
+ *alloc_size = size;
+ *orig_ptr = (unsigned long)ptr;
+ if ((unsigned long)ptr & 0x07)
+ ptr = (void *)(((unsigned long)ptr + 7) & ~(7UL));
+ return ptr;
+}
+
+#define cnnic_free_aligned_dma(pci_dev, ptr, size, orig_ptr, dma_addr) \
+ free_pages(orig_ptr, get_order(size))
+
+static inline void
+sleep_cond(wait_queue_head_t *wait_queue, int *condition)
+{
+ wait_queue_t we;
+
+ init_waitqueue_entry(&we, current);
+ add_wait_queue(wait_queue, &we);
+ while (!(ACCESS_ONCE(*condition))) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (signal_pending(current))
+ goto out;
+ schedule();
+ }
+out:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(wait_queue, &we);
+}
+
+static inline void
+sleep_atomic_cond(wait_queue_head_t *waitq, atomic_t *pcond)
+{
+ wait_queue_t we;
+
+ init_waitqueue_entry(&we, current);
+ add_wait_queue(waitq, &we);
+ while (!atomic_read(pcond)) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (signal_pending(current))
+ goto out;
+ schedule();
+ }
+out:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(waitq, &we);
+}
+
+/* Gives up the CPU for a timeout period.
+ * Check that the condition is not true before we go to sleep for a
+ * timeout period.
+ */
+static inline void
+sleep_timeout_cond(wait_queue_head_t *wait_queue,
+ int *condition,
+ int timeout)
+{
+ wait_queue_t we;
+
+ init_waitqueue_entry(&we, current);
+ add_wait_queue(wait_queue, &we);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!(*condition))
+ schedule_timeout(timeout);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(wait_queue, &we);
+}
+
+#ifndef ROUNDUP4
+#define ROUNDUP4(val) (((val) + 3) & 0xfffffffc)
+#endif
+
+#ifndef ROUNDUP8
+#define ROUNDUP8(val) (((val) + 7) & 0xfffffff8)
+#endif
+
+#ifndef ROUNDUP16
+#define ROUNDUP16(val) (((val) + 15) & 0xfffffff0)
+#endif
+
+#ifndef ROUNDUP128
+#define ROUNDUP128(val) (((val) + 127) & 0xffffff80)
+#endif
+
+#endif /* _OCTEON_MAIN_H_ */
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.c b/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.c
new file mode 100644
index 000000000000..5aecef870377
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.c
@@ -0,0 +1,199 @@
+/**********************************************************************
+ * Author: Cavium, Inc.
+ *
+ * Contact: support@cavium.com
+ * Please include "LiquidIO" in the subject.
+ *
+ * Copyright (c) 2003-2015 Cavium, Inc.
+ *
+ * This file 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 file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium, Inc. for more information
+ **********************************************************************/
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include "octeon_config.h"
+#include "liquidio_common.h"
+#include "octeon_droq.h"
+#include "octeon_iq.h"
+#include "response_manager.h"
+#include "octeon_device.h"
+#include "octeon_nic.h"
+#include "octeon_main.h"
+#include "octeon_network.h"
+#include "cn66xx_regs.h"
+#include "cn66xx_device.h"
+#include "cn68xx_regs.h"
+#include "cn68xx_device.h"
+#include "liquidio_image.h"
+#include "octeon_mem_ops.h"
+
+#define MEMOPS_IDX MAX_BAR1_MAP_INDEX
+
+static inline void
+octeon_toggle_bar1_swapmode(struct octeon_device *oct __attribute__((unused)),
+ u32 idx __attribute__((unused)))
+{
+#ifdef __BIG_ENDIAN_BITFIELD
+ u32 mask;
+
+ mask = oct->fn_list.bar1_idx_read(oct, idx);
+ mask = (mask & 0x2) ? (mask & ~2) : (mask | 2);
+ oct->fn_list.bar1_idx_write(oct, idx, mask);
+#endif
+}
+
+static void
+octeon_pci_fastwrite(struct octeon_device *oct, u8 __iomem *mapped_addr,
+ u8 *hostbuf, u32 len)
+{
+ while ((len) && ((unsigned long)mapped_addr) & 7) {
+ writeb(*(hostbuf++), mapped_addr++);
+ len--;
+ }
+
+ octeon_toggle_bar1_swapmode(oct, MEMOPS_IDX);
+
+ while (len >= 8) {
+ writeq(*((u64 *)hostbuf), mapped_addr);
+ mapped_addr += 8;
+ hostbuf += 8;
+ len -= 8;
+ }
+
+ octeon_toggle_bar1_swapmode(oct, MEMOPS_IDX);
+
+ while (len--)
+ writeb(*(hostbuf++), mapped_addr++);
+}
+
+static void
+octeon_pci_fastread(struct octeon_device *oct, u8 __iomem *mapped_addr,
+ u8 *hostbuf, u32 len)
+{
+ while ((len) && ((unsigned long)mapped_addr) & 7) {
+ *(hostbuf++) = readb(mapped_addr++);
+ len--;
+ }
+
+ octeon_toggle_bar1_swapmode(oct, MEMOPS_IDX);
+
+ while (len >= 8) {
+ *((u64 *)hostbuf) = readq(mapped_addr);
+ mapped_addr += 8;
+ hostbuf += 8;
+ len -= 8;
+ }
+
+ octeon_toggle_bar1_swapmode(oct, MEMOPS_IDX);
+
+ while (len--)
+ *(hostbuf++) = readb(mapped_addr++);
+}
+
+/* Core mem read/write with temporary bar1 settings. */
+/* op = 1 to read, op = 0 to write. */
+static void
+__octeon_pci_rw_core_mem(struct octeon_device *oct, u64 addr,
+ u8 *hostbuf, u32 len, u32 op)
+{
+ u32 copy_len = 0, index_reg_val = 0;
+ unsigned long flags;
+ u8 __iomem *mapped_addr;
+
+ spin_lock_irqsave(&oct->mem_access_lock, flags);
+
+ /* Save the original index reg value. */
+ index_reg_val = oct->fn_list.bar1_idx_read(oct, MEMOPS_IDX);
+ do {
+ oct->fn_list.bar1_idx_setup(oct, addr, MEMOPS_IDX, 1);
+ mapped_addr = oct->mmio[1].hw_addr
+ + (MEMOPS_IDX << 22) + (addr & 0x3fffff);
+
+ /* If operation crosses a 4MB boundary, split the transfer
+ * at the 4MB
+ * boundary.
+ */
+ if (((addr + len - 1) & ~(0x3fffff)) != (addr & ~(0x3fffff))) {
+ copy_len = (u32)(((addr & ~(0x3fffff)) +
+ (MEMOPS_IDX << 22)) - addr);
+ } else {
+ copy_len = len;
+ }
+
+ if (op) { /* read from core */
+ octeon_pci_fastread(oct, mapped_addr, hostbuf,
+ copy_len);
+ } else {
+ octeon_pci_fastwrite(oct, mapped_addr, hostbuf,
+ copy_len);
+ }
+
+ len -= copy_len;
+ addr += copy_len;
+ hostbuf += copy_len;
+
+ } while (len);
+
+ oct->fn_list.bar1_idx_write(oct, MEMOPS_IDX, index_reg_val);
+
+ spin_unlock_irqrestore(&oct->mem_access_lock, flags);
+}
+
+void
+octeon_pci_read_core_mem(struct octeon_device *oct,
+ u64 coreaddr,
+ u8 *buf,
+ u32 len)
+{
+ __octeon_pci_rw_core_mem(oct, coreaddr, buf, len, 1);
+}
+
+void
+octeon_pci_write_core_mem(struct octeon_device *oct,
+ u64 coreaddr,
+ u8 *buf,
+ u32 len)
+{
+ __octeon_pci_rw_core_mem(oct, coreaddr, buf, len, 0);
+}
+
+u64 octeon_read_device_mem64(struct octeon_device *oct, u64 coreaddr)
+{
+ __be64 ret;
+
+ __octeon_pci_rw_core_mem(oct, coreaddr, (u8 *)&ret, 8, 1);
+
+ return be64_to_cpu(ret);
+}
+
+u32 octeon_read_device_mem32(struct octeon_device *oct, u64 coreaddr)
+{
+ __be32 ret;
+
+ __octeon_pci_rw_core_mem(oct, coreaddr, (u8 *)&ret, 4, 1);
+
+ return be32_to_cpu(ret);
+}
+
+void octeon_write_device_mem32(struct octeon_device *oct, u64 coreaddr,
+ u32 val)
+{
+ __be32 t = cpu_to_be32(val);
+
+ __octeon_pci_rw_core_mem(oct, coreaddr, (u8 *)&t, 4, 0);
+}
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.h b/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.h
new file mode 100644
index 000000000000..11b183377b44
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.h
@@ -0,0 +1,75 @@
+/**********************************************************************
+ * Author: Cavium, Inc.
+ *
+ * Contact: support@cavium.com
+ * Please include "LiquidIO" in the subject.
+ *
+ * Copyright (c) 2003-2015 Cavium, Inc.
+ *
+ * This file 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 file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium, Inc. for more information
+ **********************************************************************/
+
+/*! \file octeon_mem_ops.h
+ * \brief Host Driver: Routines used to read/write Octeon memory.
+ */
+
+#ifndef __OCTEON_MEM_OPS_H__
+#define __OCTEON_MEM_OPS_H__
+
+/** Read a 64-bit value from a BAR1 mapped core memory address.
+ * @param oct - pointer to the octeon device.
+ * @param core_addr - the address to read from.
+ *
+ * The range_idx gives the BAR1 index register for the range of address
+ * in which core_addr is mapped.
+ *
+ * @return 64-bit value read from Core memory
+ */
+u64 octeon_read_device_mem64(struct octeon_device *oct, u64 core_addr);
+
+/** Read a 32-bit value from a BAR1 mapped core memory address.
+ * @param oct - pointer to the octeon device.
+ * @param core_addr - the address to read from.
+ *
+ * @return 32-bit value read from Core memory
+ */
+u32 octeon_read_device_mem32(struct octeon_device *oct, u64 core_addr);
+
+/** Write a 32-bit value to a BAR1 mapped core memory address.
+ * @param oct - pointer to the octeon device.
+ * @param core_addr - the address to write to.
+ * @param val - 32-bit value to write.
+ */
+void
+octeon_write_device_mem32(struct octeon_device *oct,
+ u64 core_addr,
+ u32 val);
+
+/** Read multiple bytes from Octeon memory.
+ */
+void
+octeon_pci_read_core_mem(struct octeon_device *oct,
+ u64 coreaddr,
+ u8 *buf,
+ u32 len);
+
+/** Write multiple bytes into Octeon memory.
+ */
+void
+octeon_pci_write_core_mem(struct octeon_device *oct,
+ u64 coreaddr,
+ u8 *buf,
+ u32 len);
+
+#endif
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_network.h b/drivers/net/ethernet/cavium/liquidio/octeon_network.h
new file mode 100644
index 000000000000..b3abe5818fd3
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_network.h
@@ -0,0 +1,224 @@
+/**********************************************************************
+ * Author: Cavium, Inc.
+ *
+ * Contact: support@cavium.com
+ * Please include "LiquidIO" in the subject.
+ *
+ * Copyright (c) 2003-2015 Cavium, Inc.
+ *
+ * This file 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 file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium, Inc. for more information
+ **********************************************************************/
+
+/*! \file octeon_network.h
+ * \brief Host NIC Driver: Structure and Macro definitions used by NIC Module.
+ */
+
+#ifndef __OCTEON_NETWORK_H__
+#define __OCTEON_NETWORK_H__
+#include <linux/version.h>
+#include <linux/dma-mapping.h>
+#include <linux/ptp_clock_kernel.h>
+
+/** LiquidIO per-interface network private data */
+struct lio {
+ /** State of the interface. Rx/Tx happens only in the RUNNING state. */
+ atomic_t ifstate;
+
+ /** Octeon Interface index number. This device will be represented as
+ * oct<ifidx> in the system.
+ */
+ int ifidx;
+
+ /** Octeon Input queue to use to transmit for this network interface. */
+ int txq;
+
+ /** Octeon Output queue from which pkts arrive
+ * for this network interface.
+ */
+ int rxq;
+
+ /** Guards the glist */
+ spinlock_t lock;
+
+ /** Linked list of gather components */
+ struct list_head glist;
+
+ /** Pointer to the NIC properties for the Octeon device this network
+ * interface is associated with.
+ */
+ struct octdev_props *octprops;
+
+ /** Pointer to the octeon device structure. */
+ struct octeon_device *oct_dev;
+
+ struct net_device *netdev;
+
+ /** Link information sent by the core application for this interface. */
+ struct oct_link_info linfo;
+
+ /** Size of Tx queue for this octeon device. */
+ u32 tx_qsize;
+
+ /** Size of Rx queue for this octeon device. */
+ u32 rx_qsize;
+
+ /** Size of MTU this octeon device. */
+ u32 mtu;
+
+ /** msg level flag per interface. */
+ u32 msg_enable;
+
+ /** Copy of Interface capabilities: TSO, TSO6, LRO, Chescksums . */
+ u64 dev_capability;
+
+ /** Copy of beacaon reg in phy */
+ u32 phy_beacon_val;
+
+ /** Copy of ctrl reg in phy */
+ u32 led_ctrl_val;
+
+ /* PTP clock information */
+ struct ptp_clock_info ptp_info;
+ struct ptp_clock *ptp_clock;
+ s64 ptp_adjust;
+
+ /* for atomic access to Octeon PTP reg and data struct */
+ spinlock_t ptp_lock;
+
+ /* Interface info */
+ u32 intf_open;
+
+ /* work queue for txq status */
+ struct cavium_wq txq_status_wq;
+
+};
+
+#define LIO_SIZE (sizeof(struct lio))
+#define GET_LIO(netdev) ((struct lio *)netdev_priv(netdev))
+
+/**
+ * \brief Enable or disable feature
+ * @param netdev pointer to network device
+ * @param cmd Command that just requires acknowledgment
+ */
+int liquidio_set_feature(struct net_device *netdev, int cmd);
+
+/**
+ * \brief Link control command completion callback
+ * @param nctrl_ptr pointer to control packet structure
+ *
+ * This routine is called by the callback function when a ctrl pkt sent to
+ * core app completes. The nctrl_ptr contains a copy of the command type
+ * and data sent to the core app. This routine is only called if the ctrl
+ * pkt was sent successfully to the core app.
+ */
+void liquidio_link_ctrl_cmd_completion(void *nctrl_ptr);
+
+/**
+ * \brief Register ethtool operations
+ * @param netdev pointer to network device
+ */
+void liquidio_set_ethtool_ops(struct net_device *netdev);
+
+static inline void
+*recv_buffer_alloc(struct octeon_device *oct __attribute__((unused)),
+ u32 q_no __attribute__((unused)), u32 size)
+{
+#define SKB_ADJ_MASK 0x3F
+#define SKB_ADJ (SKB_ADJ_MASK + 1)
+
+ struct sk_buff *skb = dev_alloc_skb(size + SKB_ADJ);
+
+ if ((unsigned long)skb->data & SKB_ADJ_MASK) {
+ u32 r = SKB_ADJ - ((unsigned long)skb->data & SKB_ADJ_MASK);
+
+ skb_reserve(skb, r);
+ }
+
+ return (void *)skb;
+}
+
+static inline void recv_buffer_free(void *buffer)
+{
+ dev_kfree_skb_any((struct sk_buff *)buffer);
+}
+
+#define lio_dma_alloc(oct, size, dma_addr) \
+ dma_alloc_coherent(&oct->pci_dev->dev, size, dma_addr, GFP_KERNEL)
+#define lio_dma_free(oct, size, virt_addr, dma_addr) \
+ dma_free_coherent(&oct->pci_dev->dev, size, virt_addr, dma_addr)
+
+#define get_rbd(ptr) (((struct sk_buff *)(ptr))->data)
+
+static inline u64
+lio_map_ring_info(struct octeon_droq *droq, u32 i)
+{
+ dma_addr_t dma_addr;
+ struct octeon_device *oct = droq->oct_dev;
+
+ dma_addr = dma_map_single(&oct->pci_dev->dev, &droq->info_list[i],
+ OCT_DROQ_INFO_SIZE, DMA_FROM_DEVICE);
+
+ BUG_ON(dma_mapping_error(&oct->pci_dev->dev, dma_addr));
+
+ return (u64)dma_addr;
+}
+
+static inline void
+lio_unmap_ring_info(struct pci_dev *pci_dev,
+ u64 info_ptr, u32 size)
+{
+ dma_unmap_single(&pci_dev->dev, info_ptr, size, DMA_FROM_DEVICE);
+}
+
+static inline u64
+lio_map_ring(struct pci_dev *pci_dev,
+ void *buf, u32 size)
+{
+ dma_addr_t dma_addr;
+
+ dma_addr = dma_map_single(&pci_dev->dev, get_rbd(buf), size,
+ DMA_FROM_DEVICE);
+
+ BUG_ON(dma_mapping_error(&pci_dev->dev, dma_addr));
+
+ return (u64)dma_addr;
+}
+
+static inline void
+lio_unmap_ring(struct pci_dev *pci_dev,
+ u64 buf_ptr, u32 size)
+{
+ dma_unmap_single(&pci_dev->dev,
+ buf_ptr, size,
+ DMA_FROM_DEVICE);
+}
+
+static inline void *octeon_fast_packet_alloc(struct octeon_device *oct,
+ struct octeon_droq *droq,
+ u32 q_no, u32 size)
+{
+ return recv_buffer_alloc(oct, q_no, size);
+}
+
+static inline void octeon_fast_packet_next(struct octeon_droq *droq,
+ struct sk_buff *nicbuf,
+ int copy_len,
+ int idx)
+{
+ memcpy(skb_put(nicbuf, copy_len),
+ get_rbd(droq->recv_buf_list[idx].buffer), copy_len);
+}
+
+#endif
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_nic.c b/drivers/net/ethernet/cavium/liquidio/octeon_nic.c
new file mode 100644
index 000000000000..1a0191549cb3
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_nic.c
@@ -0,0 +1,189 @@
+/**********************************************************************
+ * Author: Cavium, Inc.
+ *
+ * Contact: support@cavium.com
+ * Please include "LiquidIO" in the subject.
+ *
+ * Copyright (c) 2003-2015 Cavium, Inc.
+ *
+ * This file 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 file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium, Inc. for more information
+ **********************************************************************/
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include "octeon_config.h"
+#include "liquidio_common.h"
+#include "octeon_droq.h"
+#include "octeon_iq.h"
+#include "response_manager.h"
+#include "octeon_device.h"
+#include "octeon_nic.h"
+#include "octeon_main.h"
+#include "octeon_network.h"
+#include "cn66xx_regs.h"
+#include "cn66xx_device.h"
+#include "cn68xx_regs.h"
+#include "cn68xx_device.h"
+#include "liquidio_image.h"
+#include "octeon_mem_ops.h"
+
+void *
+octeon_alloc_soft_command_resp(struct octeon_device *oct,
+ struct octeon_instr_64B *cmd,
+ size_t rdatasize)
+{
+ struct octeon_soft_command *sc;
+ struct octeon_instr_ih *ih;
+ struct octeon_instr_irh *irh;
+ struct octeon_instr_rdp *rdp;
+
+ sc = (struct octeon_soft_command *)
+ octeon_alloc_soft_command(oct, 0, rdatasize, 0);
+
+ if (!sc)
+ return NULL;
+
+ /* Copy existing command structure into the soft command */
+ memcpy(&sc->cmd, cmd, sizeof(struct octeon_instr_64B));
+
+ /* Add in the response related fields. Opcode and Param are already
+ * there.
+ */
+ ih = (struct octeon_instr_ih *)&sc->cmd.ih;
+ ih->fsz = 40; /* irh + ossp[0] + ossp[1] + rdp + rptr = 40 bytes */
+
+ irh = (struct octeon_instr_irh *)&sc->cmd.irh;
+ irh->rflag = 1; /* a response is required */
+ irh->len = 4; /* means four 64-bit words immediately follow irh */
+
+ rdp = (struct octeon_instr_rdp *)&sc->cmd.rdp;
+ rdp->pcie_port = oct->pcie_port;
+ rdp->rlen = rdatasize;
+
+ *sc->status_word = COMPLETION_WORD_INIT;
+
+ sc->wait_time = 1000;
+ sc->timeout = jiffies + sc->wait_time;
+
+ return sc;
+}
+
+int octnet_send_nic_data_pkt(struct octeon_device *oct,
+ struct octnic_data_pkt *ndata,
+ u32 xmit_more)
+{
+ int ring_doorbell;
+
+ ring_doorbell = !xmit_more;
+
+ return octeon_send_command(oct, ndata->q_no, ring_doorbell, &ndata->cmd,
+ ndata->buf, ndata->datasize,
+ ndata->reqtype);
+}
+
+static void octnet_link_ctrl_callback(struct octeon_device *oct,
+ u32 status,
+ void *sc_ptr)
+{
+ struct octeon_soft_command *sc = (struct octeon_soft_command *)sc_ptr;
+ struct octnic_ctrl_pkt *nctrl;
+
+ nctrl = (struct octnic_ctrl_pkt *)sc->ctxptr;
+
+ /* Call the callback function if status is OK.
+ * Status is OK only if a response was expected and core returned
+ * success.
+ * If no response was expected, status is OK if the command was posted
+ * successfully.
+ */
+ if (!status && nctrl->cb_fn)
+ nctrl->cb_fn(nctrl);
+
+ octeon_free_soft_command(oct, sc);
+}
+
+static inline struct octeon_soft_command
+*octnic_alloc_ctrl_pkt_sc(struct octeon_device *oct,
+ struct octnic_ctrl_pkt *nctrl,
+ struct octnic_ctrl_params nparams)
+{
+ struct octeon_soft_command *sc = NULL;
+ u8 *data;
+ size_t rdatasize;
+ u32 uddsize = 0, datasize = 0;
+
+ uddsize = (u32)(nctrl->ncmd.s.more * 8);
+
+ datasize = OCTNET_CMD_SIZE + uddsize;
+ rdatasize = (nctrl->wait_time) ? 16 : 0;
+
+ sc = (struct octeon_soft_command *)
+ octeon_alloc_soft_command(oct, datasize, rdatasize,
+ sizeof(struct octnic_ctrl_pkt));
+
+ if (!sc)
+ return NULL;
+
+ memcpy(sc->ctxptr, nctrl, sizeof(struct octnic_ctrl_pkt));
+
+ data = (u8 *)sc->virtdptr;
+
+ memcpy(data, &nctrl->ncmd, OCTNET_CMD_SIZE);
+
+ octeon_swap_8B_data((u64 *)data, (OCTNET_CMD_SIZE >> 3));
+
+ if (uddsize) {
+ /* Endian-Swap for UDD should have been done by caller. */
+ memcpy(data + OCTNET_CMD_SIZE, nctrl->udd, uddsize);
+ }
+
+ octeon_prepare_soft_command(oct, sc, OPCODE_NIC, OPCODE_NIC_CMD,
+ 0, 0, 0);
+
+ sc->callback = octnet_link_ctrl_callback;
+ sc->callback_arg = sc;
+ sc->wait_time = nctrl->wait_time;
+
+ return sc;
+}
+
+int
+octnet_send_nic_ctrl_pkt(struct octeon_device *oct,
+ struct octnic_ctrl_pkt *nctrl,
+ struct octnic_ctrl_params nparams)
+{
+ int retval;
+ struct octeon_soft_command *sc = NULL;
+
+ sc = octnic_alloc_ctrl_pkt_sc(oct, nctrl, nparams);
+ if (!sc) {
+ dev_err(&oct->pci_dev->dev, "%s soft command alloc failed\n",
+ __func__);
+ return -1;
+ }
+
+ retval = octeon_send_soft_command(oct, sc);
+ if (retval) {
+ octeon_free_soft_command(oct, sc);
+ dev_err(&oct->pci_dev->dev, "%s soft command send failed status: %x\n",
+ __func__, retval);
+ return -1;
+ }
+
+ return retval;
+}
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_nic.h b/drivers/net/ethernet/cavium/liquidio/octeon_nic.h
new file mode 100644
index 000000000000..0238857c8105
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_nic.h
@@ -0,0 +1,227 @@
+/**********************************************************************
+ * Author: Cavium, Inc.
+ *
+ * Contact: support@cavium.com
+ * Please include "LiquidIO" in the subject.
+ *
+ * Copyright (c) 2003-2015 Cavium, Inc.
+ *
+ * This file 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 file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium, Inc. for more information
+ **********************************************************************/
+
+/*! \file octeon_nic.h
+ * \brief Host NIC Driver: Routine to send network data &
+ * control packet to Octeon.
+ */
+
+#ifndef __OCTEON_NIC_H__
+#define __OCTEON_NIC_H__
+
+/* Maximum number of 8-byte words can be sent in a NIC control message.
+ */
+#define MAX_NCTRL_UDD 32
+
+typedef void (*octnic_ctrl_pkt_cb_fn_t) (void *);
+
+/* Structure of control information passed by the NIC module to the OSI
+ * layer when sending control commands to Octeon device software.
+ */
+struct octnic_ctrl_pkt {
+ /** Command to be passed to the Octeon device software. */
+ union octnet_cmd ncmd;
+
+ /** Send buffer */
+ void *data;
+ u64 dmadata;
+
+ /** Response buffer */
+ void *rdata;
+ u64 dmardata;
+
+ /** Additional data that may be needed by some commands. */
+ u64 udd[MAX_NCTRL_UDD];
+
+ /** Time to wait for Octeon software to respond to this control command.
+ * If wait_time is 0, OSI assumes no response is expected.
+ */
+ size_t wait_time;
+
+ /** The network device that issued the control command. */
+ u64 netpndev;
+
+ /** Callback function called when the command has been fetched */
+ octnic_ctrl_pkt_cb_fn_t cb_fn;
+};
+
+#define MAX_UDD_SIZE(nctrl) (sizeof(nctrl->udd))
+
+/** Structure of data information passed by the NIC module to the OSI
+ * layer when forwarding data to Octeon device software.
+ */
+struct octnic_data_pkt {
+ /** Pointer to information maintained by NIC module for this packet. The
+ * OSI layer passes this as-is to the driver.
+ */
+ void *buf;
+
+ /** Type of buffer passed in "buf" above. */
+ u32 reqtype;
+
+ /** Total data bytes to be transferred in this command. */
+ u32 datasize;
+
+ /** Command to be passed to the Octeon device software. */
+ struct octeon_instr_64B cmd;
+
+ /** Input queue to use to send this command. */
+ u32 q_no;
+
+};
+
+/** Structure passed by NIC module to OSI layer to prepare a command to send
+ * network data to Octeon.
+ */
+union octnic_cmd_setup {
+ struct {
+ u32 ifidx:8;
+ u32 cksum_offset:7;
+ u32 gather:1;
+ u32 timestamp:1;
+ u32 ipv4opts_ipv6exthdr:2;
+ u32 ip_csum:1;
+ u32 tnl_csum:1;
+
+ u32 rsvd:11;
+ union {
+ u32 datasize;
+ u32 gatherptrs;
+ } u;
+ } s;
+
+ u64 u64;
+
+};
+
+struct octnic_ctrl_params {
+ u32 resp_order;
+};
+
+static inline int octnet_iq_is_full(struct octeon_device *oct, u32 q_no)
+{
+ return ((u32)atomic_read(&oct->instr_queue[q_no]->instr_pending)
+ >= (oct->instr_queue[q_no]->max_count - 2));
+}
+
+/** Utility function to prepare a 64B NIC instruction based on a setup command
+ * @param cmd - pointer to instruction to be filled in.
+ * @param setup - pointer to the setup structure
+ * @param q_no - which queue for back pressure
+ *
+ * Assumes the cmd instruction is pre-allocated, but no fields are filled in.
+ */
+static inline void
+octnet_prepare_pci_cmd(struct octeon_instr_64B *cmd,
+ union octnic_cmd_setup *setup, u32 tag)
+{
+ struct octeon_instr_ih *ih;
+ struct octeon_instr_irh *irh;
+ union octnic_packet_params packet_params;
+
+ memset(cmd, 0, sizeof(struct octeon_instr_64B));
+
+ ih = (struct octeon_instr_ih *)&cmd->ih;
+
+ /* assume that rflag is cleared so therefore front data will only have
+ * irh and ossp[1] and ossp[2] for a total of 24 bytes
+ */
+ ih->fsz = 24;
+
+ ih->tagtype = ORDERED_TAG;
+ ih->grp = DEFAULT_POW_GRP;
+
+ if (tag)
+ ih->tag = tag;
+ else
+ ih->tag = LIO_DATA(setup->s.ifidx);
+
+ ih->raw = 1;
+ ih->qos = (setup->s.ifidx & 3) + 4; /* map qos based on interface */
+
+ if (!setup->s.gather) {
+ ih->dlengsz = setup->s.u.datasize;
+ } else {
+ ih->gather = 1;
+ ih->dlengsz = setup->s.u.gatherptrs;
+ }
+
+ irh = (struct octeon_instr_irh *)&cmd->irh;
+
+ irh->opcode = OPCODE_NIC;
+ irh->subcode = OPCODE_NIC_NW_DATA;
+
+ packet_params.u32 = 0;
+
+ if (setup->s.cksum_offset) {
+ packet_params.s.csoffset = setup->s.cksum_offset;
+ packet_params.s.ipv4opts_ipv6exthdr =
+ setup->s.ipv4opts_ipv6exthdr;
+ }
+
+ packet_params.s.ip_csum = setup->s.ip_csum;
+ packet_params.s.tnl_csum = setup->s.tnl_csum;
+ packet_params.s.ifidx = setup->s.ifidx;
+ packet_params.s.tsflag = setup->s.timestamp;
+
+ irh->ossp = packet_params.u32;
+}
+
+/** Allocate and a soft command with space for a response immediately following
+ * the commnad.
+ * @param oct - octeon device pointer
+ * @param cmd - pointer to the command structure, pre-filled for everything
+ * except the response.
+ * @param rdatasize - size in bytes of the response.
+ *
+ * @returns pointer to allocated buffer with command copied into it, and
+ * response space immediately following.
+ */
+void *
+octeon_alloc_soft_command_resp(struct octeon_device *oct,
+ struct octeon_instr_64B *cmd,
+ size_t rdatasize);
+
+/** Send a NIC data packet to the device
+ * @param oct - octeon device pointer
+ * @param ndata - control structure with queueing, and buffer information
+ *
+ * @returns IQ_FAILED if it failed to add to the input queue. IQ_STOP if it the
+ * queue should be stopped, and IQ_SEND_OK if it sent okay.
+ */
+int octnet_send_nic_data_pkt(struct octeon_device *oct,
+ struct octnic_data_pkt *ndata, u32 xmit_more);
+
+/** Send a NIC control packet to the device
+ * @param oct - octeon device pointer
+ * @param nctrl - control structure with command, timout, and callback info
+ * @param nparams - response control structure
+ *
+ * @returns IQ_FAILED if it failed to add to the input queue. IQ_STOP if it the
+ * queue should be stopped, and IQ_SEND_OK if it sent okay.
+ */
+int
+octnet_send_nic_ctrl_pkt(struct octeon_device *oct,
+ struct octnic_ctrl_pkt *nctrl,
+ struct octnic_ctrl_params nparams);
+
+#endif
diff --git a/drivers/net/ethernet/cavium/liquidio/request_manager.c b/drivers/net/ethernet/cavium/liquidio/request_manager.c
new file mode 100644
index 000000000000..356796bf9b87
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/request_manager.c
@@ -0,0 +1,766 @@
+/**********************************************************************
+ * Author: Cavium, Inc.
+ *
+ * Contact: support@cavium.com
+ * Please include "LiquidIO" in the subject.
+ *
+ * Copyright (c) 2003-2015 Cavium, Inc.
+ *
+ * This file 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 file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium, Inc. for more information
+ **********************************************************************/
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include "octeon_config.h"
+#include "liquidio_common.h"
+#include "octeon_droq.h"
+#include "octeon_iq.h"
+#include "response_manager.h"
+#include "octeon_device.h"
+#include "octeon_nic.h"
+#include "octeon_main.h"
+#include "octeon_network.h"
+#include "cn66xx_regs.h"
+#include "cn66xx_device.h"
+#include "cn68xx_regs.h"
+#include "cn68xx_device.h"
+#include "liquidio_image.h"
+
+#define INCR_INSTRQUEUE_PKT_COUNT(octeon_dev_ptr, iq_no, field, count) \
+ (octeon_dev_ptr->instr_queue[iq_no]->stats.field += count)
+
+struct iq_post_status {
+ int status;
+ int index;
+};
+
+static void check_db_timeout(struct work_struct *work);
+static void __check_db_timeout(struct octeon_device *oct, unsigned long iq_no);
+
+static void (*reqtype_free_fn[MAX_OCTEON_DEVICES][REQTYPE_LAST + 1]) (void *);
+
+static inline int IQ_INSTR_MODE_64B(struct octeon_device *oct, int iq_no)
+{
+ struct octeon_instr_queue *iq =
+ (struct octeon_instr_queue *)oct->instr_queue[iq_no];
+ return iq->iqcmd_64B;
+}
+
+#define IQ_INSTR_MODE_32B(oct, iq_no) (!IQ_INSTR_MODE_64B(oct, iq_no))
+
+/* Define this to return the request status comaptible to old code */
+/*#define OCTEON_USE_OLD_REQ_STATUS*/
+
+/* Return 0 on success, 1 on failure */
+int octeon_init_instr_queue(struct octeon_device *oct,
+ u32 iq_no, u32 num_descs)
+{
+ struct octeon_instr_queue *iq;
+ struct octeon_iq_config *conf = NULL;
+ u32 q_size;
+ struct cavium_wq *db_wq;
+
+ if (OCTEON_CN6XXX(oct))
+ conf = &(CFG_GET_IQ_CFG(CHIP_FIELD(oct, cn6xxx, conf)));
+
+ if (!conf) {
+ dev_err(&oct->pci_dev->dev, "Unsupported Chip %x\n",
+ oct->chip_id);
+ return 1;
+ }
+
+ if (num_descs & (num_descs - 1)) {
+ dev_err(&oct->pci_dev->dev,
+ "Number of descriptors for instr queue %d not in power of 2.\n",
+ iq_no);
+ return 1;
+ }
+
+ q_size = (u32)conf->instr_type * num_descs;
+
+ iq = oct->instr_queue[iq_no];
+
+ iq->base_addr = lio_dma_alloc(oct, q_size,
+ (dma_addr_t *)&iq->base_addr_dma);
+ if (!iq->base_addr) {
+ dev_err(&oct->pci_dev->dev, "Cannot allocate memory for instr queue %d\n",
+ iq_no);
+ return 1;
+ }
+
+ iq->max_count = num_descs;
+
+ /* Initialize a list to holds requests that have been posted to Octeon
+ * but has yet to be fetched by octeon
+ */
+ iq->request_list = vmalloc(sizeof(*iq->request_list) * num_descs);
+ if (!iq->request_list) {
+ lio_dma_free(oct, q_size, iq->base_addr, iq->base_addr_dma);
+ dev_err(&oct->pci_dev->dev, "Alloc failed for IQ[%d] nr free list\n",
+ iq_no);
+ return 1;
+ }
+
+ memset(iq->request_list, 0, sizeof(*iq->request_list) * num_descs);
+
+ dev_dbg(&oct->pci_dev->dev, "IQ[%d]: base: %p basedma: %llx count: %d\n",
+ iq_no, iq->base_addr, iq->base_addr_dma, iq->max_count);
+
+ iq->iq_no = iq_no;
+ iq->fill_threshold = (u32)conf->db_min;
+ iq->fill_cnt = 0;
+ iq->host_write_index = 0;
+ iq->octeon_read_index = 0;
+ iq->flush_index = 0;
+ iq->last_db_time = 0;
+ iq->do_auto_flush = 1;
+ iq->db_timeout = (u32)conf->db_timeout;
+ atomic_set(&iq->instr_pending, 0);
+
+ /* Initialize the spinlock for this instruction queue */
+ spin_lock_init(&iq->lock);
+
+ oct->io_qmask.iq |= (1 << iq_no);
+
+ /* Set the 32B/64B mode for each input queue */
+ oct->io_qmask.iq64B |= ((conf->instr_type == 64) << iq_no);
+ iq->iqcmd_64B = (conf->instr_type == 64);
+
+ oct->fn_list.setup_iq_regs(oct, iq_no);
+
+ oct->check_db_wq[iq_no].wq = create_workqueue("check_iq_db");
+ if (!oct->check_db_wq[iq_no].wq) {
+ lio_dma_free(oct, q_size, iq->base_addr, iq->base_addr_dma);
+ dev_err(&oct->pci_dev->dev, "check db wq create failed for iq %d\n",
+ iq_no);
+ return 1;
+ }
+
+ db_wq = &oct->check_db_wq[iq_no];
+
+ INIT_DELAYED_WORK(&db_wq->wk.work, check_db_timeout);
+ db_wq->wk.ctxptr = oct;
+ db_wq->wk.ctxul = iq_no;
+ queue_delayed_work(db_wq->wq, &db_wq->wk.work, msecs_to_jiffies(1));
+
+ return 0;
+}
+
+int octeon_delete_instr_queue(struct octeon_device *oct, u32 iq_no)
+{
+ u64 desc_size = 0, q_size;
+ struct octeon_instr_queue *iq = oct->instr_queue[iq_no];
+
+ cancel_delayed_work_sync(&oct->check_db_wq[iq_no].wk.work);
+ flush_workqueue(oct->check_db_wq[iq_no].wq);
+ destroy_workqueue(oct->check_db_wq[iq_no].wq);
+
+ if (OCTEON_CN6XXX(oct))
+ desc_size =
+ CFG_GET_IQ_INSTR_TYPE(CHIP_FIELD(oct, cn6xxx, conf));
+
+ if (iq->request_list)
+ vfree(iq->request_list);
+
+ if (iq->base_addr) {
+ q_size = iq->max_count * desc_size;
+ lio_dma_free(oct, (u32)q_size, iq->base_addr,
+ iq->base_addr_dma);
+ return 0;
+ }
+ return 1;
+}
+
+/* Return 0 on success, 1 on failure */
+int octeon_setup_iq(struct octeon_device *oct,
+ u32 iq_no,
+ u32 num_descs,
+ void *app_ctx)
+{
+ if (oct->instr_queue[iq_no]) {
+ dev_dbg(&oct->pci_dev->dev, "IQ is in use. Cannot create the IQ: %d again\n",
+ iq_no);
+ oct->instr_queue[iq_no]->app_ctx = app_ctx;
+ return 0;
+ }
+ oct->instr_queue[iq_no] =
+ vmalloc(sizeof(struct octeon_instr_queue));
+ if (!oct->instr_queue[iq_no])
+ return 1;
+
+ memset(oct->instr_queue[iq_no], 0,
+ sizeof(struct octeon_instr_queue));
+
+ oct->instr_queue[iq_no]->app_ctx = app_ctx;
+ if (octeon_init_instr_queue(oct, iq_no, num_descs)) {
+ vfree(oct->instr_queue[iq_no]);
+ oct->instr_queue[iq_no] = NULL;
+ return 1;
+ }
+
+ oct->num_iqs++;
+ oct->fn_list.enable_io_queues(oct);
+ return 0;
+}
+
+int lio_wait_for_instr_fetch(struct octeon_device *oct)
+{
+ int i, retry = 1000, pending, instr_cnt = 0;
+
+ do {
+ instr_cnt = 0;
+
+ /*for (i = 0; i < oct->num_iqs; i++) {*/
+ for (i = 0; i < MAX_OCTEON_INSTR_QUEUES; i++) {
+ if (!(oct->io_qmask.iq & (1UL << i)))
+ continue;
+ pending =
+ atomic_read(&oct->
+ instr_queue[i]->instr_pending);
+ if (pending)
+ __check_db_timeout(oct, i);
+ instr_cnt += pending;
+ }
+
+ if (instr_cnt == 0)
+ break;
+
+ schedule_timeout_uninterruptible(1);
+
+ } while (retry-- && instr_cnt);
+
+ return instr_cnt;
+}
+
+static inline void
+ring_doorbell(struct octeon_device *oct, struct octeon_instr_queue *iq)
+{
+ if (atomic_read(&oct->status) == OCT_DEV_RUNNING) {
+ writel(iq->fill_cnt, iq->doorbell_reg);
+ /* make sure doorbell write goes through */
+ mmiowb();
+ iq->fill_cnt = 0;
+ iq->last_db_time = jiffies;
+ return;
+ }
+}
+
+static inline void __copy_cmd_into_iq(struct octeon_instr_queue *iq,
+ u8 *cmd)
+{
+ u8 *iqptr, cmdsize;
+
+ cmdsize = ((iq->iqcmd_64B) ? 64 : 32);
+ iqptr = iq->base_addr + (cmdsize * iq->host_write_index);
+
+ memcpy(iqptr, cmd, cmdsize);
+}
+
+static inline int
+__post_command(struct octeon_device *octeon_dev __attribute__((unused)),
+ struct octeon_instr_queue *iq,
+ u32 force_db __attribute__((unused)), u8 *cmd)
+{
+ u32 index = -1;
+
+ /* This ensures that the read index does not wrap around to the same
+ * position if queue gets full before Octeon could fetch any instr.
+ */
+ if (atomic_read(&iq->instr_pending) >= (s32)(iq->max_count - 1))
+ return -1;
+
+ __copy_cmd_into_iq(iq, cmd);
+
+ /* "index" is returned, host_write_index is modified. */
+ index = iq->host_write_index;
+ INCR_INDEX_BY1(iq->host_write_index, iq->max_count);
+ iq->fill_cnt++;
+
+ /* Flush the command into memory. We need to be sure the data is in
+ * memory before indicating that the instruction is pending.
+ */
+ wmb();
+
+ atomic_inc(&iq->instr_pending);
+
+ return index;
+}
+
+static inline struct iq_post_status
+__post_command2(struct octeon_device *octeon_dev __attribute__((unused)),
+ struct octeon_instr_queue *iq,
+ u32 force_db __attribute__((unused)), u8 *cmd)
+{
+ struct iq_post_status st;
+
+ st.status = IQ_SEND_OK;
+
+ /* This ensures that the read index does not wrap around to the same
+ * position if queue gets full before Octeon could fetch any instr.
+ */
+ if (atomic_read(&iq->instr_pending) >= (s32)(iq->max_count - 1)) {
+ st.status = IQ_SEND_FAILED;
+ st.index = -1;
+ return st;
+ }
+
+ if (atomic_read(&iq->instr_pending) >= (s32)(iq->max_count - 2))
+ st.status = IQ_SEND_STOP;
+
+ __copy_cmd_into_iq(iq, cmd);
+
+ /* "index" is returned, host_write_index is modified. */
+ st.index = iq->host_write_index;
+ INCR_INDEX_BY1(iq->host_write_index, iq->max_count);
+ iq->fill_cnt++;
+
+ /* Flush the command into memory. We need to be sure the data is in
+ * memory before indicating that the instruction is pending.
+ */
+ wmb();
+
+ atomic_inc(&iq->instr_pending);
+
+ return st;
+}
+
+int
+octeon_register_reqtype_free_fn(struct octeon_device *oct, int reqtype,
+ void (*fn)(void *))
+{
+ if (reqtype > REQTYPE_LAST) {
+ dev_err(&oct->pci_dev->dev, "%s: Invalid reqtype: %d\n",
+ __func__, reqtype);
+ return -EINVAL;
+ }
+
+ reqtype_free_fn[oct->octeon_id][reqtype] = fn;
+
+ return 0;
+}
+
+static inline void
+__add_to_request_list(struct octeon_instr_queue *iq,
+ int idx, void *buf, int reqtype)
+{
+ iq->request_list[idx].buf = buf;
+ iq->request_list[idx].reqtype = reqtype;
+}
+
+int
+lio_process_iq_request_list(struct octeon_device *oct,
+ struct octeon_instr_queue *iq)
+{
+ int reqtype;
+ void *buf;
+ u32 old = iq->flush_index;
+ u32 inst_count = 0;
+ unsigned pkts_compl = 0, bytes_compl = 0;
+ struct octeon_soft_command *sc;
+ struct octeon_instr_irh *irh;
+
+ while (old != iq->octeon_read_index) {
+ reqtype = iq->request_list[old].reqtype;
+ buf = iq->request_list[old].buf;
+
+ if (reqtype == REQTYPE_NONE)
+ goto skip_this;
+
+ octeon_update_tx_completion_counters(buf, reqtype, &pkts_compl,
+ &bytes_compl);
+
+ switch (reqtype) {
+ case REQTYPE_NORESP_NET:
+ case REQTYPE_NORESP_NET_SG:
+ case REQTYPE_RESP_NET_SG:
+ reqtype_free_fn[oct->octeon_id][reqtype](buf);
+ break;
+ case REQTYPE_RESP_NET:
+ case REQTYPE_SOFT_COMMAND:
+ sc = buf;
+
+ irh = (struct octeon_instr_irh *)&sc->cmd.irh;
+ if (irh->rflag) {
+ /* We're expecting a response from Octeon.
+ * It's up to lio_process_ordered_list() to
+ * process sc. Add sc to the ordered soft
+ * command response list because we expect
+ * a response from Octeon.
+ */
+ spin_lock_bh(&oct->response_list
+ [OCTEON_ORDERED_SC_LIST].lock);
+ atomic_inc(&oct->response_list
+ [OCTEON_ORDERED_SC_LIST].
+ pending_req_count);
+ list_add_tail(&sc->node, &oct->response_list
+ [OCTEON_ORDERED_SC_LIST].head);
+ spin_unlock_bh(&oct->response_list
+ [OCTEON_ORDERED_SC_LIST].lock);
+ } else {
+ if (sc->callback) {
+ sc->callback(oct, OCTEON_REQUEST_DONE,
+ sc->callback_arg);
+ }
+ }
+ break;
+ default:
+ dev_err(&oct->pci_dev->dev,
+ "%s Unknown reqtype: %d buf: %p at idx %d\n",
+ __func__, reqtype, buf, old);
+ }
+
+ iq->request_list[old].buf = NULL;
+ iq->request_list[old].reqtype = 0;
+
+ skip_this:
+ inst_count++;
+ INCR_INDEX_BY1(old, iq->max_count);
+ }
+ if (bytes_compl)
+ octeon_report_tx_completion_to_bql(iq->app_ctx, pkts_compl,
+ bytes_compl);
+ iq->flush_index = old;
+
+ return inst_count;
+}
+
+static inline void
+update_iq_indices(struct octeon_device *oct, struct octeon_instr_queue *iq)
+{
+ u32 inst_processed = 0;
+
+ /* Calculate how many commands Octeon has read and move the read index
+ * accordingly.
+ */
+ iq->octeon_read_index = oct->fn_list.update_iq_read_idx(oct, iq);
+
+ /* Move the NORESPONSE requests to the per-device completion list. */
+ if (iq->flush_index != iq->octeon_read_index)
+ inst_processed = lio_process_iq_request_list(oct, iq);
+
+ if (inst_processed) {
+ atomic_sub(inst_processed, &iq->instr_pending);
+ iq->stats.instr_processed += inst_processed;
+ }
+}
+
+static void
+octeon_flush_iq(struct octeon_device *oct, struct octeon_instr_queue *iq,
+ u32 pending_thresh)
+{
+ if (atomic_read(&iq->instr_pending) >= (s32)pending_thresh) {
+ spin_lock_bh(&iq->lock);
+ update_iq_indices(oct, iq);
+ spin_unlock_bh(&iq->lock);
+ }
+}
+
+static void __check_db_timeout(struct octeon_device *oct, unsigned long iq_no)
+{
+ struct octeon_instr_queue *iq;
+ u64 next_time;
+
+ if (!oct)
+ return;
+ iq = oct->instr_queue[iq_no];
+ if (!iq)
+ return;
+
+ /* If jiffies - last_db_time < db_timeout do nothing */
+ next_time = iq->last_db_time + iq->db_timeout;
+ if (!time_after(jiffies, (unsigned long)next_time))
+ return;
+ iq->last_db_time = jiffies;
+
+ /* Get the lock and prevent tasklets. This routine gets called from
+ * the poll thread. Instructions can now be posted in tasklet context
+ */
+ spin_lock_bh(&iq->lock);
+ if (iq->fill_cnt != 0)
+ ring_doorbell(oct, iq);
+
+ spin_unlock_bh(&iq->lock);
+
+ /* Flush the instruction queue */
+ if (iq->do_auto_flush)
+ octeon_flush_iq(oct, iq, 1);
+}
+
+/* Called by the Poll thread at regular intervals to check the instruction
+ * queue for commands to be posted and for commands that were fetched by Octeon.
+ */
+static void check_db_timeout(struct work_struct *work)
+{
+ struct cavium_wk *wk = (struct cavium_wk *)work;
+ struct octeon_device *oct = (struct octeon_device *)wk->ctxptr;
+ unsigned long iq_no = wk->ctxul;
+ struct cavium_wq *db_wq = &oct->check_db_wq[iq_no];
+
+ __check_db_timeout(oct, iq_no);
+ queue_delayed_work(db_wq->wq, &db_wq->wk.work, msecs_to_jiffies(1));
+}
+
+int
+octeon_send_command(struct octeon_device *oct, u32 iq_no,
+ u32 force_db, void *cmd, void *buf,
+ u32 datasize, u32 reqtype)
+{
+ struct iq_post_status st;
+ struct octeon_instr_queue *iq = oct->instr_queue[iq_no];
+
+ spin_lock_bh(&iq->lock);
+
+ st = __post_command2(oct, iq, force_db, cmd);
+
+ if (st.status != IQ_SEND_FAILED) {
+ octeon_report_sent_bytes_to_bql(buf, reqtype);
+ __add_to_request_list(iq, st.index, buf, reqtype);
+ INCR_INSTRQUEUE_PKT_COUNT(oct, iq_no, bytes_sent, datasize);
+ INCR_INSTRQUEUE_PKT_COUNT(oct, iq_no, instr_posted, 1);
+
+ if (iq->fill_cnt >= iq->fill_threshold || force_db)
+ ring_doorbell(oct, iq);
+ } else {
+ INCR_INSTRQUEUE_PKT_COUNT(oct, iq_no, instr_dropped, 1);
+ }
+
+ spin_unlock_bh(&iq->lock);
+
+ if (iq->do_auto_flush)
+ octeon_flush_iq(oct, iq, 2);
+
+ return st.status;
+}
+
+void
+octeon_prepare_soft_command(struct octeon_device *oct,
+ struct octeon_soft_command *sc,
+ u8 opcode,
+ u8 subcode,
+ u32 irh_ossp,
+ u64 ossp0,
+ u64 ossp1)
+{
+ struct octeon_config *oct_cfg;
+ struct octeon_instr_ih *ih;
+ struct octeon_instr_irh *irh;
+ struct octeon_instr_rdp *rdp;
+
+ BUG_ON(opcode > 15);
+ BUG_ON(subcode > 127);
+
+ oct_cfg = octeon_get_conf(oct);
+
+ ih = (struct octeon_instr_ih *)&sc->cmd.ih;
+ ih->tagtype = ATOMIC_TAG;
+ ih->tag = LIO_CONTROL;
+ ih->raw = 1;
+ ih->grp = CFG_GET_CTRL_Q_GRP(oct_cfg);
+
+ if (sc->datasize) {
+ ih->dlengsz = sc->datasize;
+ ih->rs = 1;
+ }
+
+ irh = (struct octeon_instr_irh *)&sc->cmd.irh;
+ irh->opcode = opcode;
+ irh->subcode = subcode;
+
+ /* opcode/subcode specific parameters (ossp) */
+ irh->ossp = irh_ossp;
+ sc->cmd.ossp[0] = ossp0;
+ sc->cmd.ossp[1] = ossp1;
+
+ if (sc->rdatasize) {
+ rdp = (struct octeon_instr_rdp *)&sc->cmd.rdp;
+ rdp->pcie_port = oct->pcie_port;
+ rdp->rlen = sc->rdatasize;
+
+ irh->rflag = 1;
+ irh->len = 4;
+ ih->fsz = 40; /* irh+ossp[0]+ossp[1]+rdp+rptr = 40 bytes */
+ } else {
+ irh->rflag = 0;
+ irh->len = 2;
+ ih->fsz = 24; /* irh + ossp[0] + ossp[1] = 24 bytes */
+ }
+
+ while (!(oct->io_qmask.iq & (1 << sc->iq_no)))
+ sc->iq_no++;
+}
+
+int octeon_send_soft_command(struct octeon_device *oct,
+ struct octeon_soft_command *sc)
+{
+ struct octeon_instr_ih *ih;
+ struct octeon_instr_irh *irh;
+ struct octeon_instr_rdp *rdp;
+
+ ih = (struct octeon_instr_ih *)&sc->cmd.ih;
+ if (ih->dlengsz) {
+ BUG_ON(!sc->dmadptr);
+ sc->cmd.dptr = sc->dmadptr;
+ }
+
+ irh = (struct octeon_instr_irh *)&sc->cmd.irh;
+ if (irh->rflag) {
+ BUG_ON(!sc->dmarptr);
+ BUG_ON(!sc->status_word);
+ *sc->status_word = COMPLETION_WORD_INIT;
+
+ rdp = (struct octeon_instr_rdp *)&sc->cmd.rdp;
+
+ sc->cmd.rptr = sc->dmarptr;
+ }
+
+ if (sc->wait_time)
+ sc->timeout = jiffies + sc->wait_time;
+
+ return octeon_send_command(oct, sc->iq_no, 1, &sc->cmd, sc,
+ (u32)ih->dlengsz, REQTYPE_SOFT_COMMAND);
+}
+
+int octeon_setup_sc_buffer_pool(struct octeon_device *oct)
+{
+ int i;
+ u64 dma_addr;
+ struct octeon_soft_command *sc;
+
+ INIT_LIST_HEAD(&oct->sc_buf_pool.head);
+ spin_lock_init(&oct->sc_buf_pool.lock);
+ atomic_set(&oct->sc_buf_pool.alloc_buf_count, 0);
+
+ for (i = 0; i < MAX_SOFT_COMMAND_BUFFERS; i++) {
+ sc = (struct octeon_soft_command *)
+ lio_dma_alloc(oct,
+ SOFT_COMMAND_BUFFER_SIZE,
+ (dma_addr_t *)&dma_addr);
+ if (!sc)
+ return 1;
+
+ sc->dma_addr = dma_addr;
+ sc->size = SOFT_COMMAND_BUFFER_SIZE;
+
+ list_add_tail(&sc->node, &oct->sc_buf_pool.head);
+ }
+
+ return 0;
+}
+
+int octeon_free_sc_buffer_pool(struct octeon_device *oct)
+{
+ struct list_head *tmp, *tmp2;
+ struct octeon_soft_command *sc;
+
+ spin_lock(&oct->sc_buf_pool.lock);
+
+ list_for_each_safe(tmp, tmp2, &oct->sc_buf_pool.head) {
+ list_del(tmp);
+
+ sc = (struct octeon_soft_command *)tmp;
+
+ lio_dma_free(oct, sc->size, sc, sc->dma_addr);
+ }
+
+ INIT_LIST_HEAD(&oct->sc_buf_pool.head);
+
+ spin_unlock(&oct->sc_buf_pool.lock);
+
+ return 0;
+}
+
+struct octeon_soft_command *octeon_alloc_soft_command(struct octeon_device *oct,
+ u32 datasize,
+ u32 rdatasize,
+ u32 ctxsize)
+{
+ u64 dma_addr;
+ u32 size;
+ u32 offset = sizeof(struct octeon_soft_command);
+ struct octeon_soft_command *sc = NULL;
+ struct list_head *tmp;
+
+ BUG_ON((offset + datasize + rdatasize + ctxsize) >
+ SOFT_COMMAND_BUFFER_SIZE);
+
+ spin_lock(&oct->sc_buf_pool.lock);
+
+ if (list_empty(&oct->sc_buf_pool.head)) {
+ spin_unlock(&oct->sc_buf_pool.lock);
+ return NULL;
+ }
+
+ list_for_each(tmp, &oct->sc_buf_pool.head)
+ break;
+
+ list_del(tmp);
+
+ atomic_inc(&oct->sc_buf_pool.alloc_buf_count);
+
+ spin_unlock(&oct->sc_buf_pool.lock);
+
+ sc = (struct octeon_soft_command *)tmp;
+
+ dma_addr = sc->dma_addr;
+ size = sc->size;
+
+ memset(sc, 0, sc->size);
+
+ sc->dma_addr = dma_addr;
+ sc->size = size;
+
+ if (ctxsize) {
+ sc->ctxptr = (u8 *)sc + offset;
+ sc->ctxsize = ctxsize;
+ }
+
+ /* Start data at 128 byte boundary */
+ offset = (offset + ctxsize + 127) & 0xffffff80;
+
+ if (datasize) {
+ sc->virtdptr = (u8 *)sc + offset;
+ sc->dmadptr = dma_addr + offset;
+ sc->datasize = datasize;
+ }
+
+ /* Start rdata at 128 byte boundary */
+ offset = (offset + datasize + 127) & 0xffffff80;
+
+ if (rdatasize) {
+ BUG_ON(rdatasize < 16);
+ sc->virtrptr = (u8 *)sc + offset;
+ sc->dmarptr = dma_addr + offset;
+ sc->rdatasize = rdatasize;
+ sc->status_word = (u64 *)((u8 *)(sc->virtrptr) + rdatasize - 8);
+ }
+
+ return sc;
+}
+
+void octeon_free_soft_command(struct octeon_device *oct,
+ struct octeon_soft_command *sc)
+{
+ spin_lock(&oct->sc_buf_pool.lock);
+
+ list_add_tail(&sc->node, &oct->sc_buf_pool.head);
+
+ atomic_dec(&oct->sc_buf_pool.alloc_buf_count);
+
+ spin_unlock(&oct->sc_buf_pool.lock);
+}
diff --git a/drivers/net/ethernet/cavium/liquidio/response_manager.c b/drivers/net/ethernet/cavium/liquidio/response_manager.c
new file mode 100644
index 000000000000..091f537a946e
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/response_manager.c
@@ -0,0 +1,178 @@
+/**********************************************************************
+ * Author: Cavium, Inc.
+ *
+ * Contact: support@cavium.com
+ * Please include "LiquidIO" in the subject.
+ *
+ * Copyright (c) 2003-2015 Cavium, Inc.
+ *
+ * This file 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 file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium, Inc. for more information
+ **********************************************************************/
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include "octeon_config.h"
+#include "liquidio_common.h"
+#include "octeon_droq.h"
+#include "octeon_iq.h"
+#include "response_manager.h"
+#include "octeon_device.h"
+#include "octeon_nic.h"
+#include "octeon_main.h"
+#include "octeon_network.h"
+#include "cn66xx_regs.h"
+#include "cn66xx_device.h"
+#include "cn68xx_regs.h"
+#include "cn68xx_device.h"
+#include "liquidio_image.h"
+
+static void oct_poll_req_completion(struct work_struct *work);
+
+int octeon_setup_response_list(struct octeon_device *oct)
+{
+ int i, ret = 0;
+ struct cavium_wq *cwq;
+
+ for (i = 0; i < MAX_RESPONSE_LISTS; i++) {
+ INIT_LIST_HEAD(&oct->response_list[i].head);
+ spin_lock_init(&oct->response_list[i].lock);
+ atomic_set(&oct->response_list[i].pending_req_count, 0);
+ }
+
+ oct->dma_comp_wq.wq = create_workqueue("dma-comp");
+ if (!oct->dma_comp_wq.wq) {
+ dev_err(&oct->pci_dev->dev, "failed to create wq thread\n");
+ return -ENOMEM;
+ }
+
+ cwq = &oct->dma_comp_wq;
+ INIT_DELAYED_WORK(&cwq->wk.work, oct_poll_req_completion);
+ cwq->wk.ctxptr = oct;
+ queue_delayed_work(cwq->wq, &cwq->wk.work, msecs_to_jiffies(100));
+
+ return ret;
+}
+
+void octeon_delete_response_list(struct octeon_device *oct)
+{
+ cancel_delayed_work_sync(&oct->dma_comp_wq.wk.work);
+ flush_workqueue(oct->dma_comp_wq.wq);
+ destroy_workqueue(oct->dma_comp_wq.wq);
+}
+
+int lio_process_ordered_list(struct octeon_device *octeon_dev,
+ u32 force_quit)
+{
+ struct octeon_response_list *ordered_sc_list;
+ struct octeon_soft_command *sc;
+ int request_complete = 0;
+ int resp_to_process = MAX_ORD_REQS_TO_PROCESS;
+ u32 status;
+ u64 status64;
+ struct octeon_instr_rdp *rdp;
+
+ ordered_sc_list = &octeon_dev->response_list[OCTEON_ORDERED_SC_LIST];
+
+ do {
+ spin_lock_bh(&ordered_sc_list->lock);
+
+ if (ordered_sc_list->head.next == &ordered_sc_list->head) {
+ /* ordered_sc_list is empty; there is
+ * nothing to process
+ */
+ spin_unlock_bh
+ (&ordered_sc_list->lock);
+ return 1;
+ }
+
+ sc = (struct octeon_soft_command *)ordered_sc_list->
+ head.next;
+ rdp = (struct octeon_instr_rdp *)&sc->cmd.rdp;
+
+ status = OCTEON_REQUEST_PENDING;
+
+ /* check if octeon has finished DMA'ing a response
+ * to where rptr is pointing to
+ */
+ dma_sync_single_for_cpu(&octeon_dev->pci_dev->dev,
+ sc->cmd.rptr, rdp->rlen,
+ DMA_FROM_DEVICE);
+ status64 = *sc->status_word;
+
+ if (status64 != COMPLETION_WORD_INIT) {
+ if ((status64 & 0xff) != 0xff) {
+ octeon_swap_8B_data(&status64, 1);
+ if (((status64 & 0xff) != 0xff)) {
+ status = (u32)(status64 &
+ 0xffffffffULL);
+ }
+ }
+ } else if (force_quit || (sc->timeout &&
+ time_after(jiffies, (unsigned long)sc->timeout))) {
+ status = OCTEON_REQUEST_TIMEOUT;
+ }
+
+ if (status != OCTEON_REQUEST_PENDING) {
+ /* we have received a response or we have timed out */
+ /* remove node from linked list */
+ list_del(&sc->node);
+ atomic_dec(&octeon_dev->response_list
+ [OCTEON_ORDERED_SC_LIST].
+ pending_req_count);
+ spin_unlock_bh
+ (&ordered_sc_list->lock);
+
+ if (sc->callback)
+ sc->callback(octeon_dev, status,
+ sc->callback_arg);
+
+ request_complete++;
+
+ } else {
+ /* no response yet */
+ request_complete = 0;
+ spin_unlock_bh
+ (&ordered_sc_list->lock);
+ }
+
+ /* If we hit the Max Ordered requests to process every loop,
+ * we quit
+ * and let this function be invoked the next time the poll
+ * thread runs
+ * to process the remaining requests. This function can take up
+ * the entire CPU if there is no upper limit to the requests
+ * processed.
+ */
+ if (request_complete >= resp_to_process)
+ break;
+ } while (request_complete);
+
+ return 0;
+}
+
+static void oct_poll_req_completion(struct work_struct *work)
+{
+ struct cavium_wk *wk = (struct cavium_wk *)work;
+ struct octeon_device *oct = (struct octeon_device *)wk->ctxptr;
+ struct cavium_wq *cwq = &oct->dma_comp_wq;
+
+ lio_process_ordered_list(oct, 0);
+
+ queue_delayed_work(cwq->wq, &cwq->wk.work, msecs_to_jiffies(100));
+}
diff --git a/drivers/net/ethernet/cavium/liquidio/response_manager.h b/drivers/net/ethernet/cavium/liquidio/response_manager.h
new file mode 100644
index 000000000000..7a48752dcb10
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/response_manager.h
@@ -0,0 +1,140 @@
+/**********************************************************************
+ * Author: Cavium, Inc.
+ *
+ * Contact: support@cavium.com
+ * Please include "LiquidIO" in the subject.
+ *
+ * Copyright (c) 2003-2015 Cavium, Inc.
+ *
+ * This file 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 file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium, Inc. for more information
+ **********************************************************************/
+
+/*! \file response_manager.h
+ * \brief Host Driver: Response queues for host instructions.
+ */
+
+#ifndef __RESPONSE_MANAGER_H__
+#define __RESPONSE_MANAGER_H__
+
+/** Maximum ordered requests to process in every invocation of
+ * lio_process_ordered_list(). The function will continue to process requests
+ * as long as it can find one that has finished processing. If it keeps
+ * finding requests that have completed, the function can run for ever. The
+ * value defined here sets an upper limit on the number of requests it can
+ * process before it returns control to the poll thread.
+ */
+#define MAX_ORD_REQS_TO_PROCESS 4096
+
+/** Head of a response list. There are several response lists in the
+ * system. One for each response order- Unordered, ordered
+ * and 1 for noresponse entries on each instruction queue.
+ */
+struct octeon_response_list {
+ /** List structure to add delete pending entries to */
+ struct list_head head;
+
+ /** A lock for this response list */
+ spinlock_t lock;
+
+ atomic_t pending_req_count;
+};
+
+/** The type of response list.
+ */
+enum {
+ OCTEON_ORDERED_LIST = 0,
+ OCTEON_UNORDERED_NONBLOCKING_LIST = 1,
+ OCTEON_UNORDERED_BLOCKING_LIST = 2,
+ OCTEON_ORDERED_SC_LIST = 3
+};
+
+/** Response Order values for a Octeon Request. */
+enum {
+ OCTEON_RESP_ORDERED = 0,
+ OCTEON_RESP_UNORDERED = 1,
+ OCTEON_RESP_NORESPONSE = 2
+};
+
+/** Error codes used in Octeon Host-Core communication.
+ *
+ * 31 16 15 0
+ * ---------------------------------
+ * | | |
+ * ---------------------------------
+ * Error codes are 32-bit wide. The upper 16-bits, called Major Error Number,
+ * are reserved to identify the group to which the error code belongs. The
+ * lower 16-bits, called Minor Error Number, carry the actual code.
+ *
+ * So error codes are (MAJOR NUMBER << 16)| MINOR_NUMBER.
+ */
+
+/*------------ Error codes used by host driver -----------------*/
+#define DRIVER_MAJOR_ERROR_CODE 0x0000
+
+/** A value of 0x00000000 indicates no error i.e. success */
+#define DRIVER_ERROR_NONE 0x00000000
+
+/** (Major number: 0x0000; Minor Number: 0x0001) */
+#define DRIVER_ERROR_REQ_PENDING 0x00000001
+#define DRIVER_ERROR_REQ_TIMEOUT 0x00000003
+#define DRIVER_ERROR_REQ_EINTR 0x00000004
+#define DRIVER_ERROR_REQ_ENXIO 0x00000006
+#define DRIVER_ERROR_REQ_ENOMEM 0x0000000C
+#define DRIVER_ERROR_REQ_EINVAL 0x00000016
+#define DRIVER_ERROR_REQ_FAILED 0x000000ff
+
+/** Status for a request.
+ * If a request is not queued to Octeon by the driver, the driver returns
+ * an error condition that's describe by one of the OCTEON_REQ_ERR_* value
+ * below. If the request is successfully queued, the driver will return
+ * a OCTEON_REQUEST_PENDING status. OCTEON_REQUEST_TIMEOUT and
+ * OCTEON_REQUEST_INTERRUPTED are only returned by the driver if the
+ * response for request failed to arrive before a time-out period or if
+ * the request processing * got interrupted due to a signal respectively.
+ */
+enum {
+ OCTEON_REQUEST_DONE = (DRIVER_ERROR_NONE),
+ OCTEON_REQUEST_PENDING = (DRIVER_ERROR_REQ_PENDING),
+ OCTEON_REQUEST_TIMEOUT = (DRIVER_ERROR_REQ_TIMEOUT),
+ OCTEON_REQUEST_INTERRUPTED = (DRIVER_ERROR_REQ_EINTR),
+ OCTEON_REQUEST_NO_DEVICE = (0x00000021),
+ OCTEON_REQUEST_NOT_RUNNING,
+ OCTEON_REQUEST_INVALID_IQ,
+ OCTEON_REQUEST_INVALID_BUFCNT,
+ OCTEON_REQUEST_INVALID_RESP_ORDER,
+ OCTEON_REQUEST_NO_MEMORY,
+ OCTEON_REQUEST_INVALID_BUFSIZE,
+ OCTEON_REQUEST_NO_PENDING_ENTRY,
+ OCTEON_REQUEST_NO_IQ_SPACE = (0x7FFFFFFF)
+
+};
+
+/** Initialize the response lists. The number of response lists to create is
+ * given by count.
+ * @param octeon_dev - the octeon device structure.
+ */
+int octeon_setup_response_list(struct octeon_device *octeon_dev);
+
+void octeon_delete_response_list(struct octeon_device *octeon_dev);
+
+/** Check the status of first entry in the ordered list. If the instruction at
+ * that entry finished processing or has timed-out, the entry is cleaned.
+ * @param octeon_dev - the octeon device structure.
+ * @param force_quit - the request is forced to timeout if this is 1
+ * @return 1 if the ordered list is empty, 0 otherwise.
+ */
+int lio_process_ordered_list(struct octeon_device *octeon_dev,
+ u32 force_quit);
+
+#endif
diff --git a/drivers/net/ethernet/cavium/thunder/Makefile b/drivers/net/ethernet/cavium/thunder/Makefile
new file mode 100644
index 000000000000..5c4615ccaa14
--- /dev/null
+++ b/drivers/net/ethernet/cavium/thunder/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for Cavium's Thunder ethernet device
+#
+
+obj-$(CONFIG_THUNDER_NIC_BGX) += thunder_bgx.o
+obj-$(CONFIG_THUNDER_NIC_PF) += nicpf.o
+obj-$(CONFIG_THUNDER_NIC_VF) += nicvf.o
+
+nicpf-y := nic_main.o
+nicvf-y := nicvf_main.o nicvf_queues.o
+nicvf-y += nicvf_ethtool.o
diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h
new file mode 100644
index 000000000000..dda8a02b7322
--- /dev/null
+++ b/drivers/net/ethernet/cavium/thunder/nic.h
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2015 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef NIC_H
+#define NIC_H
+
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include "thunder_bgx.h"
+
+/* PCI device IDs */
+#define PCI_DEVICE_ID_THUNDER_NIC_PF 0xA01E
+#define PCI_DEVICE_ID_THUNDER_PASS1_NIC_VF 0x0011
+#define PCI_DEVICE_ID_THUNDER_NIC_VF 0xA034
+#define PCI_DEVICE_ID_THUNDER_BGX 0xA026
+
+/* PCI BAR nos */
+#define PCI_CFG_REG_BAR_NUM 0
+#define PCI_MSIX_REG_BAR_NUM 4
+
+/* NIC SRIOV VF count */
+#define MAX_NUM_VFS_SUPPORTED 128
+#define DEFAULT_NUM_VF_ENABLED 8
+
+#define NIC_TNS_BYPASS_MODE 0
+#define NIC_TNS_MODE 1
+
+/* NIC priv flags */
+#define NIC_SRIOV_ENABLED BIT(0)
+
+/* Min/Max packet size */
+#define NIC_HW_MIN_FRS 64
+#define NIC_HW_MAX_FRS 9200 /* 9216 max packet including FCS */
+
+/* Max pkinds */
+#define NIC_MAX_PKIND 16
+
+/* Rx Channels */
+/* Receive channel configuration in TNS bypass mode
+ * Below is configuration in TNS bypass mode
+ * BGX0-LMAC0-CHAN0 - VNIC CHAN0
+ * BGX0-LMAC1-CHAN0 - VNIC CHAN16
+ * ...
+ * BGX1-LMAC0-CHAN0 - VNIC CHAN128
+ * ...
+ * BGX1-LMAC3-CHAN0 - VNIC CHAN174
+ */
+#define NIC_INTF_COUNT 2 /* Interfaces btw VNIC and TNS/BGX */
+#define NIC_CHANS_PER_INF 128
+#define NIC_MAX_CHANS (NIC_INTF_COUNT * NIC_CHANS_PER_INF)
+#define NIC_CPI_COUNT 2048 /* No of channel parse indices */
+
+/* TNS bypass mode: 1-1 mapping between VNIC and BGX:LMAC */
+#define NIC_MAX_BGX MAX_BGX_PER_CN88XX
+#define NIC_CPI_PER_BGX (NIC_CPI_COUNT / NIC_MAX_BGX)
+#define NIC_MAX_CPI_PER_LMAC 64 /* Max when CPI_ALG is IP diffserv */
+#define NIC_RSSI_PER_BGX (NIC_RSSI_COUNT / NIC_MAX_BGX)
+
+/* Tx scheduling */
+#define NIC_MAX_TL4 1024
+#define NIC_MAX_TL4_SHAPERS 256 /* 1 shaper for 4 TL4s */
+#define NIC_MAX_TL3 256
+#define NIC_MAX_TL3_SHAPERS 64 /* 1 shaper for 4 TL3s */
+#define NIC_MAX_TL2 64
+#define NIC_MAX_TL2_SHAPERS 2 /* 1 shaper for 32 TL2s */
+#define NIC_MAX_TL1 2
+
+/* TNS bypass mode */
+#define NIC_TL2_PER_BGX 32
+#define NIC_TL4_PER_BGX (NIC_MAX_TL4 / NIC_MAX_BGX)
+#define NIC_TL4_PER_LMAC (NIC_MAX_TL4 / NIC_CHANS_PER_INF)
+
+/* NIC VF Interrupts */
+#define NICVF_INTR_CQ 0
+#define NICVF_INTR_SQ 1
+#define NICVF_INTR_RBDR 2
+#define NICVF_INTR_PKT_DROP 3
+#define NICVF_INTR_TCP_TIMER 4
+#define NICVF_INTR_MBOX 5
+#define NICVF_INTR_QS_ERR 6
+
+#define NICVF_INTR_CQ_SHIFT 0
+#define NICVF_INTR_SQ_SHIFT 8
+#define NICVF_INTR_RBDR_SHIFT 16
+#define NICVF_INTR_PKT_DROP_SHIFT 20
+#define NICVF_INTR_TCP_TIMER_SHIFT 21
+#define NICVF_INTR_MBOX_SHIFT 22
+#define NICVF_INTR_QS_ERR_SHIFT 23
+
+#define NICVF_INTR_CQ_MASK (0xFF << NICVF_INTR_CQ_SHIFT)
+#define NICVF_INTR_SQ_MASK (0xFF << NICVF_INTR_SQ_SHIFT)
+#define NICVF_INTR_RBDR_MASK (0x03 << NICVF_INTR_RBDR_SHIFT)
+#define NICVF_INTR_PKT_DROP_MASK BIT(NICVF_INTR_PKT_DROP_SHIFT)
+#define NICVF_INTR_TCP_TIMER_MASK BIT(NICVF_INTR_TCP_TIMER_SHIFT)
+#define NICVF_INTR_MBOX_MASK BIT(NICVF_INTR_MBOX_SHIFT)
+#define NICVF_INTR_QS_ERR_MASK BIT(NICVF_INTR_QS_ERR_SHIFT)
+
+/* MSI-X interrupts */
+#define NIC_PF_MSIX_VECTORS 10
+#define NIC_VF_MSIX_VECTORS 20
+
+#define NIC_PF_INTR_ID_ECC0_SBE 0
+#define NIC_PF_INTR_ID_ECC0_DBE 1
+#define NIC_PF_INTR_ID_ECC1_SBE 2
+#define NIC_PF_INTR_ID_ECC1_DBE 3
+#define NIC_PF_INTR_ID_ECC2_SBE 4
+#define NIC_PF_INTR_ID_ECC2_DBE 5
+#define NIC_PF_INTR_ID_ECC3_SBE 6
+#define NIC_PF_INTR_ID_ECC3_DBE 7
+#define NIC_PF_INTR_ID_MBOX0 8
+#define NIC_PF_INTR_ID_MBOX1 9
+
+/* Global timer for CQ timer thresh interrupts
+ * Calculated for SCLK of 700Mhz
+ * value written should be a 1/16th of what is expected
+ *
+ * 1 tick per 0.05usec = value of 2.2
+ * This 10% would be covered in CQ timer thresh value
+ */
+#define NICPF_CLK_PER_INT_TICK 2
+
+struct nicvf_cq_poll {
+ u8 cq_idx; /* Completion queue index */
+ struct napi_struct napi;
+};
+
+#define NIC_RSSI_COUNT 4096 /* Total no of RSS indices */
+#define NIC_MAX_RSS_HASH_BITS 8
+#define NIC_MAX_RSS_IDR_TBL_SIZE (1 << NIC_MAX_RSS_HASH_BITS)
+#define RSS_HASH_KEY_SIZE 5 /* 320 bit key */
+
+struct nicvf_rss_info {
+ bool enable;
+#define RSS_L2_EXTENDED_HASH_ENA BIT(0)
+#define RSS_IP_HASH_ENA BIT(1)
+#define RSS_TCP_HASH_ENA BIT(2)
+#define RSS_TCP_SYN_DIS BIT(3)
+#define RSS_UDP_HASH_ENA BIT(4)
+#define RSS_L4_EXTENDED_HASH_ENA BIT(5)
+#define RSS_ROCE_ENA BIT(6)
+#define RSS_L3_BI_DIRECTION_ENA BIT(7)
+#define RSS_L4_BI_DIRECTION_ENA BIT(8)
+ u64 cfg;
+ u8 hash_bits;
+ u16 rss_size;
+ u8 ind_tbl[NIC_MAX_RSS_IDR_TBL_SIZE];
+ u64 key[RSS_HASH_KEY_SIZE];
+} ____cacheline_aligned_in_smp;
+
+enum rx_stats_reg_offset {
+ RX_OCTS = 0x0,
+ RX_UCAST = 0x1,
+ RX_BCAST = 0x2,
+ RX_MCAST = 0x3,
+ RX_RED = 0x4,
+ RX_RED_OCTS = 0x5,
+ RX_ORUN = 0x6,
+ RX_ORUN_OCTS = 0x7,
+ RX_FCS = 0x8,
+ RX_L2ERR = 0x9,
+ RX_DRP_BCAST = 0xa,
+ RX_DRP_MCAST = 0xb,
+ RX_DRP_L3BCAST = 0xc,
+ RX_DRP_L3MCAST = 0xd,
+ RX_STATS_ENUM_LAST,
+};
+
+enum tx_stats_reg_offset {
+ TX_OCTS = 0x0,
+ TX_UCAST = 0x1,
+ TX_BCAST = 0x2,
+ TX_MCAST = 0x3,
+ TX_DROP = 0x4,
+ TX_STATS_ENUM_LAST,
+};
+
+struct nicvf_hw_stats {
+ u64 rx_bytes_ok;
+ u64 rx_ucast_frames_ok;
+ u64 rx_bcast_frames_ok;
+ u64 rx_mcast_frames_ok;
+ u64 rx_fcs_errors;
+ u64 rx_l2_errors;
+ u64 rx_drop_red;
+ u64 rx_drop_red_bytes;
+ u64 rx_drop_overrun;
+ u64 rx_drop_overrun_bytes;
+ u64 rx_drop_bcast;
+ u64 rx_drop_mcast;
+ u64 rx_drop_l3_bcast;
+ u64 rx_drop_l3_mcast;
+ u64 tx_bytes_ok;
+ u64 tx_ucast_frames_ok;
+ u64 tx_bcast_frames_ok;
+ u64 tx_mcast_frames_ok;
+ u64 tx_drops;
+};
+
+struct nicvf_drv_stats {
+ /* Rx */
+ u64 rx_frames_ok;
+ u64 rx_frames_64;
+ u64 rx_frames_127;
+ u64 rx_frames_255;
+ u64 rx_frames_511;
+ u64 rx_frames_1023;
+ u64 rx_frames_1518;
+ u64 rx_frames_jumbo;
+ u64 rx_drops;
+ /* Tx */
+ u64 tx_frames_ok;
+ u64 tx_drops;
+ u64 tx_busy;
+ u64 tx_tso;
+};
+
+struct nicvf {
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ u8 vf_id;
+ u8 node;
+ u8 tns_mode;
+ u16 mtu;
+ struct queue_set *qs;
+ void __iomem *reg_base;
+ bool link_up;
+ u8 duplex;
+ u32 speed;
+ struct page *rb_page;
+ u32 rb_page_offset;
+ bool rb_alloc_fail;
+ bool rb_work_scheduled;
+ struct delayed_work rbdr_work;
+ struct tasklet_struct rbdr_task;
+ struct tasklet_struct qs_err_task;
+ struct tasklet_struct cq_task;
+ struct nicvf_cq_poll *napi[8];
+ struct nicvf_rss_info rss_info;
+ u8 cpi_alg;
+ /* Interrupt coalescing settings */
+ u32 cq_coalesce_usecs;
+
+ u32 msg_enable;
+ struct nicvf_hw_stats stats;
+ struct nicvf_drv_stats drv_stats;
+ struct bgx_stats bgx_stats;
+ struct work_struct reset_task;
+
+ /* MSI-X */
+ bool msix_enabled;
+ u8 num_vec;
+ struct msix_entry msix_entries[NIC_VF_MSIX_VECTORS];
+ char irq_name[NIC_VF_MSIX_VECTORS][20];
+ bool irq_allocated[NIC_VF_MSIX_VECTORS];
+
+ bool pf_ready_to_rcv_msg;
+ bool pf_acked;
+ bool pf_nacked;
+ bool bgx_stats_acked;
+ bool set_mac_pending;
+} ____cacheline_aligned_in_smp;
+
+/* PF <--> VF Mailbox communication
+ * Eight 64bit registers are shared between PF and VF.
+ * Separate set for each VF.
+ * Writing '1' into last register mbx7 means end of message.
+ */
+
+/* PF <--> VF mailbox communication */
+#define NIC_PF_VF_MAILBOX_SIZE 2
+#define NIC_MBOX_MSG_TIMEOUT 2000 /* ms */
+
+/* Mailbox message types */
+#define NIC_MBOX_MSG_READY 0x01 /* Is PF ready to rcv msgs */
+#define NIC_MBOX_MSG_ACK 0x02 /* ACK the message received */
+#define NIC_MBOX_MSG_NACK 0x03 /* NACK the message received */
+#define NIC_MBOX_MSG_QS_CFG 0x04 /* Configure Qset */
+#define NIC_MBOX_MSG_RQ_CFG 0x05 /* Configure receive queue */
+#define NIC_MBOX_MSG_SQ_CFG 0x06 /* Configure Send queue */
+#define NIC_MBOX_MSG_RQ_DROP_CFG 0x07 /* Configure receive queue */
+#define NIC_MBOX_MSG_SET_MAC 0x08 /* Add MAC ID to DMAC filter */
+#define NIC_MBOX_MSG_SET_MAX_FRS 0x09 /* Set max frame size */
+#define NIC_MBOX_MSG_CPI_CFG 0x0A /* Config CPI, RSSI */
+#define NIC_MBOX_MSG_RSS_SIZE 0x0B /* Get RSS indir_tbl size */
+#define NIC_MBOX_MSG_RSS_CFG 0x0C /* Config RSS table */
+#define NIC_MBOX_MSG_RSS_CFG_CONT 0x0D /* RSS config continuation */
+#define NIC_MBOX_MSG_RQ_BP_CFG 0x0E /* RQ backpressure config */
+#define NIC_MBOX_MSG_RQ_SW_SYNC 0x0F /* Flush inflight pkts to RQ */
+#define NIC_MBOX_MSG_BGX_STATS 0x10 /* Get stats from BGX */
+#define NIC_MBOX_MSG_BGX_LINK_CHANGE 0x11 /* BGX:LMAC link status */
+#define NIC_MBOX_MSG_CFG_DONE 0x12 /* VF configuration done */
+#define NIC_MBOX_MSG_SHUTDOWN 0x13 /* VF is being shutdown */
+
+struct nic_cfg_msg {
+ u8 msg;
+ u8 vf_id;
+ u8 tns_mode;
+ u8 node_id;
+ u8 mac_addr[ETH_ALEN];
+};
+
+/* Qset configuration */
+struct qs_cfg_msg {
+ u8 msg;
+ u8 num;
+ u64 cfg;
+};
+
+/* Receive queue configuration */
+struct rq_cfg_msg {
+ u8 msg;
+ u8 qs_num;
+ u8 rq_num;
+ u64 cfg;
+};
+
+/* Send queue configuration */
+struct sq_cfg_msg {
+ u8 msg;
+ u8 qs_num;
+ u8 sq_num;
+ u64 cfg;
+};
+
+/* Set VF's MAC address */
+struct set_mac_msg {
+ u8 msg;
+ u8 vf_id;
+ u8 mac_addr[ETH_ALEN];
+};
+
+/* Set Maximum frame size */
+struct set_frs_msg {
+ u8 msg;
+ u8 vf_id;
+ u16 max_frs;
+};
+
+/* Set CPI algorithm type */
+struct cpi_cfg_msg {
+ u8 msg;
+ u8 vf_id;
+ u8 rq_cnt;
+ u8 cpi_alg;
+};
+
+/* Get RSS table size */
+struct rss_sz_msg {
+ u8 msg;
+ u8 vf_id;
+ u16 ind_tbl_size;
+};
+
+/* Set RSS configuration */
+struct rss_cfg_msg {
+ u8 msg;
+ u8 vf_id;
+ u8 hash_bits;
+ u8 tbl_len;
+ u8 tbl_offset;
+#define RSS_IND_TBL_LEN_PER_MBX_MSG 8
+ u8 ind_tbl[RSS_IND_TBL_LEN_PER_MBX_MSG];
+};
+
+struct bgx_stats_msg {
+ u8 msg;
+ u8 vf_id;
+ u8 rx;
+ u8 idx;
+ u64 stats;
+};
+
+/* Physical interface link status */
+struct bgx_link_status {
+ u8 msg;
+ u8 link_up;
+ u8 duplex;
+ u32 speed;
+};
+
+/* 128 bit shared memory between PF and each VF */
+union nic_mbx {
+ struct { u8 msg; } msg;
+ struct nic_cfg_msg nic_cfg;
+ struct qs_cfg_msg qs;
+ struct rq_cfg_msg rq;
+ struct sq_cfg_msg sq;
+ struct set_mac_msg mac;
+ struct set_frs_msg frs;
+ struct cpi_cfg_msg cpi_cfg;
+ struct rss_sz_msg rss_size;
+ struct rss_cfg_msg rss_cfg;
+ struct bgx_stats_msg bgx_stats;
+ struct bgx_link_status link_status;
+};
+
+#define NIC_NODE_ID_MASK 0x03
+#define NIC_NODE_ID_SHIFT 44
+
+static inline int nic_get_node_id(struct pci_dev *pdev)
+{
+ u64 addr = pci_resource_start(pdev, PCI_CFG_REG_BAR_NUM);
+ return ((addr >> NIC_NODE_ID_SHIFT) & NIC_NODE_ID_MASK);
+}
+
+int nicvf_set_real_num_queues(struct net_device *netdev,
+ int tx_queues, int rx_queues);
+int nicvf_open(struct net_device *netdev);
+int nicvf_stop(struct net_device *netdev);
+int nicvf_send_msg_to_pf(struct nicvf *vf, union nic_mbx *mbx);
+void nicvf_config_rss(struct nicvf *nic);
+void nicvf_set_rss_key(struct nicvf *nic);
+void nicvf_set_ethtool_ops(struct net_device *netdev);
+void nicvf_update_stats(struct nicvf *nic);
+void nicvf_update_lmac_stats(struct nicvf *nic);
+
+#endif /* NIC_H */
diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c
new file mode 100644
index 000000000000..6e0c03169a55
--- /dev/null
+++ b/drivers/net/ethernet/cavium/thunder/nic_main.c
@@ -0,0 +1,932 @@
+/*
+ * Copyright (C) 2015 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/etherdevice.h>
+#include <linux/of.h>
+
+#include "nic_reg.h"
+#include "nic.h"
+#include "q_struct.h"
+#include "thunder_bgx.h"
+
+#define DRV_NAME "thunder-nic"
+#define DRV_VERSION "1.0"
+
+struct nicpf {
+ struct pci_dev *pdev;
+ u8 rev_id;
+ u8 node;
+ unsigned int flags;
+ u8 num_vf_en; /* No of VF enabled */
+ bool vf_enabled[MAX_NUM_VFS_SUPPORTED];
+ void __iomem *reg_base; /* Register start address */
+ struct pkind_cfg pkind;
+#define NIC_SET_VF_LMAC_MAP(bgx, lmac) (((bgx & 0xF) << 4) | (lmac & 0xF))
+#define NIC_GET_BGX_FROM_VF_LMAC_MAP(map) ((map >> 4) & 0xF)
+#define NIC_GET_LMAC_FROM_VF_LMAC_MAP(map) (map & 0xF)
+ u8 vf_lmac_map[MAX_LMAC];
+ struct delayed_work dwork;
+ struct workqueue_struct *check_link;
+ u8 link[MAX_LMAC];
+ u8 duplex[MAX_LMAC];
+ u32 speed[MAX_LMAC];
+ u16 cpi_base[MAX_NUM_VFS_SUPPORTED];
+ u16 rss_ind_tbl_size;
+ bool mbx_lock[MAX_NUM_VFS_SUPPORTED];
+
+ /* MSI-X */
+ bool msix_enabled;
+ u8 num_vec;
+ struct msix_entry msix_entries[NIC_PF_MSIX_VECTORS];
+ bool irq_allocated[NIC_PF_MSIX_VECTORS];
+};
+
+/* Supported devices */
+static const struct pci_device_id nic_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_NIC_PF) },
+ { 0, } /* end of table */
+};
+
+MODULE_AUTHOR("Sunil Goutham");
+MODULE_DESCRIPTION("Cavium Thunder NIC Physical Function Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, nic_id_table);
+
+/* The Cavium ThunderX network controller can *only* be found in SoCs
+ * containing the ThunderX ARM64 CPU implementation. All accesses to the device
+ * registers on this platform are implicitly strongly ordered with respect
+ * to memory accesses. So writeq_relaxed() and readq_relaxed() are safe to use
+ * with no memory barriers in this driver. The readq()/writeq() functions add
+ * explicit ordering operation which in this case are redundant, and only
+ * add overhead.
+ */
+
+/* Register read/write APIs */
+static void nic_reg_write(struct nicpf *nic, u64 offset, u64 val)
+{
+ writeq_relaxed(val, nic->reg_base + offset);
+}
+
+static u64 nic_reg_read(struct nicpf *nic, u64 offset)
+{
+ return readq_relaxed(nic->reg_base + offset);
+}
+
+/* PF -> VF mailbox communication APIs */
+static void nic_enable_mbx_intr(struct nicpf *nic)
+{
+ /* Enable mailbox interrupt for all 128 VFs */
+ nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S, ~0ull);
+ nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S + sizeof(u64), ~0ull);
+}
+
+static void nic_clear_mbx_intr(struct nicpf *nic, int vf, int mbx_reg)
+{
+ nic_reg_write(nic, NIC_PF_MAILBOX_INT + (mbx_reg << 3), BIT_ULL(vf));
+}
+
+static u64 nic_get_mbx_addr(int vf)
+{
+ return NIC_PF_VF_0_127_MAILBOX_0_1 + (vf << NIC_VF_NUM_SHIFT);
+}
+
+/* Send a mailbox message to VF
+ * @vf: vf to which this message to be sent
+ * @mbx: Message to be sent
+ */
+static void nic_send_msg_to_vf(struct nicpf *nic, int vf, union nic_mbx *mbx)
+{
+ void __iomem *mbx_addr = nic->reg_base + nic_get_mbx_addr(vf);
+ u64 *msg = (u64 *)mbx;
+
+ /* In first revision HW, mbox interrupt is triggerred
+ * when PF writes to MBOX(1), in next revisions when
+ * PF writes to MBOX(0)
+ */
+ if (nic->rev_id == 0) {
+ /* see the comment for nic_reg_write()/nic_reg_read()
+ * functions above
+ */
+ writeq_relaxed(msg[0], mbx_addr);
+ writeq_relaxed(msg[1], mbx_addr + 8);
+ } else {
+ writeq_relaxed(msg[1], mbx_addr + 8);
+ writeq_relaxed(msg[0], mbx_addr);
+ }
+}
+
+/* Responds to VF's READY message with VF's
+ * ID, node, MAC address e.t.c
+ * @vf: VF which sent READY message
+ */
+static void nic_mbx_send_ready(struct nicpf *nic, int vf)
+{
+ union nic_mbx mbx = {};
+ int bgx_idx, lmac;
+ const char *mac;
+
+ mbx.nic_cfg.msg = NIC_MBOX_MSG_READY;
+ mbx.nic_cfg.vf_id = vf;
+
+ mbx.nic_cfg.tns_mode = NIC_TNS_BYPASS_MODE;
+
+ bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
+ lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
+
+ mac = bgx_get_lmac_mac(nic->node, bgx_idx, lmac);
+ if (mac)
+ ether_addr_copy((u8 *)&mbx.nic_cfg.mac_addr, mac);
+
+ mbx.nic_cfg.node_id = nic->node;
+ nic_send_msg_to_vf(nic, vf, &mbx);
+}
+
+/* ACKs VF's mailbox message
+ * @vf: VF to which ACK to be sent
+ */
+static void nic_mbx_send_ack(struct nicpf *nic, int vf)
+{
+ union nic_mbx mbx = {};
+
+ mbx.msg.msg = NIC_MBOX_MSG_ACK;
+ nic_send_msg_to_vf(nic, vf, &mbx);
+}
+
+/* NACKs VF's mailbox message that PF is not able to
+ * complete the action
+ * @vf: VF to which ACK to be sent
+ */
+static void nic_mbx_send_nack(struct nicpf *nic, int vf)
+{
+ union nic_mbx mbx = {};
+
+ mbx.msg.msg = NIC_MBOX_MSG_NACK;
+ nic_send_msg_to_vf(nic, vf, &mbx);
+}
+
+/* Flush all in flight receive packets to memory and
+ * bring down an active RQ
+ */
+static int nic_rcv_queue_sw_sync(struct nicpf *nic)
+{
+ u16 timeout = ~0x00;
+
+ nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x01);
+ /* Wait till sync cycle is finished */
+ while (timeout) {
+ if (nic_reg_read(nic, NIC_PF_SW_SYNC_RX_DONE) & 0x1)
+ break;
+ timeout--;
+ }
+ nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x00);
+ if (!timeout) {
+ dev_err(&nic->pdev->dev, "Receive queue software sync failed");
+ return 1;
+ }
+ return 0;
+}
+
+/* Get BGX Rx/Tx stats and respond to VF's request */
+static void nic_get_bgx_stats(struct nicpf *nic, struct bgx_stats_msg *bgx)
+{
+ int bgx_idx, lmac;
+ union nic_mbx mbx = {};
+
+ bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]);
+ lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]);
+
+ mbx.bgx_stats.msg = NIC_MBOX_MSG_BGX_STATS;
+ mbx.bgx_stats.vf_id = bgx->vf_id;
+ mbx.bgx_stats.rx = bgx->rx;
+ mbx.bgx_stats.idx = bgx->idx;
+ if (bgx->rx)
+ mbx.bgx_stats.stats = bgx_get_rx_stats(nic->node, bgx_idx,
+ lmac, bgx->idx);
+ else
+ mbx.bgx_stats.stats = bgx_get_tx_stats(nic->node, bgx_idx,
+ lmac, bgx->idx);
+ nic_send_msg_to_vf(nic, bgx->vf_id, &mbx);
+}
+
+/* Update hardware min/max frame size */
+static int nic_update_hw_frs(struct nicpf *nic, int new_frs, int vf)
+{
+ if ((new_frs > NIC_HW_MAX_FRS) || (new_frs < NIC_HW_MIN_FRS)) {
+ dev_err(&nic->pdev->dev,
+ "Invalid MTU setting from VF%d rejected, should be between %d and %d\n",
+ vf, NIC_HW_MIN_FRS, NIC_HW_MAX_FRS);
+ return 1;
+ }
+ new_frs += ETH_HLEN;
+ if (new_frs <= nic->pkind.maxlen)
+ return 0;
+
+ nic->pkind.maxlen = new_frs;
+ nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG, *(u64 *)&nic->pkind);
+ return 0;
+}
+
+/* Set minimum transmit packet size */
+static void nic_set_tx_pkt_pad(struct nicpf *nic, int size)
+{
+ int lmac;
+ u64 lmac_cfg;
+
+ /* Max value that can be set is 60 */
+ if (size > 60)
+ size = 60;
+
+ for (lmac = 0; lmac < (MAX_BGX_PER_CN88XX * MAX_LMAC_PER_BGX); lmac++) {
+ lmac_cfg = nic_reg_read(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3));
+ lmac_cfg &= ~(0xF << 2);
+ lmac_cfg |= ((size / 4) << 2);
+ nic_reg_write(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3), lmac_cfg);
+ }
+}
+
+/* Function to check number of LMACs present and set VF::LMAC mapping.
+ * Mapping will be used while initializing channels.
+ */
+static void nic_set_lmac_vf_mapping(struct nicpf *nic)
+{
+ unsigned bgx_map = bgx_get_map(nic->node);
+ int bgx, next_bgx_lmac = 0;
+ int lmac, lmac_cnt = 0;
+ u64 lmac_credit;
+
+ nic->num_vf_en = 0;
+
+ for (bgx = 0; bgx < NIC_MAX_BGX; bgx++) {
+ if (!(bgx_map & (1 << bgx)))
+ continue;
+ lmac_cnt = bgx_get_lmac_count(nic->node, bgx);
+ for (lmac = 0; lmac < lmac_cnt; lmac++)
+ nic->vf_lmac_map[next_bgx_lmac++] =
+ NIC_SET_VF_LMAC_MAP(bgx, lmac);
+ nic->num_vf_en += lmac_cnt;
+
+ /* Program LMAC credits */
+ lmac_credit = (1ull << 1); /* channel credit enable */
+ lmac_credit |= (0x1ff << 2); /* Max outstanding pkt count */
+ /* 48KB BGX Tx buffer size, each unit is of size 16bytes */
+ lmac_credit |= (((((48 * 1024) / lmac_cnt) -
+ NIC_HW_MAX_FRS) / 16) << 12);
+ lmac = bgx * MAX_LMAC_PER_BGX;
+ for (; lmac < lmac_cnt + (bgx * MAX_LMAC_PER_BGX); lmac++)
+ nic_reg_write(nic,
+ NIC_PF_LMAC_0_7_CREDIT + (lmac * 8),
+ lmac_credit);
+ }
+}
+
+#define BGX0_BLOCK 8
+#define BGX1_BLOCK 9
+
+static void nic_init_hw(struct nicpf *nic)
+{
+ int i;
+
+ /* Reset NIC, in case the driver is repeatedly inserted and removed */
+ nic_reg_write(nic, NIC_PF_SOFT_RESET, 1);
+
+ /* Enable NIC HW block */
+ nic_reg_write(nic, NIC_PF_CFG, 0x3);
+
+ /* Enable backpressure */
+ nic_reg_write(nic, NIC_PF_BP_CFG, (1ULL << 6) | 0x03);
+
+ /* Disable TNS mode on both interfaces */
+ nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG,
+ (NIC_TNS_BYPASS_MODE << 7) | BGX0_BLOCK);
+ nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8),
+ (NIC_TNS_BYPASS_MODE << 7) | BGX1_BLOCK);
+ nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG,
+ (1ULL << 63) | BGX0_BLOCK);
+ nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8),
+ (1ULL << 63) | BGX1_BLOCK);
+
+ /* PKIND configuration */
+ nic->pkind.minlen = 0;
+ nic->pkind.maxlen = NIC_HW_MAX_FRS + ETH_HLEN;
+ nic->pkind.lenerr_en = 1;
+ nic->pkind.rx_hdr = 0;
+ nic->pkind.hdr_sl = 0;
+
+ for (i = 0; i < NIC_MAX_PKIND; i++)
+ nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (i << 3),
+ *(u64 *)&nic->pkind);
+
+ nic_set_tx_pkt_pad(nic, NIC_HW_MIN_FRS);
+
+ /* Timer config */
+ nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK);
+}
+
+/* Channel parse index configuration */
+static void nic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg)
+{
+ u32 vnic, bgx, lmac, chan;
+ u32 padd, cpi_count = 0;
+ u64 cpi_base, cpi, rssi_base, rssi;
+ u8 qset, rq_idx = 0;
+
+ vnic = cfg->vf_id;
+ bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]);
+ lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]);
+
+ chan = (lmac * MAX_BGX_CHANS_PER_LMAC) + (bgx * NIC_CHANS_PER_INF);
+ cpi_base = (lmac * NIC_MAX_CPI_PER_LMAC) + (bgx * NIC_CPI_PER_BGX);
+ rssi_base = (lmac * nic->rss_ind_tbl_size) + (bgx * NIC_RSSI_PER_BGX);
+
+ /* Rx channel configuration */
+ nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_BP_CFG | (chan << 3),
+ (1ull << 63) | (vnic << 0));
+ nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_CFG | (chan << 3),
+ ((u64)cfg->cpi_alg << 62) | (cpi_base << 48));
+
+ if (cfg->cpi_alg == CPI_ALG_NONE)
+ cpi_count = 1;
+ else if (cfg->cpi_alg == CPI_ALG_VLAN) /* 3 bits of PCP */
+ cpi_count = 8;
+ else if (cfg->cpi_alg == CPI_ALG_VLAN16) /* 3 bits PCP + DEI */
+ cpi_count = 16;
+ else if (cfg->cpi_alg == CPI_ALG_DIFF) /* 6bits DSCP */
+ cpi_count = NIC_MAX_CPI_PER_LMAC;
+
+ /* RSS Qset, Qidx mapping */
+ qset = cfg->vf_id;
+ rssi = rssi_base;
+ for (; rssi < (rssi_base + cfg->rq_cnt); rssi++) {
+ nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3),
+ (qset << 3) | rq_idx);
+ rq_idx++;
+ }
+
+ rssi = 0;
+ cpi = cpi_base;
+ for (; cpi < (cpi_base + cpi_count); cpi++) {
+ /* Determine port to channel adder */
+ if (cfg->cpi_alg != CPI_ALG_DIFF)
+ padd = cpi % cpi_count;
+ else
+ padd = cpi % 8; /* 3 bits CS out of 6bits DSCP */
+
+ /* Leave RSS_SIZE as '0' to disable RSS */
+ nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3),
+ (vnic << 24) | (padd << 16) | (rssi_base + rssi));
+
+ if ((rssi + 1) >= cfg->rq_cnt)
+ continue;
+
+ if (cfg->cpi_alg == CPI_ALG_VLAN)
+ rssi++;
+ else if (cfg->cpi_alg == CPI_ALG_VLAN16)
+ rssi = ((cpi - cpi_base) & 0xe) >> 1;
+ else if (cfg->cpi_alg == CPI_ALG_DIFF)
+ rssi = ((cpi - cpi_base) & 0x38) >> 3;
+ }
+ nic->cpi_base[cfg->vf_id] = cpi_base;
+}
+
+/* Responsds to VF with its RSS indirection table size */
+static void nic_send_rss_size(struct nicpf *nic, int vf)
+{
+ union nic_mbx mbx = {};
+ u64 *msg;
+
+ msg = (u64 *)&mbx;
+
+ mbx.rss_size.msg = NIC_MBOX_MSG_RSS_SIZE;
+ mbx.rss_size.ind_tbl_size = nic->rss_ind_tbl_size;
+ nic_send_msg_to_vf(nic, vf, &mbx);
+}
+
+/* Receive side scaling configuration
+ * configure:
+ * - RSS index
+ * - indir table i.e hash::RQ mapping
+ * - no of hash bits to consider
+ */
+static void nic_config_rss(struct nicpf *nic, struct rss_cfg_msg *cfg)
+{
+ u8 qset, idx = 0;
+ u64 cpi_cfg, cpi_base, rssi_base, rssi;
+
+ cpi_base = nic->cpi_base[cfg->vf_id];
+ cpi_cfg = nic_reg_read(nic, NIC_PF_CPI_0_2047_CFG | (cpi_base << 3));
+ rssi_base = (cpi_cfg & 0x0FFF) + cfg->tbl_offset;
+
+ rssi = rssi_base;
+ qset = cfg->vf_id;
+
+ for (; rssi < (rssi_base + cfg->tbl_len); rssi++) {
+ nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3),
+ (qset << 3) | (cfg->ind_tbl[idx] & 0x7));
+ idx++;
+ }
+
+ cpi_cfg &= ~(0xFULL << 20);
+ cpi_cfg |= (cfg->hash_bits << 20);
+ nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi_base << 3), cpi_cfg);
+}
+
+/* 4 level transmit side scheduler configutation
+ * for TNS bypass mode
+ *
+ * Sample configuration for SQ0
+ * VNIC0-SQ0 -> TL4(0) -> TL3[0] -> TL2[0] -> TL1[0] -> BGX0
+ * VNIC1-SQ0 -> TL4(8) -> TL3[2] -> TL2[0] -> TL1[0] -> BGX0
+ * VNIC2-SQ0 -> TL4(16) -> TL3[4] -> TL2[1] -> TL1[0] -> BGX0
+ * VNIC3-SQ0 -> TL4(24) -> TL3[6] -> TL2[1] -> TL1[0] -> BGX0
+ * VNIC4-SQ0 -> TL4(512) -> TL3[128] -> TL2[32] -> TL1[1] -> BGX1
+ * VNIC5-SQ0 -> TL4(520) -> TL3[130] -> TL2[32] -> TL1[1] -> BGX1
+ * VNIC6-SQ0 -> TL4(528) -> TL3[132] -> TL2[33] -> TL1[1] -> BGX1
+ * VNIC7-SQ0 -> TL4(536) -> TL3[134] -> TL2[33] -> TL1[1] -> BGX1
+ */
+static void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic, u8 sq_idx)
+{
+ u32 bgx, lmac, chan;
+ u32 tl2, tl3, tl4;
+ u32 rr_quantum;
+
+ bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]);
+ lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]);
+ /* 24 bytes for FCS, IPG and preamble */
+ rr_quantum = ((NIC_HW_MAX_FRS + 24) / 4);
+
+ tl4 = (lmac * NIC_TL4_PER_LMAC) + (bgx * NIC_TL4_PER_BGX);
+ tl4 += sq_idx;
+ tl3 = tl4 / (NIC_MAX_TL4 / NIC_MAX_TL3);
+ nic_reg_write(nic, NIC_PF_QSET_0_127_SQ_0_7_CFG2 |
+ ((u64)vnic << NIC_QS_ID_SHIFT) |
+ ((u32)sq_idx << NIC_Q_NUM_SHIFT), tl4);
+ nic_reg_write(nic, NIC_PF_TL4_0_1023_CFG | (tl4 << 3),
+ ((u64)vnic << 27) | ((u32)sq_idx << 24) | rr_quantum);
+
+ nic_reg_write(nic, NIC_PF_TL3_0_255_CFG | (tl3 << 3), rr_quantum);
+ chan = (lmac * MAX_BGX_CHANS_PER_LMAC) + (bgx * NIC_CHANS_PER_INF);
+ nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), chan);
+ /* Enable backpressure on the channel */
+ nic_reg_write(nic, NIC_PF_CHAN_0_255_TX_CFG | (chan << 3), 1);
+
+ tl2 = tl3 >> 2;
+ nic_reg_write(nic, NIC_PF_TL3A_0_63_CFG | (tl2 << 3), tl2);
+ nic_reg_write(nic, NIC_PF_TL2_0_63_CFG | (tl2 << 3), rr_quantum);
+ /* No priorities as of now */
+ nic_reg_write(nic, NIC_PF_TL2_0_63_PRI | (tl2 << 3), 0x00);
+}
+
+/* Interrupt handler to handle mailbox messages from VFs */
+static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
+{
+ union nic_mbx mbx = {};
+ u64 *mbx_data;
+ u64 mbx_addr;
+ u64 reg_addr;
+ int bgx, lmac;
+ int i;
+ int ret = 0;
+
+ nic->mbx_lock[vf] = true;
+
+ mbx_addr = nic_get_mbx_addr(vf);
+ mbx_data = (u64 *)&mbx;
+
+ for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) {
+ *mbx_data = nic_reg_read(nic, mbx_addr);
+ mbx_data++;
+ mbx_addr += sizeof(u64);
+ }
+
+ dev_dbg(&nic->pdev->dev, "%s: Mailbox msg %d from VF%d\n",
+ __func__, mbx.msg.msg, vf);
+ switch (mbx.msg.msg) {
+ case NIC_MBOX_MSG_READY:
+ nic_mbx_send_ready(nic, vf);
+ nic->link[vf] = 0;
+ nic->duplex[vf] = 0;
+ nic->speed[vf] = 0;
+ ret = 1;
+ break;
+ case NIC_MBOX_MSG_QS_CFG:
+ reg_addr = NIC_PF_QSET_0_127_CFG |
+ (mbx.qs.num << NIC_QS_ID_SHIFT);
+ nic_reg_write(nic, reg_addr, mbx.qs.cfg);
+ break;
+ case NIC_MBOX_MSG_RQ_CFG:
+ reg_addr = NIC_PF_QSET_0_127_RQ_0_7_CFG |
+ (mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
+ (mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
+ nic_reg_write(nic, reg_addr, mbx.rq.cfg);
+ break;
+ case NIC_MBOX_MSG_RQ_BP_CFG:
+ reg_addr = NIC_PF_QSET_0_127_RQ_0_7_BP_CFG |
+ (mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
+ (mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
+ nic_reg_write(nic, reg_addr, mbx.rq.cfg);
+ break;
+ case NIC_MBOX_MSG_RQ_SW_SYNC:
+ ret = nic_rcv_queue_sw_sync(nic);
+ break;
+ case NIC_MBOX_MSG_RQ_DROP_CFG:
+ reg_addr = NIC_PF_QSET_0_127_RQ_0_7_DROP_CFG |
+ (mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
+ (mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
+ nic_reg_write(nic, reg_addr, mbx.rq.cfg);
+ break;
+ case NIC_MBOX_MSG_SQ_CFG:
+ reg_addr = NIC_PF_QSET_0_127_SQ_0_7_CFG |
+ (mbx.sq.qs_num << NIC_QS_ID_SHIFT) |
+ (mbx.sq.sq_num << NIC_Q_NUM_SHIFT);
+ nic_reg_write(nic, reg_addr, mbx.sq.cfg);
+ nic_tx_channel_cfg(nic, mbx.qs.num, mbx.sq.sq_num);
+ break;
+ case NIC_MBOX_MSG_SET_MAC:
+ lmac = mbx.mac.vf_id;
+ bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]);
+ lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]);
+ bgx_set_lmac_mac(nic->node, bgx, lmac, mbx.mac.mac_addr);
+ break;
+ case NIC_MBOX_MSG_SET_MAX_FRS:
+ ret = nic_update_hw_frs(nic, mbx.frs.max_frs,
+ mbx.frs.vf_id);
+ break;
+ case NIC_MBOX_MSG_CPI_CFG:
+ nic_config_cpi(nic, &mbx.cpi_cfg);
+ break;
+ case NIC_MBOX_MSG_RSS_SIZE:
+ nic_send_rss_size(nic, vf);
+ goto unlock;
+ case NIC_MBOX_MSG_RSS_CFG:
+ case NIC_MBOX_MSG_RSS_CFG_CONT:
+ nic_config_rss(nic, &mbx.rss_cfg);
+ break;
+ case NIC_MBOX_MSG_CFG_DONE:
+ /* Last message of VF config msg sequence */
+ nic->vf_enabled[vf] = true;
+ goto unlock;
+ case NIC_MBOX_MSG_SHUTDOWN:
+ /* First msg in VF teardown sequence */
+ nic->vf_enabled[vf] = false;
+ break;
+ case NIC_MBOX_MSG_BGX_STATS:
+ nic_get_bgx_stats(nic, &mbx.bgx_stats);
+ goto unlock;
+ default:
+ dev_err(&nic->pdev->dev,
+ "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg);
+ break;
+ }
+
+ if (!ret)
+ nic_mbx_send_ack(nic, vf);
+ else if (mbx.msg.msg != NIC_MBOX_MSG_READY)
+ nic_mbx_send_nack(nic, vf);
+unlock:
+ nic->mbx_lock[vf] = false;
+}
+
+static void nic_mbx_intr_handler (struct nicpf *nic, int mbx)
+{
+ u64 intr;
+ u8 vf, vf_per_mbx_reg = 64;
+
+ intr = nic_reg_read(nic, NIC_PF_MAILBOX_INT + (mbx << 3));
+ dev_dbg(&nic->pdev->dev, "PF interrupt Mbox%d 0x%llx\n", mbx, intr);
+ for (vf = 0; vf < vf_per_mbx_reg; vf++) {
+ if (intr & (1ULL << vf)) {
+ dev_dbg(&nic->pdev->dev, "Intr from VF %d\n",
+ vf + (mbx * vf_per_mbx_reg));
+ if ((vf + (mbx * vf_per_mbx_reg)) > nic->num_vf_en)
+ break;
+ nic_handle_mbx_intr(nic, vf + (mbx * vf_per_mbx_reg));
+ nic_clear_mbx_intr(nic, vf, mbx);
+ }
+ }
+}
+
+static irqreturn_t nic_mbx0_intr_handler (int irq, void *nic_irq)
+{
+ struct nicpf *nic = (struct nicpf *)nic_irq;
+
+ nic_mbx_intr_handler(nic, 0);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t nic_mbx1_intr_handler (int irq, void *nic_irq)
+{
+ struct nicpf *nic = (struct nicpf *)nic_irq;
+
+ nic_mbx_intr_handler(nic, 1);
+
+ return IRQ_HANDLED;
+}
+
+static int nic_enable_msix(struct nicpf *nic)
+{
+ int i, ret;
+
+ nic->num_vec = NIC_PF_MSIX_VECTORS;
+
+ for (i = 0; i < nic->num_vec; i++)
+ nic->msix_entries[i].entry = i;
+
+ ret = pci_enable_msix(nic->pdev, nic->msix_entries, nic->num_vec);
+ if (ret) {
+ dev_err(&nic->pdev->dev,
+ "Request for #%d msix vectors failed\n",
+ nic->num_vec);
+ return ret;
+ }
+
+ nic->msix_enabled = 1;
+ return 0;
+}
+
+static void nic_disable_msix(struct nicpf *nic)
+{
+ if (nic->msix_enabled) {
+ pci_disable_msix(nic->pdev);
+ nic->msix_enabled = 0;
+ nic->num_vec = 0;
+ }
+}
+
+static void nic_free_all_interrupts(struct nicpf *nic)
+{
+ int irq;
+
+ for (irq = 0; irq < nic->num_vec; irq++) {
+ if (nic->irq_allocated[irq])
+ free_irq(nic->msix_entries[irq].vector, nic);
+ nic->irq_allocated[irq] = false;
+ }
+}
+
+static int nic_register_interrupts(struct nicpf *nic)
+{
+ int ret;
+
+ /* Enable MSI-X */
+ ret = nic_enable_msix(nic);
+ if (ret)
+ return ret;
+
+ /* Register mailbox interrupt handlers */
+ ret = request_irq(nic->msix_entries[NIC_PF_INTR_ID_MBOX0].vector,
+ nic_mbx0_intr_handler, 0, "NIC Mbox0", nic);
+ if (ret)
+ goto fail;
+
+ nic->irq_allocated[NIC_PF_INTR_ID_MBOX0] = true;
+
+ ret = request_irq(nic->msix_entries[NIC_PF_INTR_ID_MBOX1].vector,
+ nic_mbx1_intr_handler, 0, "NIC Mbox1", nic);
+ if (ret)
+ goto fail;
+
+ nic->irq_allocated[NIC_PF_INTR_ID_MBOX1] = true;
+
+ /* Enable mailbox interrupt */
+ nic_enable_mbx_intr(nic);
+ return 0;
+
+fail:
+ dev_err(&nic->pdev->dev, "Request irq failed\n");
+ nic_free_all_interrupts(nic);
+ return ret;
+}
+
+static void nic_unregister_interrupts(struct nicpf *nic)
+{
+ nic_free_all_interrupts(nic);
+ nic_disable_msix(nic);
+}
+
+static int nic_sriov_init(struct pci_dev *pdev, struct nicpf *nic)
+{
+ int pos = 0;
+ int err;
+ u16 total_vf_cnt;
+
+ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+ if (!pos) {
+ dev_err(&pdev->dev, "SRIOV capability is not found in PCIe config space\n");
+ return -ENODEV;
+ }
+
+ pci_read_config_word(pdev, (pos + PCI_SRIOV_TOTAL_VF), &total_vf_cnt);
+ if (total_vf_cnt < nic->num_vf_en)
+ nic->num_vf_en = total_vf_cnt;
+
+ if (!total_vf_cnt)
+ return 0;
+
+ err = pci_enable_sriov(pdev, nic->num_vf_en);
+ if (err) {
+ dev_err(&pdev->dev, "SRIOV enable failed, num VF is %d\n",
+ nic->num_vf_en);
+ nic->num_vf_en = 0;
+ return err;
+ }
+
+ dev_info(&pdev->dev, "SRIOV enabled, number of VF available %d\n",
+ nic->num_vf_en);
+
+ nic->flags |= NIC_SRIOV_ENABLED;
+ return 0;
+}
+
+/* Poll for BGX LMAC link status and update corresponding VF
+ * if there is a change, valid only if internal L2 switch
+ * is not present otherwise VF link is always treated as up
+ */
+static void nic_poll_for_link(struct work_struct *work)
+{
+ union nic_mbx mbx = {};
+ struct nicpf *nic;
+ struct bgx_link_status link;
+ u8 vf, bgx, lmac;
+
+ nic = container_of(work, struct nicpf, dwork.work);
+
+ mbx.link_status.msg = NIC_MBOX_MSG_BGX_LINK_CHANGE;
+
+ for (vf = 0; vf < nic->num_vf_en; vf++) {
+ /* Poll only if VF is UP */
+ if (!nic->vf_enabled[vf])
+ continue;
+
+ /* Get BGX, LMAC indices for the VF */
+ bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
+ lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
+ /* Get interface link status */
+ bgx_get_lmac_link_state(nic->node, bgx, lmac, &link);
+
+ /* Inform VF only if link status changed */
+ if (nic->link[vf] == link.link_up)
+ continue;
+
+ if (!nic->mbx_lock[vf]) {
+ nic->link[vf] = link.link_up;
+ nic->duplex[vf] = link.duplex;
+ nic->speed[vf] = link.speed;
+
+ /* Send a mbox message to VF with current link status */
+ mbx.link_status.link_up = link.link_up;
+ mbx.link_status.duplex = link.duplex;
+ mbx.link_status.speed = link.speed;
+ nic_send_msg_to_vf(nic, vf, &mbx);
+ }
+ }
+ queue_delayed_work(nic->check_link, &nic->dwork, HZ * 2);
+}
+
+static int nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct device *dev = &pdev->dev;
+ struct nicpf *nic;
+ int err;
+
+ BUILD_BUG_ON(sizeof(union nic_mbx) > 16);
+
+ nic = devm_kzalloc(dev, sizeof(*nic), GFP_KERNEL);
+ if (!nic)
+ return -ENOMEM;
+
+ pci_set_drvdata(pdev, nic);
+
+ nic->pdev = pdev;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(dev, "Failed to enable PCI device\n");
+ pci_set_drvdata(pdev, NULL);
+ return err;
+ }
+
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err) {
+ dev_err(dev, "PCI request regions failed 0x%x\n", err);
+ goto err_disable_device;
+ }
+
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(48));
+ if (err) {
+ dev_err(dev, "Unable to get usable DMA configuration\n");
+ goto err_release_regions;
+ }
+
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(48));
+ if (err) {
+ dev_err(dev, "Unable to get 48-bit DMA for consistent allocations\n");
+ goto err_release_regions;
+ }
+
+ /* MAP PF's configuration registers */
+ nic->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0);
+ if (!nic->reg_base) {
+ dev_err(dev, "Cannot map config register space, aborting\n");
+ err = -ENOMEM;
+ goto err_release_regions;
+ }
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &nic->rev_id);
+
+ nic->node = nic_get_node_id(pdev);
+
+ nic_set_lmac_vf_mapping(nic);
+
+ /* Initialize hardware */
+ nic_init_hw(nic);
+
+ /* Set RSS TBL size for each VF */
+ nic->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE;
+
+ /* Register interrupts */
+ err = nic_register_interrupts(nic);
+ if (err)
+ goto err_release_regions;
+
+ /* Configure SRIOV */
+ err = nic_sriov_init(pdev, nic);
+ if (err)
+ goto err_unregister_interrupts;
+
+ /* Register a physical link status poll fn() */
+ nic->check_link = alloc_workqueue("check_link_status",
+ WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+ if (!nic->check_link) {
+ err = -ENOMEM;
+ goto err_disable_sriov;
+ }
+
+ INIT_DELAYED_WORK(&nic->dwork, nic_poll_for_link);
+ queue_delayed_work(nic->check_link, &nic->dwork, 0);
+
+ return 0;
+
+err_disable_sriov:
+ if (nic->flags & NIC_SRIOV_ENABLED)
+ pci_disable_sriov(pdev);
+err_unregister_interrupts:
+ nic_unregister_interrupts(nic);
+err_release_regions:
+ pci_release_regions(pdev);
+err_disable_device:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ return err;
+}
+
+static void nic_remove(struct pci_dev *pdev)
+{
+ struct nicpf *nic = pci_get_drvdata(pdev);
+
+ if (nic->flags & NIC_SRIOV_ENABLED)
+ pci_disable_sriov(pdev);
+
+ if (nic->check_link) {
+ /* Destroy work Queue */
+ cancel_delayed_work(&nic->dwork);
+ flush_workqueue(nic->check_link);
+ destroy_workqueue(nic->check_link);
+ }
+
+ nic_unregister_interrupts(nic);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+static struct pci_driver nic_driver = {
+ .name = DRV_NAME,
+ .id_table = nic_id_table,
+ .probe = nic_probe,
+ .remove = nic_remove,
+};
+
+static int __init nic_init_module(void)
+{
+ pr_info("%s, ver %s\n", DRV_NAME, DRV_VERSION);
+
+ return pci_register_driver(&nic_driver);
+}
+
+static void __exit nic_cleanup_module(void)
+{
+ pci_unregister_driver(&nic_driver);
+}
+
+module_init(nic_init_module);
+module_exit(nic_cleanup_module);
diff --git a/drivers/net/ethernet/cavium/thunder/nic_reg.h b/drivers/net/ethernet/cavium/thunder/nic_reg.h
new file mode 100644
index 000000000000..58197bb2f805
--- /dev/null
+++ b/drivers/net/ethernet/cavium/thunder/nic_reg.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2015 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef NIC_REG_H
+#define NIC_REG_H
+
+#define NIC_PF_REG_COUNT 29573
+#define NIC_VF_REG_COUNT 249
+
+/* Physical function register offsets */
+#define NIC_PF_CFG (0x0000)
+#define NIC_PF_STATUS (0x0010)
+#define NIC_PF_INTR_TIMER_CFG (0x0030)
+#define NIC_PF_BIST_STATUS (0x0040)
+#define NIC_PF_SOFT_RESET (0x0050)
+#define NIC_PF_TCP_TIMER (0x0060)
+#define NIC_PF_BP_CFG (0x0080)
+#define NIC_PF_RRM_CFG (0x0088)
+#define NIC_PF_CQM_CF (0x00A0)
+#define NIC_PF_CNM_CF (0x00A8)
+#define NIC_PF_CNM_STATUS (0x00B0)
+#define NIC_PF_CQ_AVG_CFG (0x00C0)
+#define NIC_PF_RRM_AVG_CFG (0x00C8)
+#define NIC_PF_INTF_0_1_SEND_CFG (0x0200)
+#define NIC_PF_INTF_0_1_BP_CFG (0x0208)
+#define NIC_PF_INTF_0_1_BP_DIS_0_1 (0x0210)
+#define NIC_PF_INTF_0_1_BP_SW_0_1 (0x0220)
+#define NIC_PF_RBDR_BP_STATE_0_3 (0x0240)
+#define NIC_PF_MAILBOX_INT (0x0410)
+#define NIC_PF_MAILBOX_INT_W1S (0x0430)
+#define NIC_PF_MAILBOX_ENA_W1C (0x0450)
+#define NIC_PF_MAILBOX_ENA_W1S (0x0470)
+#define NIC_PF_RX_ETYPE_0_7 (0x0500)
+#define NIC_PF_PKIND_0_15_CFG (0x0600)
+#define NIC_PF_ECC0_FLIP0 (0x1000)
+#define NIC_PF_ECC1_FLIP0 (0x1008)
+#define NIC_PF_ECC2_FLIP0 (0x1010)
+#define NIC_PF_ECC3_FLIP0 (0x1018)
+#define NIC_PF_ECC0_FLIP1 (0x1080)
+#define NIC_PF_ECC1_FLIP1 (0x1088)
+#define NIC_PF_ECC2_FLIP1 (0x1090)
+#define NIC_PF_ECC3_FLIP1 (0x1098)
+#define NIC_PF_ECC0_CDIS (0x1100)
+#define NIC_PF_ECC1_CDIS (0x1108)
+#define NIC_PF_ECC2_CDIS (0x1110)
+#define NIC_PF_ECC3_CDIS (0x1118)
+#define NIC_PF_BIST0_STATUS (0x1280)
+#define NIC_PF_BIST1_STATUS (0x1288)
+#define NIC_PF_BIST2_STATUS (0x1290)
+#define NIC_PF_BIST3_STATUS (0x1298)
+#define NIC_PF_ECC0_SBE_INT (0x2000)
+#define NIC_PF_ECC0_SBE_INT_W1S (0x2008)
+#define NIC_PF_ECC0_SBE_ENA_W1C (0x2010)
+#define NIC_PF_ECC0_SBE_ENA_W1S (0x2018)
+#define NIC_PF_ECC0_DBE_INT (0x2100)
+#define NIC_PF_ECC0_DBE_INT_W1S (0x2108)
+#define NIC_PF_ECC0_DBE_ENA_W1C (0x2110)
+#define NIC_PF_ECC0_DBE_ENA_W1S (0x2118)
+#define NIC_PF_ECC1_SBE_INT (0x2200)
+#define NIC_PF_ECC1_SBE_INT_W1S (0x2208)
+#define NIC_PF_ECC1_SBE_ENA_W1C (0x2210)
+#define NIC_PF_ECC1_SBE_ENA_W1S (0x2218)
+#define NIC_PF_ECC1_DBE_INT (0x2300)
+#define NIC_PF_ECC1_DBE_INT_W1S (0x2308)
+#define NIC_PF_ECC1_DBE_ENA_W1C (0x2310)
+#define NIC_PF_ECC1_DBE_ENA_W1S (0x2318)
+#define NIC_PF_ECC2_SBE_INT (0x2400)
+#define NIC_PF_ECC2_SBE_INT_W1S (0x2408)
+#define NIC_PF_ECC2_SBE_ENA_W1C (0x2410)
+#define NIC_PF_ECC2_SBE_ENA_W1S (0x2418)
+#define NIC_PF_ECC2_DBE_INT (0x2500)
+#define NIC_PF_ECC2_DBE_INT_W1S (0x2508)
+#define NIC_PF_ECC2_DBE_ENA_W1C (0x2510)
+#define NIC_PF_ECC2_DBE_ENA_W1S (0x2518)
+#define NIC_PF_ECC3_SBE_INT (0x2600)
+#define NIC_PF_ECC3_SBE_INT_W1S (0x2608)
+#define NIC_PF_ECC3_SBE_ENA_W1C (0x2610)
+#define NIC_PF_ECC3_SBE_ENA_W1S (0x2618)
+#define NIC_PF_ECC3_DBE_INT (0x2700)
+#define NIC_PF_ECC3_DBE_INT_W1S (0x2708)
+#define NIC_PF_ECC3_DBE_ENA_W1C (0x2710)
+#define NIC_PF_ECC3_DBE_ENA_W1S (0x2718)
+#define NIC_PF_CPI_0_2047_CFG (0x200000)
+#define NIC_PF_RSSI_0_4097_RQ (0x220000)
+#define NIC_PF_LMAC_0_7_CFG (0x240000)
+#define NIC_PF_LMAC_0_7_SW_XOFF (0x242000)
+#define NIC_PF_LMAC_0_7_CREDIT (0x244000)
+#define NIC_PF_CHAN_0_255_TX_CFG (0x400000)
+#define NIC_PF_CHAN_0_255_RX_CFG (0x420000)
+#define NIC_PF_CHAN_0_255_SW_XOFF (0x440000)
+#define NIC_PF_CHAN_0_255_CREDIT (0x460000)
+#define NIC_PF_CHAN_0_255_RX_BP_CFG (0x480000)
+#define NIC_PF_SW_SYNC_RX (0x490000)
+#define NIC_PF_SW_SYNC_RX_DONE (0x490008)
+#define NIC_PF_TL2_0_63_CFG (0x500000)
+#define NIC_PF_TL2_0_63_PRI (0x520000)
+#define NIC_PF_TL2_0_63_SH_STATUS (0x580000)
+#define NIC_PF_TL3A_0_63_CFG (0x5F0000)
+#define NIC_PF_TL3_0_255_CFG (0x600000)
+#define NIC_PF_TL3_0_255_CHAN (0x620000)
+#define NIC_PF_TL3_0_255_PIR (0x640000)
+#define NIC_PF_TL3_0_255_SW_XOFF (0x660000)
+#define NIC_PF_TL3_0_255_CNM_RATE (0x680000)
+#define NIC_PF_TL3_0_255_SH_STATUS (0x6A0000)
+#define NIC_PF_TL4A_0_255_CFG (0x6F0000)
+#define NIC_PF_TL4_0_1023_CFG (0x800000)
+#define NIC_PF_TL4_0_1023_SW_XOFF (0x820000)
+#define NIC_PF_TL4_0_1023_SH_STATUS (0x840000)
+#define NIC_PF_TL4A_0_1023_CNM_RATE (0x880000)
+#define NIC_PF_TL4A_0_1023_CNM_STATUS (0x8A0000)
+#define NIC_PF_VF_0_127_MAILBOX_0_1 (0x20002030)
+#define NIC_PF_VNIC_0_127_TX_STAT_0_4 (0x20004000)
+#define NIC_PF_VNIC_0_127_RX_STAT_0_13 (0x20004100)
+#define NIC_PF_QSET_0_127_LOCK_0_15 (0x20006000)
+#define NIC_PF_QSET_0_127_CFG (0x20010000)
+#define NIC_PF_QSET_0_127_RQ_0_7_CFG (0x20010400)
+#define NIC_PF_QSET_0_127_RQ_0_7_DROP_CFG (0x20010420)
+#define NIC_PF_QSET_0_127_RQ_0_7_BP_CFG (0x20010500)
+#define NIC_PF_QSET_0_127_RQ_0_7_STAT_0_1 (0x20010600)
+#define NIC_PF_QSET_0_127_SQ_0_7_CFG (0x20010C00)
+#define NIC_PF_QSET_0_127_SQ_0_7_CFG2 (0x20010C08)
+#define NIC_PF_QSET_0_127_SQ_0_7_STAT_0_1 (0x20010D00)
+
+#define NIC_PF_MSIX_VEC_0_18_ADDR (0x000000)
+#define NIC_PF_MSIX_VEC_0_CTL (0x000008)
+#define NIC_PF_MSIX_PBA_0 (0x0F0000)
+
+/* Virtual function register offsets */
+#define NIC_VNIC_CFG (0x000020)
+#define NIC_VF_PF_MAILBOX_0_1 (0x000130)
+#define NIC_VF_INT (0x000200)
+#define NIC_VF_INT_W1S (0x000220)
+#define NIC_VF_ENA_W1C (0x000240)
+#define NIC_VF_ENA_W1S (0x000260)
+
+#define NIC_VNIC_RSS_CFG (0x0020E0)
+#define NIC_VNIC_RSS_KEY_0_4 (0x002200)
+#define NIC_VNIC_TX_STAT_0_4 (0x004000)
+#define NIC_VNIC_RX_STAT_0_13 (0x004100)
+#define NIC_QSET_RQ_GEN_CFG (0x010010)
+
+#define NIC_QSET_CQ_0_7_CFG (0x010400)
+#define NIC_QSET_CQ_0_7_CFG2 (0x010408)
+#define NIC_QSET_CQ_0_7_THRESH (0x010410)
+#define NIC_QSET_CQ_0_7_BASE (0x010420)
+#define NIC_QSET_CQ_0_7_HEAD (0x010428)
+#define NIC_QSET_CQ_0_7_TAIL (0x010430)
+#define NIC_QSET_CQ_0_7_DOOR (0x010438)
+#define NIC_QSET_CQ_0_7_STATUS (0x010440)
+#define NIC_QSET_CQ_0_7_STATUS2 (0x010448)
+#define NIC_QSET_CQ_0_7_DEBUG (0x010450)
+
+#define NIC_QSET_RQ_0_7_CFG (0x010600)
+#define NIC_QSET_RQ_0_7_STAT_0_1 (0x010700)
+
+#define NIC_QSET_SQ_0_7_CFG (0x010800)
+#define NIC_QSET_SQ_0_7_THRESH (0x010810)
+#define NIC_QSET_SQ_0_7_BASE (0x010820)
+#define NIC_QSET_SQ_0_7_HEAD (0x010828)
+#define NIC_QSET_SQ_0_7_TAIL (0x010830)
+#define NIC_QSET_SQ_0_7_DOOR (0x010838)
+#define NIC_QSET_SQ_0_7_STATUS (0x010840)
+#define NIC_QSET_SQ_0_7_DEBUG (0x010848)
+#define NIC_QSET_SQ_0_7_CNM_CHG (0x010860)
+#define NIC_QSET_SQ_0_7_STAT_0_1 (0x010900)
+
+#define NIC_QSET_RBDR_0_1_CFG (0x010C00)
+#define NIC_QSET_RBDR_0_1_THRESH (0x010C10)
+#define NIC_QSET_RBDR_0_1_BASE (0x010C20)
+#define NIC_QSET_RBDR_0_1_HEAD (0x010C28)
+#define NIC_QSET_RBDR_0_1_TAIL (0x010C30)
+#define NIC_QSET_RBDR_0_1_DOOR (0x010C38)
+#define NIC_QSET_RBDR_0_1_STATUS0 (0x010C40)
+#define NIC_QSET_RBDR_0_1_STATUS1 (0x010C48)
+#define NIC_QSET_RBDR_0_1_PREFETCH_STATUS (0x010C50)
+
+#define NIC_VF_MSIX_VECTOR_0_19_ADDR (0x000000)
+#define NIC_VF_MSIX_VECTOR_0_19_CTL (0x000008)
+#define NIC_VF_MSIX_PBA (0x0F0000)
+
+/* Offsets within registers */
+#define NIC_MSIX_VEC_SHIFT 4
+#define NIC_Q_NUM_SHIFT 18
+#define NIC_QS_ID_SHIFT 21
+#define NIC_VF_NUM_SHIFT 21
+
+/* Port kind configuration register */
+struct pkind_cfg {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 reserved_42_63:22;
+ u64 hdr_sl:5; /* Header skip length */
+ u64 rx_hdr:3; /* TNS Receive header present */
+ u64 lenerr_en:1;/* L2 length error check enable */
+ u64 reserved_32_32:1;
+ u64 maxlen:16; /* Max frame size */
+ u64 minlen:16; /* Min frame size */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 minlen:16;
+ u64 maxlen:16;
+ u64 reserved_32_32:1;
+ u64 lenerr_en:1;
+ u64 rx_hdr:3;
+ u64 hdr_sl:5;
+ u64 reserved_42_63:22;
+#endif
+};
+
+#endif /* NIC_REG_H */
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
new file mode 100644
index 000000000000..16bd2d772db9
--- /dev/null
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
@@ -0,0 +1,600 @@
+/*
+ * Copyright (C) 2015 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+/* ETHTOOL Support for VNIC_VF Device*/
+
+#include <linux/pci.h>
+
+#include "nic_reg.h"
+#include "nic.h"
+#include "nicvf_queues.h"
+#include "q_struct.h"
+#include "thunder_bgx.h"
+
+#define DRV_NAME "thunder-nicvf"
+#define DRV_VERSION "1.0"
+
+struct nicvf_stat {
+ char name[ETH_GSTRING_LEN];
+ unsigned int index;
+};
+
+#define NICVF_HW_STAT(stat) { \
+ .name = #stat, \
+ .index = offsetof(struct nicvf_hw_stats, stat) / sizeof(u64), \
+}
+
+#define NICVF_DRV_STAT(stat) { \
+ .name = #stat, \
+ .index = offsetof(struct nicvf_drv_stats, stat) / sizeof(u64), \
+}
+
+static const struct nicvf_stat nicvf_hw_stats[] = {
+ NICVF_HW_STAT(rx_bytes_ok),
+ NICVF_HW_STAT(rx_ucast_frames_ok),
+ NICVF_HW_STAT(rx_bcast_frames_ok),
+ NICVF_HW_STAT(rx_mcast_frames_ok),
+ NICVF_HW_STAT(rx_fcs_errors),
+ NICVF_HW_STAT(rx_l2_errors),
+ NICVF_HW_STAT(rx_drop_red),
+ NICVF_HW_STAT(rx_drop_red_bytes),
+ NICVF_HW_STAT(rx_drop_overrun),
+ NICVF_HW_STAT(rx_drop_overrun_bytes),
+ NICVF_HW_STAT(rx_drop_bcast),
+ NICVF_HW_STAT(rx_drop_mcast),
+ NICVF_HW_STAT(rx_drop_l3_bcast),
+ NICVF_HW_STAT(rx_drop_l3_mcast),
+ NICVF_HW_STAT(tx_bytes_ok),
+ NICVF_HW_STAT(tx_ucast_frames_ok),
+ NICVF_HW_STAT(tx_bcast_frames_ok),
+ NICVF_HW_STAT(tx_mcast_frames_ok),
+};
+
+static const struct nicvf_stat nicvf_drv_stats[] = {
+ NICVF_DRV_STAT(rx_frames_ok),
+ NICVF_DRV_STAT(rx_frames_64),
+ NICVF_DRV_STAT(rx_frames_127),
+ NICVF_DRV_STAT(rx_frames_255),
+ NICVF_DRV_STAT(rx_frames_511),
+ NICVF_DRV_STAT(rx_frames_1023),
+ NICVF_DRV_STAT(rx_frames_1518),
+ NICVF_DRV_STAT(rx_frames_jumbo),
+ NICVF_DRV_STAT(rx_drops),
+ NICVF_DRV_STAT(tx_frames_ok),
+ NICVF_DRV_STAT(tx_busy),
+ NICVF_DRV_STAT(tx_tso),
+ NICVF_DRV_STAT(tx_drops),
+};
+
+static const struct nicvf_stat nicvf_queue_stats[] = {
+ { "bytes", 0 },
+ { "frames", 1 },
+};
+
+static const unsigned int nicvf_n_hw_stats = ARRAY_SIZE(nicvf_hw_stats);
+static const unsigned int nicvf_n_drv_stats = ARRAY_SIZE(nicvf_drv_stats);
+static const unsigned int nicvf_n_queue_stats = ARRAY_SIZE(nicvf_queue_stats);
+
+static int nicvf_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *cmd)
+{
+ struct nicvf *nic = netdev_priv(netdev);
+
+ cmd->supported = 0;
+ cmd->transceiver = XCVR_EXTERNAL;
+ if (nic->speed <= 1000) {
+ cmd->port = PORT_MII;
+ cmd->autoneg = AUTONEG_ENABLE;
+ } else {
+ cmd->port = PORT_FIBRE;
+ cmd->autoneg = AUTONEG_DISABLE;
+ }
+ cmd->duplex = nic->duplex;
+ ethtool_cmd_speed_set(cmd, nic->speed);
+
+ return 0;
+}
+
+static void nicvf_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *info)
+{
+ struct nicvf *nic = netdev_priv(netdev);
+
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, pci_name(nic->pdev), sizeof(info->bus_info));
+}
+
+static u32 nicvf_get_msglevel(struct net_device *netdev)
+{
+ struct nicvf *nic = netdev_priv(netdev);
+
+ return nic->msg_enable;
+}
+
+static void nicvf_set_msglevel(struct net_device *netdev, u32 lvl)
+{
+ struct nicvf *nic = netdev_priv(netdev);
+
+ nic->msg_enable = lvl;
+}
+
+static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
+{
+ int stats, qidx;
+
+ if (sset != ETH_SS_STATS)
+ return;
+
+ for (stats = 0; stats < nicvf_n_hw_stats; stats++) {
+ memcpy(data, nicvf_hw_stats[stats].name, ETH_GSTRING_LEN);
+ data += ETH_GSTRING_LEN;
+ }
+
+ for (stats = 0; stats < nicvf_n_drv_stats; stats++) {
+ memcpy(data, nicvf_drv_stats[stats].name, ETH_GSTRING_LEN);
+ data += ETH_GSTRING_LEN;
+ }
+
+ for (qidx = 0; qidx < MAX_RCV_QUEUES_PER_QS; qidx++) {
+ for (stats = 0; stats < nicvf_n_queue_stats; stats++) {
+ sprintf(data, "rxq%d: %s", qidx,
+ nicvf_queue_stats[stats].name);
+ data += ETH_GSTRING_LEN;
+ }
+ }
+
+ for (qidx = 0; qidx < MAX_SND_QUEUES_PER_QS; qidx++) {
+ for (stats = 0; stats < nicvf_n_queue_stats; stats++) {
+ sprintf(data, "txq%d: %s", qidx,
+ nicvf_queue_stats[stats].name);
+ data += ETH_GSTRING_LEN;
+ }
+ }
+
+ for (stats = 0; stats < BGX_RX_STATS_COUNT; stats++) {
+ sprintf(data, "bgx_rxstat%d: ", stats);
+ data += ETH_GSTRING_LEN;
+ }
+
+ for (stats = 0; stats < BGX_TX_STATS_COUNT; stats++) {
+ sprintf(data, "bgx_txstat%d: ", stats);
+ data += ETH_GSTRING_LEN;
+ }
+}
+
+static int nicvf_get_sset_count(struct net_device *netdev, int sset)
+{
+ if (sset != ETH_SS_STATS)
+ return -EINVAL;
+
+ return nicvf_n_hw_stats + nicvf_n_drv_stats +
+ (nicvf_n_queue_stats *
+ (MAX_RCV_QUEUES_PER_QS + MAX_SND_QUEUES_PER_QS)) +
+ BGX_RX_STATS_COUNT + BGX_TX_STATS_COUNT;
+}
+
+static void nicvf_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct nicvf *nic = netdev_priv(netdev);
+ int stat, qidx;
+
+ nicvf_update_stats(nic);
+
+ /* Update LMAC stats */
+ nicvf_update_lmac_stats(nic);
+
+ for (stat = 0; stat < nicvf_n_hw_stats; stat++)
+ *(data++) = ((u64 *)&nic->stats)
+ [nicvf_hw_stats[stat].index];
+ for (stat = 0; stat < nicvf_n_drv_stats; stat++)
+ *(data++) = ((u64 *)&nic->drv_stats)
+ [nicvf_drv_stats[stat].index];
+
+ for (qidx = 0; qidx < MAX_RCV_QUEUES_PER_QS; qidx++) {
+ for (stat = 0; stat < nicvf_n_queue_stats; stat++)
+ *(data++) = ((u64 *)&nic->qs->rq[qidx].stats)
+ [nicvf_queue_stats[stat].index];
+ }
+
+ for (qidx = 0; qidx < MAX_SND_QUEUES_PER_QS; qidx++) {
+ for (stat = 0; stat < nicvf_n_queue_stats; stat++)
+ *(data++) = ((u64 *)&nic->qs->sq[qidx].stats)
+ [nicvf_queue_stats[stat].index];
+ }
+
+ for (stat = 0; stat < BGX_RX_STATS_COUNT; stat++)
+ *(data++) = nic->bgx_stats.rx_stats[stat];
+ for (stat = 0; stat < BGX_TX_STATS_COUNT; stat++)
+ *(data++) = nic->bgx_stats.tx_stats[stat];
+}
+
+static int nicvf_get_regs_len(struct net_device *dev)
+{
+ return sizeof(u64) * NIC_VF_REG_COUNT;
+}
+
+static void nicvf_get_regs(struct net_device *dev,
+ struct ethtool_regs *regs, void *reg)
+{
+ struct nicvf *nic = netdev_priv(dev);
+ u64 *p = (u64 *)reg;
+ u64 reg_offset;
+ int mbox, key, stat, q;
+ int i = 0;
+
+ regs->version = 0;
+ memset(p, 0, NIC_VF_REG_COUNT);
+
+ p[i++] = nicvf_reg_read(nic, NIC_VNIC_CFG);
+ /* Mailbox registers */
+ for (mbox = 0; mbox < NIC_PF_VF_MAILBOX_SIZE; mbox++)
+ p[i++] = nicvf_reg_read(nic,
+ NIC_VF_PF_MAILBOX_0_1 | (mbox << 3));
+
+ p[i++] = nicvf_reg_read(nic, NIC_VF_INT);
+ p[i++] = nicvf_reg_read(nic, NIC_VF_INT_W1S);
+ p[i++] = nicvf_reg_read(nic, NIC_VF_ENA_W1C);
+ p[i++] = nicvf_reg_read(nic, NIC_VF_ENA_W1S);
+ p[i++] = nicvf_reg_read(nic, NIC_VNIC_RSS_CFG);
+
+ for (key = 0; key < RSS_HASH_KEY_SIZE; key++)
+ p[i++] = nicvf_reg_read(nic, NIC_VNIC_RSS_KEY_0_4 | (key << 3));
+
+ /* Tx/Rx statistics */
+ for (stat = 0; stat < TX_STATS_ENUM_LAST; stat++)
+ p[i++] = nicvf_reg_read(nic,
+ NIC_VNIC_TX_STAT_0_4 | (stat << 3));
+
+ for (i = 0; i < RX_STATS_ENUM_LAST; i++)
+ p[i++] = nicvf_reg_read(nic,
+ NIC_VNIC_RX_STAT_0_13 | (stat << 3));
+
+ p[i++] = nicvf_reg_read(nic, NIC_QSET_RQ_GEN_CFG);
+
+ /* All completion queue's registers */
+ for (q = 0; q < MAX_CMP_QUEUES_PER_QS; q++) {
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_CFG, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_CFG2, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_THRESH, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_BASE, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_HEAD, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_TAIL, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_DOOR, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS2, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_DEBUG, q);
+ }
+
+ /* All receive queue's registers */
+ for (q = 0; q < MAX_RCV_QUEUES_PER_QS; q++) {
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RQ_0_7_CFG, q);
+ p[i++] = nicvf_queue_reg_read(nic,
+ NIC_QSET_RQ_0_7_STAT_0_1, q);
+ reg_offset = NIC_QSET_RQ_0_7_STAT_0_1 | (1 << 3);
+ p[i++] = nicvf_queue_reg_read(nic, reg_offset, q);
+ }
+
+ for (q = 0; q < MAX_SND_QUEUES_PER_QS; q++) {
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_CFG, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_THRESH, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_BASE, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_HEAD, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_TAIL, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_DOOR, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_STATUS, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_DEBUG, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_CNM_CHG, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_STAT_0_1, q);
+ reg_offset = NIC_QSET_SQ_0_7_STAT_0_1 | (1 << 3);
+ p[i++] = nicvf_queue_reg_read(nic, reg_offset, q);
+ }
+
+ for (q = 0; q < MAX_RCV_BUF_DESC_RINGS_PER_QS; q++) {
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_CFG, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_THRESH, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_BASE, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_HEAD, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_TAIL, q);
+ p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_DOOR, q);
+ p[i++] = nicvf_queue_reg_read(nic,
+ NIC_QSET_RBDR_0_1_STATUS0, q);
+ p[i++] = nicvf_queue_reg_read(nic,
+ NIC_QSET_RBDR_0_1_STATUS1, q);
+ reg_offset = NIC_QSET_RBDR_0_1_PREFETCH_STATUS;
+ p[i++] = nicvf_queue_reg_read(nic, reg_offset, q);
+ }
+}
+
+static int nicvf_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *cmd)
+{
+ struct nicvf *nic = netdev_priv(netdev);
+
+ cmd->rx_coalesce_usecs = nic->cq_coalesce_usecs;
+ return 0;
+}
+
+static void nicvf_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct nicvf *nic = netdev_priv(netdev);
+ struct queue_set *qs = nic->qs;
+
+ ring->rx_max_pending = MAX_RCV_BUF_COUNT;
+ ring->rx_pending = qs->rbdr_len;
+ ring->tx_max_pending = MAX_SND_QUEUE_LEN;
+ ring->tx_pending = qs->sq_len;
+}
+
+static int nicvf_get_rss_hash_opts(struct nicvf *nic,
+ struct ethtool_rxnfc *info)
+{
+ info->data = 0;
+
+ switch (info->flow_type) {
+ case TCP_V4_FLOW:
+ case TCP_V6_FLOW:
+ case UDP_V4_FLOW:
+ case UDP_V6_FLOW:
+ case SCTP_V4_FLOW:
+ case SCTP_V6_FLOW:
+ info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ case IPV4_FLOW:
+ case IPV6_FLOW:
+ info->data |= RXH_IP_SRC | RXH_IP_DST;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int nicvf_get_rxnfc(struct net_device *dev,
+ struct ethtool_rxnfc *info, u32 *rules)
+{
+ struct nicvf *nic = netdev_priv(dev);
+ int ret = -EOPNOTSUPP;
+
+ switch (info->cmd) {
+ case ETHTOOL_GRXRINGS:
+ info->data = nic->qs->rq_cnt;
+ ret = 0;
+ break;
+ case ETHTOOL_GRXFH:
+ return nicvf_get_rss_hash_opts(nic, info);
+ default:
+ break;
+ }
+ return ret;
+}
+
+static int nicvf_set_rss_hash_opts(struct nicvf *nic,
+ struct ethtool_rxnfc *info)
+{
+ struct nicvf_rss_info *rss = &nic->rss_info;
+ u64 rss_cfg = nicvf_reg_read(nic, NIC_VNIC_RSS_CFG);
+
+ if (!rss->enable)
+ netdev_err(nic->netdev,
+ "RSS is disabled, hash cannot be set\n");
+
+ netdev_info(nic->netdev, "Set RSS flow type = %d, data = %lld\n",
+ info->flow_type, info->data);
+
+ if (!(info->data & RXH_IP_SRC) || !(info->data & RXH_IP_DST))
+ return -EINVAL;
+
+ switch (info->flow_type) {
+ case TCP_V4_FLOW:
+ case TCP_V6_FLOW:
+ switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+ case 0:
+ rss_cfg &= ~(1ULL << RSS_HASH_TCP);
+ break;
+ case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+ rss_cfg |= (1ULL << RSS_HASH_TCP);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case UDP_V4_FLOW:
+ case UDP_V6_FLOW:
+ switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+ case 0:
+ rss_cfg &= ~(1ULL << RSS_HASH_UDP);
+ break;
+ case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+ rss_cfg |= (1ULL << RSS_HASH_UDP);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case SCTP_V4_FLOW:
+ case SCTP_V6_FLOW:
+ switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+ case 0:
+ rss_cfg &= ~(1ULL << RSS_HASH_L4ETC);
+ break;
+ case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+ rss_cfg |= (1ULL << RSS_HASH_L4ETC);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case IPV4_FLOW:
+ case IPV6_FLOW:
+ rss_cfg = RSS_HASH_IP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ nicvf_reg_write(nic, NIC_VNIC_RSS_CFG, rss_cfg);
+ return 0;
+}
+
+static int nicvf_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
+{
+ struct nicvf *nic = netdev_priv(dev);
+
+ switch (info->cmd) {
+ case ETHTOOL_SRXFH:
+ return nicvf_set_rss_hash_opts(nic, info);
+ default:
+ break;
+ }
+ return -EOPNOTSUPP;
+}
+
+static u32 nicvf_get_rxfh_key_size(struct net_device *netdev)
+{
+ return RSS_HASH_KEY_SIZE * sizeof(u64);
+}
+
+static u32 nicvf_get_rxfh_indir_size(struct net_device *dev)
+{
+ struct nicvf *nic = netdev_priv(dev);
+
+ return nic->rss_info.rss_size;
+}
+
+static int nicvf_get_rxfh(struct net_device *dev, u32 *indir, u8 *hkey,
+ u8 *hfunc)
+{
+ struct nicvf *nic = netdev_priv(dev);
+ struct nicvf_rss_info *rss = &nic->rss_info;
+ int idx;
+
+ if (indir) {
+ for (idx = 0; idx < rss->rss_size; idx++)
+ indir[idx] = rss->ind_tbl[idx];
+ }
+
+ if (hkey)
+ memcpy(hkey, rss->key, RSS_HASH_KEY_SIZE * sizeof(u64));
+
+ if (hfunc)
+ *hfunc = ETH_RSS_HASH_TOP;
+
+ return 0;
+}
+
+static int nicvf_set_rxfh(struct net_device *dev, const u32 *indir,
+ const u8 *hkey, u8 hfunc)
+{
+ struct nicvf *nic = netdev_priv(dev);
+ struct nicvf_rss_info *rss = &nic->rss_info;
+ int idx;
+
+ if ((nic->qs->rq_cnt <= 1) || (nic->cpi_alg != CPI_ALG_NONE)) {
+ rss->enable = false;
+ rss->hash_bits = 0;
+ return -EIO;
+ }
+
+ /* We do not allow change in unsupported parameters */
+ if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ return -EOPNOTSUPP;
+
+ rss->enable = true;
+ if (indir) {
+ for (idx = 0; idx < rss->rss_size; idx++)
+ rss->ind_tbl[idx] = indir[idx];
+ }
+
+ if (hkey) {
+ memcpy(rss->key, hkey, RSS_HASH_KEY_SIZE * sizeof(u64));
+ nicvf_set_rss_key(nic);
+ }
+
+ nicvf_config_rss(nic);
+ return 0;
+}
+
+/* Get no of queues device supports and current queue count */
+static void nicvf_get_channels(struct net_device *dev,
+ struct ethtool_channels *channel)
+{
+ struct nicvf *nic = netdev_priv(dev);
+
+ memset(channel, 0, sizeof(*channel));
+
+ channel->max_rx = MAX_RCV_QUEUES_PER_QS;
+ channel->max_tx = MAX_SND_QUEUES_PER_QS;
+
+ channel->rx_count = nic->qs->rq_cnt;
+ channel->tx_count = nic->qs->sq_cnt;
+}
+
+/* Set no of Tx, Rx queues to be used */
+static int nicvf_set_channels(struct net_device *dev,
+ struct ethtool_channels *channel)
+{
+ struct nicvf *nic = netdev_priv(dev);
+ int err = 0;
+
+ if (!channel->rx_count || !channel->tx_count)
+ return -EINVAL;
+ if (channel->rx_count > MAX_RCV_QUEUES_PER_QS)
+ return -EINVAL;
+ if (channel->tx_count > MAX_SND_QUEUES_PER_QS)
+ return -EINVAL;
+
+ nic->qs->rq_cnt = channel->rx_count;
+ nic->qs->sq_cnt = channel->tx_count;
+ nic->qs->cq_cnt = max(nic->qs->rq_cnt, nic->qs->sq_cnt);
+
+ err = nicvf_set_real_num_queues(dev, nic->qs->sq_cnt, nic->qs->rq_cnt);
+ if (err)
+ return err;
+
+ if (!netif_running(dev))
+ return err;
+
+ nicvf_stop(dev);
+ nicvf_open(dev);
+ netdev_info(dev, "Setting num Tx rings to %d, Rx rings to %d success\n",
+ nic->qs->sq_cnt, nic->qs->rq_cnt);
+
+ return err;
+}
+
+static const struct ethtool_ops nicvf_ethtool_ops = {
+ .get_settings = nicvf_get_settings,
+ .get_link = ethtool_op_get_link,
+ .get_drvinfo = nicvf_get_drvinfo,
+ .get_msglevel = nicvf_get_msglevel,
+ .set_msglevel = nicvf_set_msglevel,
+ .get_strings = nicvf_get_strings,
+ .get_sset_count = nicvf_get_sset_count,
+ .get_ethtool_stats = nicvf_get_ethtool_stats,
+ .get_regs_len = nicvf_get_regs_len,
+ .get_regs = nicvf_get_regs,
+ .get_coalesce = nicvf_get_coalesce,
+ .get_ringparam = nicvf_get_ringparam,
+ .get_rxnfc = nicvf_get_rxnfc,
+ .set_rxnfc = nicvf_set_rxnfc,
+ .get_rxfh_key_size = nicvf_get_rxfh_key_size,
+ .get_rxfh_indir_size = nicvf_get_rxfh_indir_size,
+ .get_rxfh = nicvf_get_rxfh,
+ .set_rxfh = nicvf_set_rxfh,
+ .get_channels = nicvf_get_channels,
+ .set_channels = nicvf_set_channels,
+ .get_ts_info = ethtool_op_get_ts_info,
+};
+
+void nicvf_set_ethtool_ops(struct net_device *netdev)
+{
+ netdev->ethtool_ops = &nicvf_ethtool_ops;
+}
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
new file mode 100644
index 000000000000..8b119a035b7e
--- /dev/null
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
@@ -0,0 +1,1341 @@
+/*
+ * Copyright (C) 2015 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/log2.h>
+#include <linux/prefetch.h>
+#include <linux/irq.h>
+
+#include "nic_reg.h"
+#include "nic.h"
+#include "nicvf_queues.h"
+#include "thunder_bgx.h"
+
+#define DRV_NAME "thunder-nicvf"
+#define DRV_VERSION "1.0"
+
+/* Supported devices */
+static const struct pci_device_id nicvf_id_table[] = {
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM,
+ PCI_DEVICE_ID_THUNDER_NIC_VF,
+ PCI_VENDOR_ID_CAVIUM, 0xA11E) },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM,
+ PCI_DEVICE_ID_THUNDER_PASS1_NIC_VF,
+ PCI_VENDOR_ID_CAVIUM, 0xA11E) },
+ { 0, } /* end of table */
+};
+
+MODULE_AUTHOR("Sunil Goutham");
+MODULE_DESCRIPTION("Cavium Thunder NIC Virtual Function Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, nicvf_id_table);
+
+static int debug = 0x00;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug message level bitmap");
+
+static int cpi_alg = CPI_ALG_NONE;
+module_param(cpi_alg, int, S_IRUGO);
+MODULE_PARM_DESC(cpi_alg,
+ "PFC algorithm (0=none, 1=VLAN, 2=VLAN16, 3=IP Diffserv)");
+
+static inline void nicvf_set_rx_frame_cnt(struct nicvf *nic,
+ struct sk_buff *skb)
+{
+ if (skb->len <= 64)
+ nic->drv_stats.rx_frames_64++;
+ else if (skb->len <= 127)
+ nic->drv_stats.rx_frames_127++;
+ else if (skb->len <= 255)
+ nic->drv_stats.rx_frames_255++;
+ else if (skb->len <= 511)
+ nic->drv_stats.rx_frames_511++;
+ else if (skb->len <= 1023)
+ nic->drv_stats.rx_frames_1023++;
+ else if (skb->len <= 1518)
+ nic->drv_stats.rx_frames_1518++;
+ else
+ nic->drv_stats.rx_frames_jumbo++;
+}
+
+/* The Cavium ThunderX network controller can *only* be found in SoCs
+ * containing the ThunderX ARM64 CPU implementation. All accesses to the device
+ * registers on this platform are implicitly strongly ordered with respect
+ * to memory accesses. So writeq_relaxed() and readq_relaxed() are safe to use
+ * with no memory barriers in this driver. The readq()/writeq() functions add
+ * explicit ordering operation which in this case are redundant, and only
+ * add overhead.
+ */
+
+/* Register read/write APIs */
+void nicvf_reg_write(struct nicvf *nic, u64 offset, u64 val)
+{
+ writeq_relaxed(val, nic->reg_base + offset);
+}
+
+u64 nicvf_reg_read(struct nicvf *nic, u64 offset)
+{
+ return readq_relaxed(nic->reg_base + offset);
+}
+
+void nicvf_queue_reg_write(struct nicvf *nic, u64 offset,
+ u64 qidx, u64 val)
+{
+ void __iomem *addr = nic->reg_base + offset;
+
+ writeq_relaxed(val, addr + (qidx << NIC_Q_NUM_SHIFT));
+}
+
+u64 nicvf_queue_reg_read(struct nicvf *nic, u64 offset, u64 qidx)
+{
+ void __iomem *addr = nic->reg_base + offset;
+
+ return readq_relaxed(addr + (qidx << NIC_Q_NUM_SHIFT));
+}
+
+/* VF -> PF mailbox communication */
+
+static void nicvf_write_to_mbx(struct nicvf *nic, union nic_mbx *mbx)
+{
+ u64 *msg = (u64 *)mbx;
+
+ nicvf_reg_write(nic, NIC_VF_PF_MAILBOX_0_1 + 0, msg[0]);
+ nicvf_reg_write(nic, NIC_VF_PF_MAILBOX_0_1 + 8, msg[1]);
+}
+
+int nicvf_send_msg_to_pf(struct nicvf *nic, union nic_mbx *mbx)
+{
+ int timeout = NIC_MBOX_MSG_TIMEOUT;
+ int sleep = 10;
+
+ nic->pf_acked = false;
+ nic->pf_nacked = false;
+
+ nicvf_write_to_mbx(nic, mbx);
+
+ /* Wait for previous message to be acked, timeout 2sec */
+ while (!nic->pf_acked) {
+ if (nic->pf_nacked)
+ return -EINVAL;
+ msleep(sleep);
+ if (nic->pf_acked)
+ break;
+ timeout -= sleep;
+ if (!timeout) {
+ netdev_err(nic->netdev,
+ "PF didn't ack to mbox msg %d from VF%d\n",
+ (mbx->msg.msg & 0xFF), nic->vf_id);
+ return -EBUSY;
+ }
+ }
+ return 0;
+}
+
+/* Checks if VF is able to comminicate with PF
+* and also gets the VNIC number this VF is associated to.
+*/
+static int nicvf_check_pf_ready(struct nicvf *nic)
+{
+ int timeout = 5000, sleep = 20;
+ union nic_mbx mbx = {};
+
+ mbx.msg.msg = NIC_MBOX_MSG_READY;
+
+ nic->pf_ready_to_rcv_msg = false;
+
+ nicvf_write_to_mbx(nic, &mbx);
+
+ while (!nic->pf_ready_to_rcv_msg) {
+ msleep(sleep);
+ if (nic->pf_ready_to_rcv_msg)
+ break;
+ timeout -= sleep;
+ if (!timeout) {
+ netdev_err(nic->netdev,
+ "PF didn't respond to READY msg\n");
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void nicvf_read_bgx_stats(struct nicvf *nic, struct bgx_stats_msg *bgx)
+{
+ if (bgx->rx)
+ nic->bgx_stats.rx_stats[bgx->idx] = bgx->stats;
+ else
+ nic->bgx_stats.tx_stats[bgx->idx] = bgx->stats;
+}
+
+static void nicvf_handle_mbx_intr(struct nicvf *nic)
+{
+ union nic_mbx mbx = {};
+ u64 *mbx_data;
+ u64 mbx_addr;
+ int i;
+
+ mbx_addr = NIC_VF_PF_MAILBOX_0_1;
+ mbx_data = (u64 *)&mbx;
+
+ for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) {
+ *mbx_data = nicvf_reg_read(nic, mbx_addr);
+ mbx_data++;
+ mbx_addr += sizeof(u64);
+ }
+
+ netdev_dbg(nic->netdev, "Mbox message: msg: 0x%x\n", mbx.msg.msg);
+ switch (mbx.msg.msg) {
+ case NIC_MBOX_MSG_READY:
+ nic->pf_ready_to_rcv_msg = true;
+ nic->vf_id = mbx.nic_cfg.vf_id & 0x7F;
+ nic->tns_mode = mbx.nic_cfg.tns_mode & 0x7F;
+ nic->node = mbx.nic_cfg.node_id;
+ if (!nic->set_mac_pending)
+ ether_addr_copy(nic->netdev->dev_addr,
+ mbx.nic_cfg.mac_addr);
+ nic->link_up = false;
+ nic->duplex = 0;
+ nic->speed = 0;
+ break;
+ case NIC_MBOX_MSG_ACK:
+ nic->pf_acked = true;
+ break;
+ case NIC_MBOX_MSG_NACK:
+ nic->pf_nacked = true;
+ break;
+ case NIC_MBOX_MSG_RSS_SIZE:
+ nic->rss_info.rss_size = mbx.rss_size.ind_tbl_size;
+ nic->pf_acked = true;
+ break;
+ case NIC_MBOX_MSG_BGX_STATS:
+ nicvf_read_bgx_stats(nic, &mbx.bgx_stats);
+ nic->pf_acked = true;
+ nic->bgx_stats_acked = true;
+ break;
+ case NIC_MBOX_MSG_BGX_LINK_CHANGE:
+ nic->pf_acked = true;
+ nic->link_up = mbx.link_status.link_up;
+ nic->duplex = mbx.link_status.duplex;
+ nic->speed = mbx.link_status.speed;
+ if (nic->link_up) {
+ netdev_info(nic->netdev, "%s: Link is Up %d Mbps %s\n",
+ nic->netdev->name, nic->speed,
+ nic->duplex == DUPLEX_FULL ?
+ "Full duplex" : "Half duplex");
+ netif_carrier_on(nic->netdev);
+ netif_tx_wake_all_queues(nic->netdev);
+ } else {
+ netdev_info(nic->netdev, "%s: Link is Down\n",
+ nic->netdev->name);
+ netif_carrier_off(nic->netdev);
+ netif_tx_stop_all_queues(nic->netdev);
+ }
+ break;
+ default:
+ netdev_err(nic->netdev,
+ "Invalid message from PF, msg 0x%x\n", mbx.msg.msg);
+ break;
+ }
+ nicvf_clear_intr(nic, NICVF_INTR_MBOX, 0);
+}
+
+static int nicvf_hw_set_mac_addr(struct nicvf *nic, struct net_device *netdev)
+{
+ union nic_mbx mbx = {};
+
+ mbx.mac.msg = NIC_MBOX_MSG_SET_MAC;
+ mbx.mac.vf_id = nic->vf_id;
+ ether_addr_copy(mbx.mac.mac_addr, netdev->dev_addr);
+
+ return nicvf_send_msg_to_pf(nic, &mbx);
+}
+
+static void nicvf_config_cpi(struct nicvf *nic)
+{
+ union nic_mbx mbx = {};
+
+ mbx.cpi_cfg.msg = NIC_MBOX_MSG_CPI_CFG;
+ mbx.cpi_cfg.vf_id = nic->vf_id;
+ mbx.cpi_cfg.cpi_alg = nic->cpi_alg;
+ mbx.cpi_cfg.rq_cnt = nic->qs->rq_cnt;
+
+ nicvf_send_msg_to_pf(nic, &mbx);
+}
+
+static void nicvf_get_rss_size(struct nicvf *nic)
+{
+ union nic_mbx mbx = {};
+
+ mbx.rss_size.msg = NIC_MBOX_MSG_RSS_SIZE;
+ mbx.rss_size.vf_id = nic->vf_id;
+ nicvf_send_msg_to_pf(nic, &mbx);
+}
+
+void nicvf_config_rss(struct nicvf *nic)
+{
+ union nic_mbx mbx = {};
+ struct nicvf_rss_info *rss = &nic->rss_info;
+ int ind_tbl_len = rss->rss_size;
+ int i, nextq = 0;
+
+ mbx.rss_cfg.vf_id = nic->vf_id;
+ mbx.rss_cfg.hash_bits = rss->hash_bits;
+ while (ind_tbl_len) {
+ mbx.rss_cfg.tbl_offset = nextq;
+ mbx.rss_cfg.tbl_len = min(ind_tbl_len,
+ RSS_IND_TBL_LEN_PER_MBX_MSG);
+ mbx.rss_cfg.msg = mbx.rss_cfg.tbl_offset ?
+ NIC_MBOX_MSG_RSS_CFG_CONT : NIC_MBOX_MSG_RSS_CFG;
+
+ for (i = 0; i < mbx.rss_cfg.tbl_len; i++)
+ mbx.rss_cfg.ind_tbl[i] = rss->ind_tbl[nextq++];
+
+ nicvf_send_msg_to_pf(nic, &mbx);
+
+ ind_tbl_len -= mbx.rss_cfg.tbl_len;
+ }
+}
+
+void nicvf_set_rss_key(struct nicvf *nic)
+{
+ struct nicvf_rss_info *rss = &nic->rss_info;
+ u64 key_addr = NIC_VNIC_RSS_KEY_0_4;
+ int idx;
+
+ for (idx = 0; idx < RSS_HASH_KEY_SIZE; idx++) {
+ nicvf_reg_write(nic, key_addr, rss->key[idx]);
+ key_addr += sizeof(u64);
+ }
+}
+
+static int nicvf_rss_init(struct nicvf *nic)
+{
+ struct nicvf_rss_info *rss = &nic->rss_info;
+ int idx;
+
+ nicvf_get_rss_size(nic);
+
+ if ((nic->qs->rq_cnt <= 1) || (cpi_alg != CPI_ALG_NONE)) {
+ rss->enable = false;
+ rss->hash_bits = 0;
+ return 0;
+ }
+
+ rss->enable = true;
+
+ /* Using the HW reset value for now */
+ rss->key[0] = 0xFEED0BADFEED0BADULL;
+ rss->key[1] = 0xFEED0BADFEED0BADULL;
+ rss->key[2] = 0xFEED0BADFEED0BADULL;
+ rss->key[3] = 0xFEED0BADFEED0BADULL;
+ rss->key[4] = 0xFEED0BADFEED0BADULL;
+
+ nicvf_set_rss_key(nic);
+
+ rss->cfg = RSS_IP_HASH_ENA | RSS_TCP_HASH_ENA | RSS_UDP_HASH_ENA;
+ nicvf_reg_write(nic, NIC_VNIC_RSS_CFG, rss->cfg);
+
+ rss->hash_bits = ilog2(rounddown_pow_of_two(rss->rss_size));
+
+ for (idx = 0; idx < rss->rss_size; idx++)
+ rss->ind_tbl[idx] = ethtool_rxfh_indir_default(idx,
+ nic->qs->rq_cnt);
+ nicvf_config_rss(nic);
+ return 1;
+}
+
+int nicvf_set_real_num_queues(struct net_device *netdev,
+ int tx_queues, int rx_queues)
+{
+ int err = 0;
+
+ err = netif_set_real_num_tx_queues(netdev, tx_queues);
+ if (err) {
+ netdev_err(netdev,
+ "Failed to set no of Tx queues: %d\n", tx_queues);
+ return err;
+ }
+
+ err = netif_set_real_num_rx_queues(netdev, rx_queues);
+ if (err)
+ netdev_err(netdev,
+ "Failed to set no of Rx queues: %d\n", rx_queues);
+ return err;
+}
+
+static int nicvf_init_resources(struct nicvf *nic)
+{
+ int err;
+ union nic_mbx mbx = {};
+
+ mbx.msg.msg = NIC_MBOX_MSG_CFG_DONE;
+
+ /* Enable Qset */
+ nicvf_qset_config(nic, true);
+
+ /* Initialize queues and HW for data transfer */
+ err = nicvf_config_data_transfer(nic, true);
+ if (err) {
+ netdev_err(nic->netdev,
+ "Failed to alloc/config VF's QSet resources\n");
+ return err;
+ }
+
+ /* Send VF config done msg to PF */
+ nicvf_write_to_mbx(nic, &mbx);
+
+ return 0;
+}
+
+static void nicvf_snd_pkt_handler(struct net_device *netdev,
+ struct cmp_queue *cq,
+ struct cqe_send_t *cqe_tx, int cqe_type)
+{
+ struct sk_buff *skb = NULL;
+ struct nicvf *nic = netdev_priv(netdev);
+ struct snd_queue *sq;
+ struct sq_hdr_subdesc *hdr;
+
+ sq = &nic->qs->sq[cqe_tx->sq_idx];
+
+ hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, cqe_tx->sqe_ptr);
+ if (hdr->subdesc_type != SQ_DESC_TYPE_HEADER)
+ return;
+
+ netdev_dbg(nic->netdev,
+ "%s Qset #%d SQ #%d SQ ptr #%d subdesc count %d\n",
+ __func__, cqe_tx->sq_qs, cqe_tx->sq_idx,
+ cqe_tx->sqe_ptr, hdr->subdesc_cnt);
+
+ nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1);
+ nicvf_check_cqe_tx_errs(nic, cq, cqe_tx);
+ skb = (struct sk_buff *)sq->skbuff[cqe_tx->sqe_ptr];
+ /* For TSO offloaded packets only one head SKB needs to be freed */
+ if (skb) {
+ prefetch(skb);
+ dev_consume_skb_any(skb);
+ }
+}
+
+static void nicvf_rcv_pkt_handler(struct net_device *netdev,
+ struct napi_struct *napi,
+ struct cmp_queue *cq,
+ struct cqe_rx_t *cqe_rx, int cqe_type)
+{
+ struct sk_buff *skb;
+ struct nicvf *nic = netdev_priv(netdev);
+ int err = 0;
+
+ /* Check for errors */
+ err = nicvf_check_cqe_rx_errs(nic, cq, cqe_rx);
+ if (err && !cqe_rx->rb_cnt)
+ return;
+
+ skb = nicvf_get_rcv_skb(nic, cqe_rx);
+ if (!skb) {
+ netdev_dbg(nic->netdev, "Packet not received\n");
+ return;
+ }
+
+ if (netif_msg_pktdata(nic)) {
+ netdev_info(nic->netdev, "%s: skb 0x%p, len=%d\n", netdev->name,
+ skb, skb->len);
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
+ skb->data, skb->len, true);
+ }
+
+ nicvf_set_rx_frame_cnt(nic, skb);
+
+ skb_record_rx_queue(skb, cqe_rx->rq_idx);
+ if (netdev->hw_features & NETIF_F_RXCSUM) {
+ /* HW by default verifies TCP/UDP/SCTP checksums */
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ skb_checksum_none_assert(skb);
+ }
+
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ if (napi && (netdev->features & NETIF_F_GRO))
+ napi_gro_receive(napi, skb);
+ else
+ netif_receive_skb(skb);
+}
+
+static int nicvf_cq_intr_handler(struct net_device *netdev, u8 cq_idx,
+ struct napi_struct *napi, int budget)
+{
+ int processed_cqe, work_done = 0;
+ int cqe_count, cqe_head;
+ struct nicvf *nic = netdev_priv(netdev);
+ struct queue_set *qs = nic->qs;
+ struct cmp_queue *cq = &qs->cq[cq_idx];
+ struct cqe_rx_t *cq_desc;
+
+ spin_lock_bh(&cq->lock);
+loop:
+ processed_cqe = 0;
+ /* Get no of valid CQ entries to process */
+ cqe_count = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS, cq_idx);
+ cqe_count &= CQ_CQE_COUNT;
+ if (!cqe_count)
+ goto done;
+
+ /* Get head of the valid CQ entries */
+ cqe_head = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_HEAD, cq_idx) >> 9;
+ cqe_head &= 0xFFFF;
+
+ netdev_dbg(nic->netdev, "%s cqe_count %d cqe_head %d\n",
+ __func__, cqe_count, cqe_head);
+ while (processed_cqe < cqe_count) {
+ /* Get the CQ descriptor */
+ cq_desc = (struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head);
+ cqe_head++;
+ cqe_head &= (cq->dmem.q_len - 1);
+ /* Initiate prefetch for next descriptor */
+ prefetch((struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head));
+
+ if ((work_done >= budget) && napi &&
+ (cq_desc->cqe_type != CQE_TYPE_SEND)) {
+ break;
+ }
+
+ netdev_dbg(nic->netdev, "cq_desc->cqe_type %d\n",
+ cq_desc->cqe_type);
+ switch (cq_desc->cqe_type) {
+ case CQE_TYPE_RX:
+ nicvf_rcv_pkt_handler(netdev, napi, cq,
+ cq_desc, CQE_TYPE_RX);
+ work_done++;
+ break;
+ case CQE_TYPE_SEND:
+ nicvf_snd_pkt_handler(netdev, cq,
+ (void *)cq_desc, CQE_TYPE_SEND);
+ break;
+ case CQE_TYPE_INVALID:
+ case CQE_TYPE_RX_SPLIT:
+ case CQE_TYPE_RX_TCP:
+ case CQE_TYPE_SEND_PTP:
+ /* Ignore for now */
+ break;
+ }
+ processed_cqe++;
+ }
+ netdev_dbg(nic->netdev, "%s processed_cqe %d work_done %d budget %d\n",
+ __func__, processed_cqe, work_done, budget);
+
+ /* Ring doorbell to inform H/W to reuse processed CQEs */
+ nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_DOOR,
+ cq_idx, processed_cqe);
+
+ if ((work_done < budget) && napi)
+ goto loop;
+
+done:
+ spin_unlock_bh(&cq->lock);
+ return work_done;
+}
+
+static int nicvf_poll(struct napi_struct *napi, int budget)
+{
+ u64 cq_head;
+ int work_done = 0;
+ struct net_device *netdev = napi->dev;
+ struct nicvf *nic = netdev_priv(netdev);
+ struct nicvf_cq_poll *cq;
+ struct netdev_queue *txq;
+
+ cq = container_of(napi, struct nicvf_cq_poll, napi);
+ work_done = nicvf_cq_intr_handler(netdev, cq->cq_idx, napi, budget);
+
+ txq = netdev_get_tx_queue(netdev, cq->cq_idx);
+ if (netif_tx_queue_stopped(txq))
+ netif_tx_wake_queue(txq);
+
+ if (work_done < budget) {
+ /* Slow packet rate, exit polling */
+ napi_complete(napi);
+ /* Re-enable interrupts */
+ cq_head = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_HEAD,
+ cq->cq_idx);
+ nicvf_clear_intr(nic, NICVF_INTR_CQ, cq->cq_idx);
+ nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_HEAD,
+ cq->cq_idx, cq_head);
+ nicvf_enable_intr(nic, NICVF_INTR_CQ, cq->cq_idx);
+ }
+ return work_done;
+}
+
+/* Qset error interrupt handler
+ *
+ * As of now only CQ errors are handled
+ */
+static void nicvf_handle_qs_err(unsigned long data)
+{
+ struct nicvf *nic = (struct nicvf *)data;
+ struct queue_set *qs = nic->qs;
+ int qidx;
+ u64 status;
+
+ netif_tx_disable(nic->netdev);
+
+ /* Check if it is CQ err */
+ for (qidx = 0; qidx < qs->cq_cnt; qidx++) {
+ status = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS,
+ qidx);
+ if (!(status & CQ_ERR_MASK))
+ continue;
+ /* Process already queued CQEs and reconfig CQ */
+ nicvf_disable_intr(nic, NICVF_INTR_CQ, qidx);
+ nicvf_sq_disable(nic, qidx);
+ nicvf_cq_intr_handler(nic->netdev, qidx, NULL, 0);
+ nicvf_cmp_queue_config(nic, qs, qidx, true);
+ nicvf_sq_free_used_descs(nic->netdev, &qs->sq[qidx], qidx);
+ nicvf_sq_enable(nic, &qs->sq[qidx], qidx);
+
+ nicvf_enable_intr(nic, NICVF_INTR_CQ, qidx);
+ }
+
+ netif_tx_start_all_queues(nic->netdev);
+ /* Re-enable Qset error interrupt */
+ nicvf_enable_intr(nic, NICVF_INTR_QS_ERR, 0);
+}
+
+static irqreturn_t nicvf_misc_intr_handler(int irq, void *nicvf_irq)
+{
+ struct nicvf *nic = (struct nicvf *)nicvf_irq;
+ u64 intr;
+
+ intr = nicvf_reg_read(nic, NIC_VF_INT);
+ /* Check for spurious interrupt */
+ if (!(intr & NICVF_INTR_MBOX_MASK))
+ return IRQ_HANDLED;
+
+ nicvf_handle_mbx_intr(nic);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t nicvf_intr_handler(int irq, void *nicvf_irq)
+{
+ u64 qidx, intr, clear_intr = 0;
+ u64 cq_intr, rbdr_intr, qs_err_intr;
+ struct nicvf *nic = (struct nicvf *)nicvf_irq;
+ struct queue_set *qs = nic->qs;
+ struct nicvf_cq_poll *cq_poll = NULL;
+
+ intr = nicvf_reg_read(nic, NIC_VF_INT);
+ if (netif_msg_intr(nic))
+ netdev_info(nic->netdev, "%s: interrupt status 0x%llx\n",
+ nic->netdev->name, intr);
+
+ qs_err_intr = intr & NICVF_INTR_QS_ERR_MASK;
+ if (qs_err_intr) {
+ /* Disable Qset err interrupt and schedule softirq */
+ nicvf_disable_intr(nic, NICVF_INTR_QS_ERR, 0);
+ tasklet_hi_schedule(&nic->qs_err_task);
+ clear_intr |= qs_err_intr;
+ }
+
+ /* Disable interrupts and start polling */
+ cq_intr = (intr & NICVF_INTR_CQ_MASK) >> NICVF_INTR_CQ_SHIFT;
+ for (qidx = 0; qidx < qs->cq_cnt; qidx++) {
+ if (!(cq_intr & (1 << qidx)))
+ continue;
+ if (!nicvf_is_intr_enabled(nic, NICVF_INTR_CQ, qidx))
+ continue;
+
+ nicvf_disable_intr(nic, NICVF_INTR_CQ, qidx);
+ clear_intr |= ((1 << qidx) << NICVF_INTR_CQ_SHIFT);
+
+ cq_poll = nic->napi[qidx];
+ /* Schedule NAPI */
+ if (cq_poll)
+ napi_schedule(&cq_poll->napi);
+ }
+
+ /* Handle RBDR interrupts */
+ rbdr_intr = (intr & NICVF_INTR_RBDR_MASK) >> NICVF_INTR_RBDR_SHIFT;
+ if (rbdr_intr) {
+ /* Disable RBDR interrupt and schedule softirq */
+ for (qidx = 0; qidx < qs->rbdr_cnt; qidx++) {
+ if (!nicvf_is_intr_enabled(nic, NICVF_INTR_RBDR, qidx))
+ continue;
+ nicvf_disable_intr(nic, NICVF_INTR_RBDR, qidx);
+ tasklet_hi_schedule(&nic->rbdr_task);
+ clear_intr |= ((1 << qidx) << NICVF_INTR_RBDR_SHIFT);
+ }
+ }
+
+ /* Clear interrupts */
+ nicvf_reg_write(nic, NIC_VF_INT, clear_intr);
+ return IRQ_HANDLED;
+}
+
+static int nicvf_enable_msix(struct nicvf *nic)
+{
+ int ret, vec;
+
+ nic->num_vec = NIC_VF_MSIX_VECTORS;
+
+ for (vec = 0; vec < nic->num_vec; vec++)
+ nic->msix_entries[vec].entry = vec;
+
+ ret = pci_enable_msix(nic->pdev, nic->msix_entries, nic->num_vec);
+ if (ret) {
+ netdev_err(nic->netdev,
+ "Req for #%d msix vectors failed\n", nic->num_vec);
+ return 0;
+ }
+ nic->msix_enabled = 1;
+ return 1;
+}
+
+static void nicvf_disable_msix(struct nicvf *nic)
+{
+ if (nic->msix_enabled) {
+ pci_disable_msix(nic->pdev);
+ nic->msix_enabled = 0;
+ nic->num_vec = 0;
+ }
+}
+
+static int nicvf_register_interrupts(struct nicvf *nic)
+{
+ int irq, free, ret = 0;
+ int vector;
+
+ for_each_cq_irq(irq)
+ sprintf(nic->irq_name[irq], "NICVF%d CQ%d",
+ nic->vf_id, irq);
+
+ for_each_sq_irq(irq)
+ sprintf(nic->irq_name[irq], "NICVF%d SQ%d",
+ nic->vf_id, irq - NICVF_INTR_ID_SQ);
+
+ for_each_rbdr_irq(irq)
+ sprintf(nic->irq_name[irq], "NICVF%d RBDR%d",
+ nic->vf_id, irq - NICVF_INTR_ID_RBDR);
+
+ /* Register all interrupts except mailbox */
+ for (irq = 0; irq < NICVF_INTR_ID_SQ; irq++) {
+ vector = nic->msix_entries[irq].vector;
+ ret = request_irq(vector, nicvf_intr_handler,
+ 0, nic->irq_name[irq], nic);
+ if (ret)
+ break;
+ nic->irq_allocated[irq] = true;
+ }
+
+ for (irq = NICVF_INTR_ID_SQ; irq < NICVF_INTR_ID_MISC; irq++) {
+ vector = nic->msix_entries[irq].vector;
+ ret = request_irq(vector, nicvf_intr_handler,
+ 0, nic->irq_name[irq], nic);
+ if (ret)
+ break;
+ nic->irq_allocated[irq] = true;
+ }
+
+ sprintf(nic->irq_name[NICVF_INTR_ID_QS_ERR],
+ "NICVF%d Qset error", nic->vf_id);
+ if (!ret) {
+ vector = nic->msix_entries[NICVF_INTR_ID_QS_ERR].vector;
+ irq = NICVF_INTR_ID_QS_ERR;
+ ret = request_irq(vector, nicvf_intr_handler,
+ 0, nic->irq_name[irq], nic);
+ if (!ret)
+ nic->irq_allocated[irq] = true;
+ }
+
+ if (ret) {
+ netdev_err(nic->netdev, "Request irq failed\n");
+ for (free = 0; free < irq; free++)
+ free_irq(nic->msix_entries[free].vector, nic);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void nicvf_unregister_interrupts(struct nicvf *nic)
+{
+ int irq;
+
+ /* Free registered interrupts */
+ for (irq = 0; irq < nic->num_vec; irq++) {
+ if (nic->irq_allocated[irq])
+ free_irq(nic->msix_entries[irq].vector, nic);
+ nic->irq_allocated[irq] = false;
+ }
+
+ /* Disable MSI-X */
+ nicvf_disable_msix(nic);
+}
+
+/* Initialize MSIX vectors and register MISC interrupt.
+ * Send READY message to PF to check if its alive
+ */
+static int nicvf_register_misc_interrupt(struct nicvf *nic)
+{
+ int ret = 0;
+ int irq = NICVF_INTR_ID_MISC;
+
+ /* Return if mailbox interrupt is already registered */
+ if (nic->msix_enabled)
+ return 0;
+
+ /* Enable MSI-X */
+ if (!nicvf_enable_msix(nic))
+ return 1;
+
+ sprintf(nic->irq_name[irq], "%s Mbox", "NICVF");
+ /* Register Misc interrupt */
+ ret = request_irq(nic->msix_entries[irq].vector,
+ nicvf_misc_intr_handler, 0, nic->irq_name[irq], nic);
+
+ if (ret)
+ return ret;
+ nic->irq_allocated[irq] = true;
+
+ /* Enable mailbox interrupt */
+ nicvf_enable_intr(nic, NICVF_INTR_MBOX, 0);
+
+ /* Check if VF is able to communicate with PF */
+ if (!nicvf_check_pf_ready(nic)) {
+ nicvf_disable_intr(nic, NICVF_INTR_MBOX, 0);
+ nicvf_unregister_interrupts(nic);
+ return 1;
+ }
+
+ return 0;
+}
+
+static netdev_tx_t nicvf_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct nicvf *nic = netdev_priv(netdev);
+ int qid = skb_get_queue_mapping(skb);
+ struct netdev_queue *txq = netdev_get_tx_queue(netdev, qid);
+
+ /* Check for minimum packet length */
+ if (skb->len <= ETH_HLEN) {
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ if (!nicvf_sq_append_skb(nic, skb) && !netif_tx_queue_stopped(txq)) {
+ netif_tx_stop_queue(txq);
+ nic->drv_stats.tx_busy++;
+ if (netif_msg_tx_err(nic))
+ netdev_warn(netdev,
+ "%s: Transmit ring full, stopping SQ%d\n",
+ netdev->name, qid);
+
+ return NETDEV_TX_BUSY;
+ }
+
+ return NETDEV_TX_OK;
+}
+
+int nicvf_stop(struct net_device *netdev)
+{
+ int irq, qidx;
+ struct nicvf *nic = netdev_priv(netdev);
+ struct queue_set *qs = nic->qs;
+ struct nicvf_cq_poll *cq_poll = NULL;
+ union nic_mbx mbx = {};
+
+ mbx.msg.msg = NIC_MBOX_MSG_SHUTDOWN;
+ nicvf_send_msg_to_pf(nic, &mbx);
+
+ netif_carrier_off(netdev);
+ netif_tx_disable(netdev);
+
+ /* Disable RBDR & QS error interrupts */
+ for (qidx = 0; qidx < qs->rbdr_cnt; qidx++) {
+ nicvf_disable_intr(nic, NICVF_INTR_RBDR, qidx);
+ nicvf_clear_intr(nic, NICVF_INTR_RBDR, qidx);
+ }
+ nicvf_disable_intr(nic, NICVF_INTR_QS_ERR, 0);
+ nicvf_clear_intr(nic, NICVF_INTR_QS_ERR, 0);
+
+ /* Wait for pending IRQ handlers to finish */
+ for (irq = 0; irq < nic->num_vec; irq++)
+ synchronize_irq(nic->msix_entries[irq].vector);
+
+ tasklet_kill(&nic->rbdr_task);
+ tasklet_kill(&nic->qs_err_task);
+ if (nic->rb_work_scheduled)
+ cancel_delayed_work_sync(&nic->rbdr_work);
+
+ for (qidx = 0; qidx < nic->qs->cq_cnt; qidx++) {
+ cq_poll = nic->napi[qidx];
+ if (!cq_poll)
+ continue;
+ nic->napi[qidx] = NULL;
+ napi_synchronize(&cq_poll->napi);
+ /* CQ intr is enabled while napi_complete,
+ * so disable it now
+ */
+ nicvf_disable_intr(nic, NICVF_INTR_CQ, qidx);
+ nicvf_clear_intr(nic, NICVF_INTR_CQ, qidx);
+ napi_disable(&cq_poll->napi);
+ netif_napi_del(&cq_poll->napi);
+ kfree(cq_poll);
+ }
+
+ /* Free resources */
+ nicvf_config_data_transfer(nic, false);
+
+ /* Disable HW Qset */
+ nicvf_qset_config(nic, false);
+
+ /* disable mailbox interrupt */
+ nicvf_disable_intr(nic, NICVF_INTR_MBOX, 0);
+
+ nicvf_unregister_interrupts(nic);
+
+ return 0;
+}
+
+int nicvf_open(struct net_device *netdev)
+{
+ int err, qidx;
+ struct nicvf *nic = netdev_priv(netdev);
+ struct queue_set *qs = nic->qs;
+ struct nicvf_cq_poll *cq_poll = NULL;
+
+ nic->mtu = netdev->mtu;
+
+ netif_carrier_off(netdev);
+
+ err = nicvf_register_misc_interrupt(nic);
+ if (err)
+ return err;
+
+ /* Register NAPI handler for processing CQEs */
+ for (qidx = 0; qidx < qs->cq_cnt; qidx++) {
+ cq_poll = kzalloc(sizeof(*cq_poll), GFP_KERNEL);
+ if (!cq_poll) {
+ err = -ENOMEM;
+ goto napi_del;
+ }
+ cq_poll->cq_idx = qidx;
+ netif_napi_add(netdev, &cq_poll->napi, nicvf_poll,
+ NAPI_POLL_WEIGHT);
+ napi_enable(&cq_poll->napi);
+ nic->napi[qidx] = cq_poll;
+ }
+
+ /* Check if we got MAC address from PF or else generate a radom MAC */
+ if (is_zero_ether_addr(netdev->dev_addr)) {
+ eth_hw_addr_random(netdev);
+ nicvf_hw_set_mac_addr(nic, netdev);
+ }
+
+ if (nic->set_mac_pending) {
+ nic->set_mac_pending = false;
+ nicvf_hw_set_mac_addr(nic, netdev);
+ }
+
+ /* Init tasklet for handling Qset err interrupt */
+ tasklet_init(&nic->qs_err_task, nicvf_handle_qs_err,
+ (unsigned long)nic);
+
+ /* Init RBDR tasklet which will refill RBDR */
+ tasklet_init(&nic->rbdr_task, nicvf_rbdr_task,
+ (unsigned long)nic);
+ INIT_DELAYED_WORK(&nic->rbdr_work, nicvf_rbdr_work);
+
+ /* Configure CPI alorithm */
+ nic->cpi_alg = cpi_alg;
+ nicvf_config_cpi(nic);
+
+ /* Configure receive side scaling */
+ nicvf_rss_init(nic);
+
+ err = nicvf_register_interrupts(nic);
+ if (err)
+ goto cleanup;
+
+ /* Initialize the queues */
+ err = nicvf_init_resources(nic);
+ if (err)
+ goto cleanup;
+
+ /* Make sure queue initialization is written */
+ wmb();
+
+ nicvf_reg_write(nic, NIC_VF_INT, -1);
+ /* Enable Qset err interrupt */
+ nicvf_enable_intr(nic, NICVF_INTR_QS_ERR, 0);
+
+ /* Enable completion queue interrupt */
+ for (qidx = 0; qidx < qs->cq_cnt; qidx++)
+ nicvf_enable_intr(nic, NICVF_INTR_CQ, qidx);
+
+ /* Enable RBDR threshold interrupt */
+ for (qidx = 0; qidx < qs->rbdr_cnt; qidx++)
+ nicvf_enable_intr(nic, NICVF_INTR_RBDR, qidx);
+
+ netif_carrier_on(netdev);
+ netif_tx_start_all_queues(netdev);
+
+ return 0;
+cleanup:
+ nicvf_disable_intr(nic, NICVF_INTR_MBOX, 0);
+ nicvf_unregister_interrupts(nic);
+napi_del:
+ for (qidx = 0; qidx < qs->cq_cnt; qidx++) {
+ cq_poll = nic->napi[qidx];
+ if (!cq_poll)
+ continue;
+ napi_disable(&cq_poll->napi);
+ netif_napi_del(&cq_poll->napi);
+ kfree(cq_poll);
+ nic->napi[qidx] = NULL;
+ }
+ return err;
+}
+
+static int nicvf_update_hw_max_frs(struct nicvf *nic, int mtu)
+{
+ union nic_mbx mbx = {};
+
+ mbx.frs.msg = NIC_MBOX_MSG_SET_MAX_FRS;
+ mbx.frs.max_frs = mtu;
+ mbx.frs.vf_id = nic->vf_id;
+
+ return nicvf_send_msg_to_pf(nic, &mbx);
+}
+
+static int nicvf_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct nicvf *nic = netdev_priv(netdev);
+
+ if (new_mtu > NIC_HW_MAX_FRS)
+ return -EINVAL;
+
+ if (new_mtu < NIC_HW_MIN_FRS)
+ return -EINVAL;
+
+ if (nicvf_update_hw_max_frs(nic, new_mtu))
+ return -EINVAL;
+ netdev->mtu = new_mtu;
+ nic->mtu = new_mtu;
+
+ return 0;
+}
+
+static int nicvf_set_mac_address(struct net_device *netdev, void *p)
+{
+ struct sockaddr *addr = p;
+ struct nicvf *nic = netdev_priv(netdev);
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+
+ if (nic->msix_enabled) {
+ if (nicvf_hw_set_mac_addr(nic, netdev))
+ return -EBUSY;
+ } else {
+ nic->set_mac_pending = true;
+ }
+
+ return 0;
+}
+
+void nicvf_update_lmac_stats(struct nicvf *nic)
+{
+ int stat = 0;
+ union nic_mbx mbx = {};
+ int timeout;
+
+ if (!netif_running(nic->netdev))
+ return;
+
+ mbx.bgx_stats.msg = NIC_MBOX_MSG_BGX_STATS;
+ mbx.bgx_stats.vf_id = nic->vf_id;
+ /* Rx stats */
+ mbx.bgx_stats.rx = 1;
+ while (stat < BGX_RX_STATS_COUNT) {
+ nic->bgx_stats_acked = 0;
+ mbx.bgx_stats.idx = stat;
+ nicvf_send_msg_to_pf(nic, &mbx);
+ timeout = 0;
+ while ((!nic->bgx_stats_acked) && (timeout < 10)) {
+ msleep(2);
+ timeout++;
+ }
+ stat++;
+ }
+
+ stat = 0;
+
+ /* Tx stats */
+ mbx.bgx_stats.rx = 0;
+ while (stat < BGX_TX_STATS_COUNT) {
+ nic->bgx_stats_acked = 0;
+ mbx.bgx_stats.idx = stat;
+ nicvf_send_msg_to_pf(nic, &mbx);
+ timeout = 0;
+ while ((!nic->bgx_stats_acked) && (timeout < 10)) {
+ msleep(2);
+ timeout++;
+ }
+ stat++;
+ }
+}
+
+void nicvf_update_stats(struct nicvf *nic)
+{
+ int qidx;
+ struct nicvf_hw_stats *stats = &nic->stats;
+ struct nicvf_drv_stats *drv_stats = &nic->drv_stats;
+ struct queue_set *qs = nic->qs;
+
+#define GET_RX_STATS(reg) \
+ nicvf_reg_read(nic, NIC_VNIC_RX_STAT_0_13 | (reg << 3))
+#define GET_TX_STATS(reg) \
+ nicvf_reg_read(nic, NIC_VNIC_TX_STAT_0_4 | (reg << 3))
+
+ stats->rx_bytes_ok = GET_RX_STATS(RX_OCTS);
+ stats->rx_ucast_frames_ok = GET_RX_STATS(RX_UCAST);
+ stats->rx_bcast_frames_ok = GET_RX_STATS(RX_BCAST);
+ stats->rx_mcast_frames_ok = GET_RX_STATS(RX_MCAST);
+ stats->rx_fcs_errors = GET_RX_STATS(RX_FCS);
+ stats->rx_l2_errors = GET_RX_STATS(RX_L2ERR);
+ stats->rx_drop_red = GET_RX_STATS(RX_RED);
+ stats->rx_drop_overrun = GET_RX_STATS(RX_ORUN);
+ stats->rx_drop_bcast = GET_RX_STATS(RX_DRP_BCAST);
+ stats->rx_drop_mcast = GET_RX_STATS(RX_DRP_MCAST);
+ stats->rx_drop_l3_bcast = GET_RX_STATS(RX_DRP_L3BCAST);
+ stats->rx_drop_l3_mcast = GET_RX_STATS(RX_DRP_L3MCAST);
+
+ stats->tx_bytes_ok = GET_TX_STATS(TX_OCTS);
+ stats->tx_ucast_frames_ok = GET_TX_STATS(TX_UCAST);
+ stats->tx_bcast_frames_ok = GET_TX_STATS(TX_BCAST);
+ stats->tx_mcast_frames_ok = GET_TX_STATS(TX_MCAST);
+ stats->tx_drops = GET_TX_STATS(TX_DROP);
+
+ drv_stats->rx_frames_ok = stats->rx_ucast_frames_ok +
+ stats->rx_bcast_frames_ok +
+ stats->rx_mcast_frames_ok;
+ drv_stats->tx_frames_ok = stats->tx_ucast_frames_ok +
+ stats->tx_bcast_frames_ok +
+ stats->tx_mcast_frames_ok;
+ drv_stats->rx_drops = stats->rx_drop_red +
+ stats->rx_drop_overrun;
+ drv_stats->tx_drops = stats->tx_drops;
+
+ /* Update RQ and SQ stats */
+ for (qidx = 0; qidx < qs->rq_cnt; qidx++)
+ nicvf_update_rq_stats(nic, qidx);
+ for (qidx = 0; qidx < qs->sq_cnt; qidx++)
+ nicvf_update_sq_stats(nic, qidx);
+}
+
+static struct rtnl_link_stats64 *nicvf_get_stats64(struct net_device *netdev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct nicvf *nic = netdev_priv(netdev);
+ struct nicvf_hw_stats *hw_stats = &nic->stats;
+ struct nicvf_drv_stats *drv_stats = &nic->drv_stats;
+
+ nicvf_update_stats(nic);
+
+ stats->rx_bytes = hw_stats->rx_bytes_ok;
+ stats->rx_packets = drv_stats->rx_frames_ok;
+ stats->rx_dropped = drv_stats->rx_drops;
+
+ stats->tx_bytes = hw_stats->tx_bytes_ok;
+ stats->tx_packets = drv_stats->tx_frames_ok;
+ stats->tx_dropped = drv_stats->tx_drops;
+
+ return stats;
+}
+
+static void nicvf_tx_timeout(struct net_device *dev)
+{
+ struct nicvf *nic = netdev_priv(dev);
+
+ if (netif_msg_tx_err(nic))
+ netdev_warn(dev, "%s: Transmit timed out, resetting\n",
+ dev->name);
+
+ schedule_work(&nic->reset_task);
+}
+
+static void nicvf_reset_task(struct work_struct *work)
+{
+ struct nicvf *nic;
+
+ nic = container_of(work, struct nicvf, reset_task);
+
+ if (!netif_running(nic->netdev))
+ return;
+
+ nicvf_stop(nic->netdev);
+ nicvf_open(nic->netdev);
+ nic->netdev->trans_start = jiffies;
+}
+
+static const struct net_device_ops nicvf_netdev_ops = {
+ .ndo_open = nicvf_open,
+ .ndo_stop = nicvf_stop,
+ .ndo_start_xmit = nicvf_xmit,
+ .ndo_change_mtu = nicvf_change_mtu,
+ .ndo_set_mac_address = nicvf_set_mac_address,
+ .ndo_get_stats64 = nicvf_get_stats64,
+ .ndo_tx_timeout = nicvf_tx_timeout,
+};
+
+static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct device *dev = &pdev->dev;
+ struct net_device *netdev;
+ struct nicvf *nic;
+ struct queue_set *qs;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(dev, "Failed to enable PCI device\n");
+ return err;
+ }
+
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err) {
+ dev_err(dev, "PCI request regions failed 0x%x\n", err);
+ goto err_disable_device;
+ }
+
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(48));
+ if (err) {
+ dev_err(dev, "Unable to get usable DMA configuration\n");
+ goto err_release_regions;
+ }
+
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(48));
+ if (err) {
+ dev_err(dev, "unable to get 48-bit DMA for consistent allocations\n");
+ goto err_release_regions;
+ }
+
+ netdev = alloc_etherdev_mqs(sizeof(struct nicvf),
+ MAX_RCV_QUEUES_PER_QS,
+ MAX_SND_QUEUES_PER_QS);
+ if (!netdev) {
+ err = -ENOMEM;
+ goto err_release_regions;
+ }
+
+ pci_set_drvdata(pdev, netdev);
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ nic = netdev_priv(netdev);
+ nic->netdev = netdev;
+ nic->pdev = pdev;
+
+ /* MAP VF's configuration registers */
+ nic->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0);
+ if (!nic->reg_base) {
+ dev_err(dev, "Cannot map config register space, aborting\n");
+ err = -ENOMEM;
+ goto err_free_netdev;
+ }
+
+ err = nicvf_set_qset_resources(nic);
+ if (err)
+ goto err_free_netdev;
+
+ qs = nic->qs;
+
+ err = nicvf_set_real_num_queues(netdev, qs->sq_cnt, qs->rq_cnt);
+ if (err)
+ goto err_free_netdev;
+
+ /* Check if PF is alive and get MAC address for this VF */
+ err = nicvf_register_misc_interrupt(nic);
+ if (err)
+ goto err_free_netdev;
+
+ netdev->features |= (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG |
+ NETIF_F_TSO | NETIF_F_GRO);
+ netdev->hw_features = netdev->features;
+
+ netdev->netdev_ops = &nicvf_netdev_ops;
+
+ INIT_WORK(&nic->reset_task, nicvf_reset_task);
+
+ err = register_netdev(netdev);
+ if (err) {
+ dev_err(dev, "Failed to register netdevice\n");
+ goto err_unregister_interrupts;
+ }
+
+ nic->msg_enable = debug;
+
+ nicvf_set_ethtool_ops(netdev);
+
+ return 0;
+
+err_unregister_interrupts:
+ nicvf_unregister_interrupts(nic);
+err_free_netdev:
+ pci_set_drvdata(pdev, NULL);
+ free_netdev(netdev);
+err_release_regions:
+ pci_release_regions(pdev);
+err_disable_device:
+ pci_disable_device(pdev);
+ return err;
+}
+
+static void nicvf_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct nicvf *nic = netdev_priv(netdev);
+
+ unregister_netdev(netdev);
+ nicvf_unregister_interrupts(nic);
+ pci_set_drvdata(pdev, NULL);
+ free_netdev(netdev);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+static struct pci_driver nicvf_driver = {
+ .name = DRV_NAME,
+ .id_table = nicvf_id_table,
+ .probe = nicvf_probe,
+ .remove = nicvf_remove,
+};
+
+static int __init nicvf_init_module(void)
+{
+ pr_info("%s, ver %s\n", DRV_NAME, DRV_VERSION);
+
+ return pci_register_driver(&nicvf_driver);
+}
+
+static void __exit nicvf_cleanup_module(void)
+{
+ pci_unregister_driver(&nicvf_driver);
+}
+
+module_init(nicvf_init_module);
+module_exit(nicvf_cleanup_module);
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
new file mode 100644
index 000000000000..d69d228d11a0
--- /dev/null
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
@@ -0,0 +1,1545 @@
+/*
+ * Copyright (C) 2015 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/ip.h>
+#include <linux/etherdevice.h>
+#include <net/ip.h>
+#include <net/tso.h>
+
+#include "nic_reg.h"
+#include "nic.h"
+#include "q_struct.h"
+#include "nicvf_queues.h"
+
+struct rbuf_info {
+ struct page *page;
+ void *data;
+ u64 offset;
+};
+
+#define GET_RBUF_INFO(x) ((struct rbuf_info *)(x - NICVF_RCV_BUF_ALIGN_BYTES))
+
+/* Poll a register for a specific value */
+static int nicvf_poll_reg(struct nicvf *nic, int qidx,
+ u64 reg, int bit_pos, int bits, int val)
+{
+ u64 bit_mask;
+ u64 reg_val;
+ int timeout = 10;
+
+ bit_mask = (1ULL << bits) - 1;
+ bit_mask = (bit_mask << bit_pos);
+
+ while (timeout) {
+ reg_val = nicvf_queue_reg_read(nic, reg, qidx);
+ if (((reg_val & bit_mask) >> bit_pos) == val)
+ return 0;
+ usleep_range(1000, 2000);
+ timeout--;
+ }
+ netdev_err(nic->netdev, "Poll on reg 0x%llx failed\n", reg);
+ return 1;
+}
+
+/* Allocate memory for a queue's descriptors */
+static int nicvf_alloc_q_desc_mem(struct nicvf *nic, struct q_desc_mem *dmem,
+ int q_len, int desc_size, int align_bytes)
+{
+ dmem->q_len = q_len;
+ dmem->size = (desc_size * q_len) + align_bytes;
+ /* Save address, need it while freeing */
+ dmem->unalign_base = dma_zalloc_coherent(&nic->pdev->dev, dmem->size,
+ &dmem->dma, GFP_KERNEL);
+ if (!dmem->unalign_base)
+ return -ENOMEM;
+
+ /* Align memory address for 'align_bytes' */
+ dmem->phys_base = NICVF_ALIGNED_ADDR((u64)dmem->dma, align_bytes);
+ dmem->base = dmem->unalign_base + (dmem->phys_base - dmem->dma);
+ return 0;
+}
+
+/* Free queue's descriptor memory */
+static void nicvf_free_q_desc_mem(struct nicvf *nic, struct q_desc_mem *dmem)
+{
+ if (!dmem)
+ return;
+
+ dma_free_coherent(&nic->pdev->dev, dmem->size,
+ dmem->unalign_base, dmem->dma);
+ dmem->unalign_base = NULL;
+ dmem->base = NULL;
+}
+
+/* Allocate buffer for packet reception
+ * HW returns memory address where packet is DMA'ed but not a pointer
+ * into RBDR ring, so save buffer address at the start of fragment and
+ * align the start address to a cache aligned address
+ */
+static inline int nicvf_alloc_rcv_buffer(struct nicvf *nic, gfp_t gfp,
+ u32 buf_len, u64 **rbuf)
+{
+ u64 data;
+ struct rbuf_info *rinfo;
+ int order = get_order(buf_len);
+
+ /* Check if request can be accomodated in previous allocated page */
+ if (nic->rb_page) {
+ if ((nic->rb_page_offset + buf_len + buf_len) >
+ (PAGE_SIZE << order)) {
+ nic->rb_page = NULL;
+ } else {
+ nic->rb_page_offset += buf_len;
+ get_page(nic->rb_page);
+ }
+ }
+
+ /* Allocate a new page */
+ if (!nic->rb_page) {
+ nic->rb_page = alloc_pages(gfp | __GFP_COMP, order);
+ if (!nic->rb_page) {
+ netdev_err(nic->netdev, "Failed to allocate new rcv buffer\n");
+ return -ENOMEM;
+ }
+ nic->rb_page_offset = 0;
+ }
+
+ data = (u64)page_address(nic->rb_page) + nic->rb_page_offset;
+
+ /* Align buffer addr to cache line i.e 128 bytes */
+ rinfo = (struct rbuf_info *)(data + NICVF_RCV_BUF_ALIGN_LEN(data));
+ /* Save page address for reference updation */
+ rinfo->page = nic->rb_page;
+ /* Store start address for later retrieval */
+ rinfo->data = (void *)data;
+ /* Store alignment offset */
+ rinfo->offset = NICVF_RCV_BUF_ALIGN_LEN(data);
+
+ data += rinfo->offset;
+
+ /* Give next aligned address to hw for DMA */
+ *rbuf = (u64 *)(data + NICVF_RCV_BUF_ALIGN_BYTES);
+ return 0;
+}
+
+/* Retrieve actual buffer start address and build skb for received packet */
+static struct sk_buff *nicvf_rb_ptr_to_skb(struct nicvf *nic,
+ u64 rb_ptr, int len)
+{
+ struct sk_buff *skb;
+ struct rbuf_info *rinfo;
+
+ rb_ptr = (u64)phys_to_virt(rb_ptr);
+ /* Get buffer start address and alignment offset */
+ rinfo = GET_RBUF_INFO(rb_ptr);
+
+ /* Now build an skb to give to stack */
+ skb = build_skb(rinfo->data, RCV_FRAG_LEN);
+ if (!skb) {
+ put_page(rinfo->page);
+ return NULL;
+ }
+
+ /* Set correct skb->data */
+ skb_reserve(skb, rinfo->offset + NICVF_RCV_BUF_ALIGN_BYTES);
+
+ prefetch((void *)rb_ptr);
+ return skb;
+}
+
+/* Allocate RBDR ring and populate receive buffers */
+static int nicvf_init_rbdr(struct nicvf *nic, struct rbdr *rbdr,
+ int ring_len, int buf_size)
+{
+ int idx;
+ u64 *rbuf;
+ struct rbdr_entry_t *desc;
+ int err;
+
+ err = nicvf_alloc_q_desc_mem(nic, &rbdr->dmem, ring_len,
+ sizeof(struct rbdr_entry_t),
+ NICVF_RCV_BUF_ALIGN_BYTES);
+ if (err)
+ return err;
+
+ rbdr->desc = rbdr->dmem.base;
+ /* Buffer size has to be in multiples of 128 bytes */
+ rbdr->dma_size = buf_size;
+ rbdr->enable = true;
+ rbdr->thresh = RBDR_THRESH;
+
+ nic->rb_page = NULL;
+ for (idx = 0; idx < ring_len; idx++) {
+ err = nicvf_alloc_rcv_buffer(nic, GFP_KERNEL, RCV_FRAG_LEN,
+ &rbuf);
+ if (err)
+ return err;
+
+ desc = GET_RBDR_DESC(rbdr, idx);
+ desc->buf_addr = virt_to_phys(rbuf) >> NICVF_RCV_BUF_ALIGN;
+ }
+ return 0;
+}
+
+/* Free RBDR ring and its receive buffers */
+static void nicvf_free_rbdr(struct nicvf *nic, struct rbdr *rbdr)
+{
+ int head, tail;
+ u64 buf_addr;
+ struct rbdr_entry_t *desc;
+ struct rbuf_info *rinfo;
+
+ if (!rbdr)
+ return;
+
+ rbdr->enable = false;
+ if (!rbdr->dmem.base)
+ return;
+
+ head = rbdr->head;
+ tail = rbdr->tail;
+
+ /* Free SKBs */
+ while (head != tail) {
+ desc = GET_RBDR_DESC(rbdr, head);
+ buf_addr = desc->buf_addr << NICVF_RCV_BUF_ALIGN;
+ rinfo = GET_RBUF_INFO((u64)phys_to_virt(buf_addr));
+ put_page(rinfo->page);
+ head++;
+ head &= (rbdr->dmem.q_len - 1);
+ }
+ /* Free SKB of tail desc */
+ desc = GET_RBDR_DESC(rbdr, tail);
+ buf_addr = desc->buf_addr << NICVF_RCV_BUF_ALIGN;
+ rinfo = GET_RBUF_INFO((u64)phys_to_virt(buf_addr));
+ put_page(rinfo->page);
+
+ /* Free RBDR ring */
+ nicvf_free_q_desc_mem(nic, &rbdr->dmem);
+}
+
+/* Refill receive buffer descriptors with new buffers.
+ */
+static void nicvf_refill_rbdr(struct nicvf *nic, gfp_t gfp)
+{
+ struct queue_set *qs = nic->qs;
+ int rbdr_idx = qs->rbdr_cnt;
+ int tail, qcount;
+ int refill_rb_cnt;
+ struct rbdr *rbdr;
+ struct rbdr_entry_t *desc;
+ u64 *rbuf;
+ int new_rb = 0;
+
+refill:
+ if (!rbdr_idx)
+ return;
+ rbdr_idx--;
+ rbdr = &qs->rbdr[rbdr_idx];
+ /* Check if it's enabled */
+ if (!rbdr->enable)
+ goto next_rbdr;
+
+ /* Get no of desc's to be refilled */
+ qcount = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_STATUS0, rbdr_idx);
+ qcount &= 0x7FFFF;
+ /* Doorbell can be ringed with a max of ring size minus 1 */
+ if (qcount >= (qs->rbdr_len - 1))
+ goto next_rbdr;
+ else
+ refill_rb_cnt = qs->rbdr_len - qcount - 1;
+
+ /* Start filling descs from tail */
+ tail = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_TAIL, rbdr_idx) >> 3;
+ while (refill_rb_cnt) {
+ tail++;
+ tail &= (rbdr->dmem.q_len - 1);
+
+ if (nicvf_alloc_rcv_buffer(nic, gfp, RCV_FRAG_LEN, &rbuf))
+ break;
+
+ desc = GET_RBDR_DESC(rbdr, tail);
+ desc->buf_addr = virt_to_phys(rbuf) >> NICVF_RCV_BUF_ALIGN;
+ refill_rb_cnt--;
+ new_rb++;
+ }
+
+ /* make sure all memory stores are done before ringing doorbell */
+ smp_wmb();
+
+ /* Check if buffer allocation failed */
+ if (refill_rb_cnt)
+ nic->rb_alloc_fail = true;
+ else
+ nic->rb_alloc_fail = false;
+
+ /* Notify HW */
+ nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_DOOR,
+ rbdr_idx, new_rb);
+next_rbdr:
+ /* Re-enable RBDR interrupts only if buffer allocation is success */
+ if (!nic->rb_alloc_fail && rbdr->enable)
+ nicvf_enable_intr(nic, NICVF_INTR_RBDR, rbdr_idx);
+
+ if (rbdr_idx)
+ goto refill;
+}
+
+/* Alloc rcv buffers in non-atomic mode for better success */
+void nicvf_rbdr_work(struct work_struct *work)
+{
+ struct nicvf *nic = container_of(work, struct nicvf, rbdr_work.work);
+
+ nicvf_refill_rbdr(nic, GFP_KERNEL);
+ if (nic->rb_alloc_fail)
+ schedule_delayed_work(&nic->rbdr_work, msecs_to_jiffies(10));
+ else
+ nic->rb_work_scheduled = false;
+}
+
+/* In Softirq context, alloc rcv buffers in atomic mode */
+void nicvf_rbdr_task(unsigned long data)
+{
+ struct nicvf *nic = (struct nicvf *)data;
+
+ nicvf_refill_rbdr(nic, GFP_ATOMIC);
+ if (nic->rb_alloc_fail) {
+ nic->rb_work_scheduled = true;
+ schedule_delayed_work(&nic->rbdr_work, msecs_to_jiffies(10));
+ }
+}
+
+/* Initialize completion queue */
+static int nicvf_init_cmp_queue(struct nicvf *nic,
+ struct cmp_queue *cq, int q_len)
+{
+ int err;
+
+ err = nicvf_alloc_q_desc_mem(nic, &cq->dmem, q_len, CMP_QUEUE_DESC_SIZE,
+ NICVF_CQ_BASE_ALIGN_BYTES);
+ if (err)
+ return err;
+
+ cq->desc = cq->dmem.base;
+ cq->thresh = CMP_QUEUE_CQE_THRESH;
+ nic->cq_coalesce_usecs = (CMP_QUEUE_TIMER_THRESH * 0.05) - 1;
+
+ return 0;
+}
+
+static void nicvf_free_cmp_queue(struct nicvf *nic, struct cmp_queue *cq)
+{
+ if (!cq)
+ return;
+ if (!cq->dmem.base)
+ return;
+
+ nicvf_free_q_desc_mem(nic, &cq->dmem);
+}
+
+/* Initialize transmit queue */
+static int nicvf_init_snd_queue(struct nicvf *nic,
+ struct snd_queue *sq, int q_len)
+{
+ int err;
+
+ err = nicvf_alloc_q_desc_mem(nic, &sq->dmem, q_len, SND_QUEUE_DESC_SIZE,
+ NICVF_SQ_BASE_ALIGN_BYTES);
+ if (err)
+ return err;
+
+ sq->desc = sq->dmem.base;
+ sq->skbuff = kcalloc(q_len, sizeof(u64), GFP_KERNEL);
+ if (!sq->skbuff)
+ return -ENOMEM;
+ sq->head = 0;
+ sq->tail = 0;
+ atomic_set(&sq->free_cnt, q_len - 1);
+ sq->thresh = SND_QUEUE_THRESH;
+
+ /* Preallocate memory for TSO segment's header */
+ sq->tso_hdrs = dma_alloc_coherent(&nic->pdev->dev,
+ q_len * TSO_HEADER_SIZE,
+ &sq->tso_hdrs_phys, GFP_KERNEL);
+ if (!sq->tso_hdrs)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void nicvf_free_snd_queue(struct nicvf *nic, struct snd_queue *sq)
+{
+ if (!sq)
+ return;
+ if (!sq->dmem.base)
+ return;
+
+ if (sq->tso_hdrs)
+ dma_free_coherent(&nic->pdev->dev, sq->dmem.q_len,
+ sq->tso_hdrs, sq->tso_hdrs_phys);
+
+ kfree(sq->skbuff);
+ nicvf_free_q_desc_mem(nic, &sq->dmem);
+}
+
+static void nicvf_reclaim_snd_queue(struct nicvf *nic,
+ struct queue_set *qs, int qidx)
+{
+ /* Disable send queue */
+ nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, 0);
+ /* Check if SQ is stopped */
+ if (nicvf_poll_reg(nic, qidx, NIC_QSET_SQ_0_7_STATUS, 21, 1, 0x01))
+ return;
+ /* Reset send queue */
+ nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, NICVF_SQ_RESET);
+}
+
+static void nicvf_reclaim_rcv_queue(struct nicvf *nic,
+ struct queue_set *qs, int qidx)
+{
+ union nic_mbx mbx = {};
+
+ /* Make sure all packets in the pipeline are written back into mem */
+ mbx.msg.msg = NIC_MBOX_MSG_RQ_SW_SYNC;
+ nicvf_send_msg_to_pf(nic, &mbx);
+}
+
+static void nicvf_reclaim_cmp_queue(struct nicvf *nic,
+ struct queue_set *qs, int qidx)
+{
+ /* Disable timer threshold (doesn't get reset upon CQ reset */
+ nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG2, qidx, 0);
+ /* Disable completion queue */
+ nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, 0);
+ /* Reset completion queue */
+ nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, NICVF_CQ_RESET);
+}
+
+static void nicvf_reclaim_rbdr(struct nicvf *nic,
+ struct rbdr *rbdr, int qidx)
+{
+ u64 tmp, fifo_state;
+ int timeout = 10;
+
+ /* Save head and tail pointers for feeing up buffers */
+ rbdr->head = nicvf_queue_reg_read(nic,
+ NIC_QSET_RBDR_0_1_HEAD,
+ qidx) >> 3;
+ rbdr->tail = nicvf_queue_reg_read(nic,
+ NIC_QSET_RBDR_0_1_TAIL,
+ qidx) >> 3;
+
+ /* If RBDR FIFO is in 'FAIL' state then do a reset first
+ * before relaiming.
+ */
+ fifo_state = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_STATUS0, qidx);
+ if (((fifo_state >> 62) & 0x03) == 0x3)
+ nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG,
+ qidx, NICVF_RBDR_RESET);
+
+ /* Disable RBDR */
+ nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG, qidx, 0);
+ if (nicvf_poll_reg(nic, qidx, NIC_QSET_RBDR_0_1_STATUS0, 62, 2, 0x00))
+ return;
+ while (1) {
+ tmp = nicvf_queue_reg_read(nic,
+ NIC_QSET_RBDR_0_1_PREFETCH_STATUS,
+ qidx);
+ if ((tmp & 0xFFFFFFFF) == ((tmp >> 32) & 0xFFFFFFFF))
+ break;
+ usleep_range(1000, 2000);
+ timeout--;
+ if (!timeout) {
+ netdev_err(nic->netdev,
+ "Failed polling on prefetch status\n");
+ return;
+ }
+ }
+ nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG,
+ qidx, NICVF_RBDR_RESET);
+
+ if (nicvf_poll_reg(nic, qidx, NIC_QSET_RBDR_0_1_STATUS0, 62, 2, 0x02))
+ return;
+ nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG, qidx, 0x00);
+ if (nicvf_poll_reg(nic, qidx, NIC_QSET_RBDR_0_1_STATUS0, 62, 2, 0x00))
+ return;
+}
+
+/* Configures receive queue */
+static void nicvf_rcv_queue_config(struct nicvf *nic, struct queue_set *qs,
+ int qidx, bool enable)
+{
+ union nic_mbx mbx = {};
+ struct rcv_queue *rq;
+ struct rq_cfg rq_cfg;
+
+ rq = &qs->rq[qidx];
+ rq->enable = enable;
+
+ /* Disable receive queue */
+ nicvf_queue_reg_write(nic, NIC_QSET_RQ_0_7_CFG, qidx, 0);
+
+ if (!rq->enable) {
+ nicvf_reclaim_rcv_queue(nic, qs, qidx);
+ return;
+ }
+
+ rq->cq_qs = qs->vnic_id;
+ rq->cq_idx = qidx;
+ rq->start_rbdr_qs = qs->vnic_id;
+ rq->start_qs_rbdr_idx = qs->rbdr_cnt - 1;
+ rq->cont_rbdr_qs = qs->vnic_id;
+ rq->cont_qs_rbdr_idx = qs->rbdr_cnt - 1;
+ /* all writes of RBDR data to be loaded into L2 Cache as well*/
+ rq->caching = 1;
+
+ /* Send a mailbox msg to PF to config RQ */
+ mbx.rq.msg = NIC_MBOX_MSG_RQ_CFG;
+ mbx.rq.qs_num = qs->vnic_id;
+ mbx.rq.rq_num = qidx;
+ mbx.rq.cfg = (rq->caching << 26) | (rq->cq_qs << 19) |
+ (rq->cq_idx << 16) | (rq->cont_rbdr_qs << 9) |
+ (rq->cont_qs_rbdr_idx << 8) |
+ (rq->start_rbdr_qs << 1) | (rq->start_qs_rbdr_idx);
+ nicvf_send_msg_to_pf(nic, &mbx);
+
+ mbx.rq.msg = NIC_MBOX_MSG_RQ_BP_CFG;
+ mbx.rq.cfg = (1ULL << 63) | (1ULL << 62) | (qs->vnic_id << 0);
+ nicvf_send_msg_to_pf(nic, &mbx);
+
+ /* RQ drop config
+ * Enable CQ drop to reserve sufficient CQEs for all tx packets
+ */
+ mbx.rq.msg = NIC_MBOX_MSG_RQ_DROP_CFG;
+ mbx.rq.cfg = (1ULL << 62) | (RQ_CQ_DROP << 8);
+ nicvf_send_msg_to_pf(nic, &mbx);
+
+ nicvf_queue_reg_write(nic, NIC_QSET_RQ_GEN_CFG, qidx, 0x00);
+
+ /* Enable Receive queue */
+ rq_cfg.ena = 1;
+ rq_cfg.tcp_ena = 0;
+ nicvf_queue_reg_write(nic, NIC_QSET_RQ_0_7_CFG, qidx, *(u64 *)&rq_cfg);
+}
+
+/* Configures completion queue */
+void nicvf_cmp_queue_config(struct nicvf *nic, struct queue_set *qs,
+ int qidx, bool enable)
+{
+ struct cmp_queue *cq;
+ struct cq_cfg cq_cfg;
+
+ cq = &qs->cq[qidx];
+ cq->enable = enable;
+
+ if (!cq->enable) {
+ nicvf_reclaim_cmp_queue(nic, qs, qidx);
+ return;
+ }
+
+ /* Reset completion queue */
+ nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, NICVF_CQ_RESET);
+
+ if (!cq->enable)
+ return;
+
+ spin_lock_init(&cq->lock);
+ /* Set completion queue base address */
+ nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_BASE,
+ qidx, (u64)(cq->dmem.phys_base));
+
+ /* Enable Completion queue */
+ cq_cfg.ena = 1;
+ cq_cfg.reset = 0;
+ cq_cfg.caching = 0;
+ cq_cfg.qsize = CMP_QSIZE;
+ cq_cfg.avg_con = 0;
+ nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, *(u64 *)&cq_cfg);
+
+ /* Set threshold value for interrupt generation */
+ nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_THRESH, qidx, cq->thresh);
+ nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG2,
+ qidx, nic->cq_coalesce_usecs);
+}
+
+/* Configures transmit queue */
+static void nicvf_snd_queue_config(struct nicvf *nic, struct queue_set *qs,
+ int qidx, bool enable)
+{
+ union nic_mbx mbx = {};
+ struct snd_queue *sq;
+ struct sq_cfg sq_cfg;
+
+ sq = &qs->sq[qidx];
+ sq->enable = enable;
+
+ if (!sq->enable) {
+ nicvf_reclaim_snd_queue(nic, qs, qidx);
+ return;
+ }
+
+ /* Reset send queue */
+ nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, NICVF_SQ_RESET);
+
+ sq->cq_qs = qs->vnic_id;
+ sq->cq_idx = qidx;
+
+ /* Send a mailbox msg to PF to config SQ */
+ mbx.sq.msg = NIC_MBOX_MSG_SQ_CFG;
+ mbx.sq.qs_num = qs->vnic_id;
+ mbx.sq.sq_num = qidx;
+ mbx.sq.cfg = (sq->cq_qs << 3) | sq->cq_idx;
+ nicvf_send_msg_to_pf(nic, &mbx);
+
+ /* Set queue base address */
+ nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_BASE,
+ qidx, (u64)(sq->dmem.phys_base));
+
+ /* Enable send queue & set queue size */
+ sq_cfg.ena = 1;
+ sq_cfg.reset = 0;
+ sq_cfg.ldwb = 0;
+ sq_cfg.qsize = SND_QSIZE;
+ sq_cfg.tstmp_bgx_intf = 0;
+ nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, *(u64 *)&sq_cfg);
+
+ /* Set threshold value for interrupt generation */
+ nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_THRESH, qidx, sq->thresh);
+
+ /* Set queue:cpu affinity for better load distribution */
+ if (cpu_online(qidx)) {
+ cpumask_set_cpu(qidx, &sq->affinity_mask);
+ netif_set_xps_queue(nic->netdev,
+ &sq->affinity_mask, qidx);
+ }
+}
+
+/* Configures receive buffer descriptor ring */
+static void nicvf_rbdr_config(struct nicvf *nic, struct queue_set *qs,
+ int qidx, bool enable)
+{
+ struct rbdr *rbdr;
+ struct rbdr_cfg rbdr_cfg;
+
+ rbdr = &qs->rbdr[qidx];
+ nicvf_reclaim_rbdr(nic, rbdr, qidx);
+ if (!enable)
+ return;
+
+ /* Set descriptor base address */
+ nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_BASE,
+ qidx, (u64)(rbdr->dmem.phys_base));
+
+ /* Enable RBDR & set queue size */
+ /* Buffer size should be in multiples of 128 bytes */
+ rbdr_cfg.ena = 1;
+ rbdr_cfg.reset = 0;
+ rbdr_cfg.ldwb = 0;
+ rbdr_cfg.qsize = RBDR_SIZE;
+ rbdr_cfg.avg_con = 0;
+ rbdr_cfg.lines = rbdr->dma_size / 128;
+ nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG,
+ qidx, *(u64 *)&rbdr_cfg);
+
+ /* Notify HW */
+ nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_DOOR,
+ qidx, qs->rbdr_len - 1);
+
+ /* Set threshold value for interrupt generation */
+ nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_THRESH,
+ qidx, rbdr->thresh - 1);
+}
+
+/* Requests PF to assign and enable Qset */
+void nicvf_qset_config(struct nicvf *nic, bool enable)
+{
+ union nic_mbx mbx = {};
+ struct queue_set *qs = nic->qs;
+ struct qs_cfg *qs_cfg;
+
+ if (!qs) {
+ netdev_warn(nic->netdev,
+ "Qset is still not allocated, don't init queues\n");
+ return;
+ }
+
+ qs->enable = enable;
+ qs->vnic_id = nic->vf_id;
+
+ /* Send a mailbox msg to PF to config Qset */
+ mbx.qs.msg = NIC_MBOX_MSG_QS_CFG;
+ mbx.qs.num = qs->vnic_id;
+
+ mbx.qs.cfg = 0;
+ qs_cfg = (struct qs_cfg *)&mbx.qs.cfg;
+ if (qs->enable) {
+ qs_cfg->ena = 1;
+#ifdef __BIG_ENDIAN
+ qs_cfg->be = 1;
+#endif
+ qs_cfg->vnic = qs->vnic_id;
+ }
+ nicvf_send_msg_to_pf(nic, &mbx);
+}
+
+static void nicvf_free_resources(struct nicvf *nic)
+{
+ int qidx;
+ struct queue_set *qs = nic->qs;
+
+ /* Free receive buffer descriptor ring */
+ for (qidx = 0; qidx < qs->rbdr_cnt; qidx++)
+ nicvf_free_rbdr(nic, &qs->rbdr[qidx]);
+
+ /* Free completion queue */
+ for (qidx = 0; qidx < qs->cq_cnt; qidx++)
+ nicvf_free_cmp_queue(nic, &qs->cq[qidx]);
+
+ /* Free send queue */
+ for (qidx = 0; qidx < qs->sq_cnt; qidx++)
+ nicvf_free_snd_queue(nic, &qs->sq[qidx]);
+}
+
+static int nicvf_alloc_resources(struct nicvf *nic)
+{
+ int qidx;
+ struct queue_set *qs = nic->qs;
+
+ /* Alloc receive buffer descriptor ring */
+ for (qidx = 0; qidx < qs->rbdr_cnt; qidx++) {
+ if (nicvf_init_rbdr(nic, &qs->rbdr[qidx], qs->rbdr_len,
+ DMA_BUFFER_LEN))
+ goto alloc_fail;
+ }
+
+ /* Alloc send queue */
+ for (qidx = 0; qidx < qs->sq_cnt; qidx++) {
+ if (nicvf_init_snd_queue(nic, &qs->sq[qidx], qs->sq_len))
+ goto alloc_fail;
+ }
+
+ /* Alloc completion queue */
+ for (qidx = 0; qidx < qs->cq_cnt; qidx++) {
+ if (nicvf_init_cmp_queue(nic, &qs->cq[qidx], qs->cq_len))
+ goto alloc_fail;
+ }
+
+ return 0;
+alloc_fail:
+ nicvf_free_resources(nic);
+ return -ENOMEM;
+}
+
+int nicvf_set_qset_resources(struct nicvf *nic)
+{
+ struct queue_set *qs;
+
+ qs = devm_kzalloc(&nic->pdev->dev, sizeof(*qs), GFP_KERNEL);
+ if (!qs)
+ return -ENOMEM;
+ nic->qs = qs;
+
+ /* Set count of each queue */
+ qs->rbdr_cnt = RBDR_CNT;
+ qs->rq_cnt = RCV_QUEUE_CNT;
+ qs->sq_cnt = SND_QUEUE_CNT;
+ qs->cq_cnt = CMP_QUEUE_CNT;
+
+ /* Set queue lengths */
+ qs->rbdr_len = RCV_BUF_COUNT;
+ qs->sq_len = SND_QUEUE_LEN;
+ qs->cq_len = CMP_QUEUE_LEN;
+ return 0;
+}
+
+int nicvf_config_data_transfer(struct nicvf *nic, bool enable)
+{
+ bool disable = false;
+ struct queue_set *qs = nic->qs;
+ int qidx;
+
+ if (!qs)
+ return 0;
+
+ if (enable) {
+ if (nicvf_alloc_resources(nic))
+ return -ENOMEM;
+
+ for (qidx = 0; qidx < qs->sq_cnt; qidx++)
+ nicvf_snd_queue_config(nic, qs, qidx, enable);
+ for (qidx = 0; qidx < qs->cq_cnt; qidx++)
+ nicvf_cmp_queue_config(nic, qs, qidx, enable);
+ for (qidx = 0; qidx < qs->rbdr_cnt; qidx++)
+ nicvf_rbdr_config(nic, qs, qidx, enable);
+ for (qidx = 0; qidx < qs->rq_cnt; qidx++)
+ nicvf_rcv_queue_config(nic, qs, qidx, enable);
+ } else {
+ for (qidx = 0; qidx < qs->rq_cnt; qidx++)
+ nicvf_rcv_queue_config(nic, qs, qidx, disable);
+ for (qidx = 0; qidx < qs->rbdr_cnt; qidx++)
+ nicvf_rbdr_config(nic, qs, qidx, disable);
+ for (qidx = 0; qidx < qs->sq_cnt; qidx++)
+ nicvf_snd_queue_config(nic, qs, qidx, disable);
+ for (qidx = 0; qidx < qs->cq_cnt; qidx++)
+ nicvf_cmp_queue_config(nic, qs, qidx, disable);
+
+ nicvf_free_resources(nic);
+ }
+
+ return 0;
+}
+
+/* Get a free desc from SQ
+ * returns descriptor ponter & descriptor number
+ */
+static inline int nicvf_get_sq_desc(struct snd_queue *sq, int desc_cnt)
+{
+ int qentry;
+
+ qentry = sq->tail;
+ atomic_sub(desc_cnt, &sq->free_cnt);
+ sq->tail += desc_cnt;
+ sq->tail &= (sq->dmem.q_len - 1);
+
+ return qentry;
+}
+
+/* Free descriptor back to SQ for future use */
+void nicvf_put_sq_desc(struct snd_queue *sq, int desc_cnt)
+{
+ atomic_add(desc_cnt, &sq->free_cnt);
+ sq->head += desc_cnt;
+ sq->head &= (sq->dmem.q_len - 1);
+}
+
+static inline int nicvf_get_nxt_sqentry(struct snd_queue *sq, int qentry)
+{
+ qentry++;
+ qentry &= (sq->dmem.q_len - 1);
+ return qentry;
+}
+
+void nicvf_sq_enable(struct nicvf *nic, struct snd_queue *sq, int qidx)
+{
+ u64 sq_cfg;
+
+ sq_cfg = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_CFG, qidx);
+ sq_cfg |= NICVF_SQ_EN;
+ nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, sq_cfg);
+ /* Ring doorbell so that H/W restarts processing SQEs */
+ nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_DOOR, qidx, 0);
+}
+
+void nicvf_sq_disable(struct nicvf *nic, int qidx)
+{
+ u64 sq_cfg;
+
+ sq_cfg = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_CFG, qidx);
+ sq_cfg &= ~NICVF_SQ_EN;
+ nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, sq_cfg);
+}
+
+void nicvf_sq_free_used_descs(struct net_device *netdev, struct snd_queue *sq,
+ int qidx)
+{
+ u64 head, tail;
+ struct sk_buff *skb;
+ struct nicvf *nic = netdev_priv(netdev);
+ struct sq_hdr_subdesc *hdr;
+
+ head = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_HEAD, qidx) >> 4;
+ tail = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_TAIL, qidx) >> 4;
+ while (sq->head != head) {
+ hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, sq->head);
+ if (hdr->subdesc_type != SQ_DESC_TYPE_HEADER) {
+ nicvf_put_sq_desc(sq, 1);
+ continue;
+ }
+ skb = (struct sk_buff *)sq->skbuff[sq->head];
+ atomic64_add(1, (atomic64_t *)&netdev->stats.tx_packets);
+ atomic64_add(hdr->tot_len,
+ (atomic64_t *)&netdev->stats.tx_bytes);
+ dev_kfree_skb_any(skb);
+ nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1);
+ }
+}
+
+/* Calculate no of SQ subdescriptors needed to transmit all
+ * segments of this TSO packet.
+ * Taken from 'Tilera network driver' with a minor modification.
+ */
+static int nicvf_tso_count_subdescs(struct sk_buff *skb)
+{
+ struct skb_shared_info *sh = skb_shinfo(skb);
+ unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ unsigned int data_len = skb->len - sh_len;
+ unsigned int p_len = sh->gso_size;
+ long f_id = -1; /* id of the current fragment */
+ long f_size = skb_headlen(skb) - sh_len; /* current fragment size */
+ long f_used = 0; /* bytes used from the current fragment */
+ long n; /* size of the current piece of payload */
+ int num_edescs = 0;
+ int segment;
+
+ for (segment = 0; segment < sh->gso_segs; segment++) {
+ unsigned int p_used = 0;
+
+ /* One edesc for header and for each piece of the payload. */
+ for (num_edescs++; p_used < p_len; num_edescs++) {
+ /* Advance as needed. */
+ while (f_used >= f_size) {
+ f_id++;
+ f_size = skb_frag_size(&sh->frags[f_id]);
+ f_used = 0;
+ }
+
+ /* Use bytes from the current fragment. */
+ n = p_len - p_used;
+ if (n > f_size - f_used)
+ n = f_size - f_used;
+ f_used += n;
+ p_used += n;
+ }
+
+ /* The last segment may be less than gso_size. */
+ data_len -= p_len;
+ if (data_len < p_len)
+ p_len = data_len;
+ }
+
+ /* '+ gso_segs' for SQ_HDR_SUDESCs for each segment */
+ return num_edescs + sh->gso_segs;
+}
+
+/* Get the number of SQ descriptors needed to xmit this skb */
+static int nicvf_sq_subdesc_required(struct nicvf *nic, struct sk_buff *skb)
+{
+ int subdesc_cnt = MIN_SQ_DESC_PER_PKT_XMIT;
+
+ if (skb_shinfo(skb)->gso_size) {
+ subdesc_cnt = nicvf_tso_count_subdescs(skb);
+ return subdesc_cnt;
+ }
+
+ if (skb_shinfo(skb)->nr_frags)
+ subdesc_cnt += skb_shinfo(skb)->nr_frags;
+
+ return subdesc_cnt;
+}
+
+/* Add SQ HEADER subdescriptor.
+ * First subdescriptor for every send descriptor.
+ */
+static inline void
+nicvf_sq_add_hdr_subdesc(struct snd_queue *sq, int qentry,
+ int subdesc_cnt, struct sk_buff *skb, int len)
+{
+ int proto;
+ struct sq_hdr_subdesc *hdr;
+
+ hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, qentry);
+ sq->skbuff[qentry] = (u64)skb;
+
+ memset(hdr, 0, SND_QUEUE_DESC_SIZE);
+ hdr->subdesc_type = SQ_DESC_TYPE_HEADER;
+ /* Enable notification via CQE after processing SQE */
+ hdr->post_cqe = 1;
+ /* No of subdescriptors following this */
+ hdr->subdesc_cnt = subdesc_cnt;
+ hdr->tot_len = len;
+
+ /* Offload checksum calculation to HW */
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (skb->protocol != htons(ETH_P_IP))
+ return;
+
+ hdr->csum_l3 = 1; /* Enable IP csum calculation */
+ hdr->l3_offset = skb_network_offset(skb);
+ hdr->l4_offset = skb_transport_offset(skb);
+
+ proto = ip_hdr(skb)->protocol;
+ switch (proto) {
+ case IPPROTO_TCP:
+ hdr->csum_l4 = SEND_L4_CSUM_TCP;
+ break;
+ case IPPROTO_UDP:
+ hdr->csum_l4 = SEND_L4_CSUM_UDP;
+ break;
+ case IPPROTO_SCTP:
+ hdr->csum_l4 = SEND_L4_CSUM_SCTP;
+ break;
+ }
+ }
+}
+
+/* SQ GATHER subdescriptor
+ * Must follow HDR descriptor
+ */
+static inline void nicvf_sq_add_gather_subdesc(struct snd_queue *sq, int qentry,
+ int size, u64 data)
+{
+ struct sq_gather_subdesc *gather;
+
+ qentry &= (sq->dmem.q_len - 1);
+ gather = (struct sq_gather_subdesc *)GET_SQ_DESC(sq, qentry);
+
+ memset(gather, 0, SND_QUEUE_DESC_SIZE);
+ gather->subdesc_type = SQ_DESC_TYPE_GATHER;
+ gather->ld_type = NIC_SEND_LD_TYPE_E_LDWB;
+ gather->size = size;
+ gather->addr = data;
+}
+
+/* Segment a TSO packet into 'gso_size' segments and append
+ * them to SQ for transfer
+ */
+static int nicvf_sq_append_tso(struct nicvf *nic, struct snd_queue *sq,
+ int qentry, struct sk_buff *skb)
+{
+ struct tso_t tso;
+ int seg_subdescs = 0, desc_cnt = 0;
+ int seg_len, total_len, data_left;
+ int hdr_qentry = qentry;
+ int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+
+ tso_start(skb, &tso);
+ total_len = skb->len - hdr_len;
+ while (total_len > 0) {
+ char *hdr;
+
+ /* Save Qentry for adding HDR_SUBDESC at the end */
+ hdr_qentry = qentry;
+
+ data_left = min_t(int, skb_shinfo(skb)->gso_size, total_len);
+ total_len -= data_left;
+
+ /* Add segment's header */
+ qentry = nicvf_get_nxt_sqentry(sq, qentry);
+ hdr = sq->tso_hdrs + qentry * TSO_HEADER_SIZE;
+ tso_build_hdr(skb, hdr, &tso, data_left, total_len == 0);
+ nicvf_sq_add_gather_subdesc(sq, qentry, hdr_len,
+ sq->tso_hdrs_phys +
+ qentry * TSO_HEADER_SIZE);
+ /* HDR_SUDESC + GATHER */
+ seg_subdescs = 2;
+ seg_len = hdr_len;
+
+ /* Add segment's payload fragments */
+ while (data_left > 0) {
+ int size;
+
+ size = min_t(int, tso.size, data_left);
+
+ qentry = nicvf_get_nxt_sqentry(sq, qentry);
+ nicvf_sq_add_gather_subdesc(sq, qentry, size,
+ virt_to_phys(tso.data));
+ seg_subdescs++;
+ seg_len += size;
+
+ data_left -= size;
+ tso_build_data(skb, &tso, size);
+ }
+ nicvf_sq_add_hdr_subdesc(sq, hdr_qentry,
+ seg_subdescs - 1, skb, seg_len);
+ sq->skbuff[hdr_qentry] = 0;
+ qentry = nicvf_get_nxt_sqentry(sq, qentry);
+
+ desc_cnt += seg_subdescs;
+ }
+ /* Save SKB in the last segment for freeing */
+ sq->skbuff[hdr_qentry] = (u64)skb;
+
+ /* make sure all memory stores are done before ringing doorbell */
+ smp_wmb();
+
+ /* Inform HW to xmit all TSO segments */
+ nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_DOOR,
+ skb_get_queue_mapping(skb), desc_cnt);
+ return 1;
+}
+
+/* Append an skb to a SQ for packet transfer. */
+int nicvf_sq_append_skb(struct nicvf *nic, struct sk_buff *skb)
+{
+ int i, size;
+ int subdesc_cnt;
+ int sq_num, qentry;
+ struct queue_set *qs = nic->qs;
+ struct snd_queue *sq;
+
+ sq_num = skb_get_queue_mapping(skb);
+ sq = &qs->sq[sq_num];
+
+ subdesc_cnt = nicvf_sq_subdesc_required(nic, skb);
+ if (subdesc_cnt > atomic_read(&sq->free_cnt))
+ goto append_fail;
+
+ qentry = nicvf_get_sq_desc(sq, subdesc_cnt);
+
+ /* Check if its a TSO packet */
+ if (skb_shinfo(skb)->gso_size)
+ return nicvf_sq_append_tso(nic, sq, qentry, skb);
+
+ /* Add SQ header subdesc */
+ nicvf_sq_add_hdr_subdesc(sq, qentry, subdesc_cnt - 1, skb, skb->len);
+
+ /* Add SQ gather subdescs */
+ qentry = nicvf_get_nxt_sqentry(sq, qentry);
+ size = skb_is_nonlinear(skb) ? skb_headlen(skb) : skb->len;
+ nicvf_sq_add_gather_subdesc(sq, qentry, size, virt_to_phys(skb->data));
+
+ /* Check for scattered buffer */
+ if (!skb_is_nonlinear(skb))
+ goto doorbell;
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ const struct skb_frag_struct *frag;
+
+ frag = &skb_shinfo(skb)->frags[i];
+
+ qentry = nicvf_get_nxt_sqentry(sq, qentry);
+ size = skb_frag_size(frag);
+ nicvf_sq_add_gather_subdesc(sq, qentry, size,
+ virt_to_phys(
+ skb_frag_address(frag)));
+ }
+
+doorbell:
+ /* make sure all memory stores are done before ringing doorbell */
+ smp_wmb();
+
+ /* Inform HW to xmit new packet */
+ nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_DOOR,
+ sq_num, subdesc_cnt);
+ return 1;
+
+append_fail:
+ netdev_dbg(nic->netdev, "Not enough SQ descriptors to xmit pkt\n");
+ return 0;
+}
+
+static inline unsigned frag_num(unsigned i)
+{
+#ifdef __BIG_ENDIAN
+ return (i & ~3) + 3 - (i & 3);
+#else
+ return i;
+#endif
+}
+
+/* Returns SKB for a received packet */
+struct sk_buff *nicvf_get_rcv_skb(struct nicvf *nic, struct cqe_rx_t *cqe_rx)
+{
+ int frag;
+ int payload_len = 0;
+ struct sk_buff *skb = NULL;
+ struct sk_buff *skb_frag = NULL;
+ struct sk_buff *prev_frag = NULL;
+ u16 *rb_lens = NULL;
+ u64 *rb_ptrs = NULL;
+
+ rb_lens = (void *)cqe_rx + (3 * sizeof(u64));
+ rb_ptrs = (void *)cqe_rx + (6 * sizeof(u64));
+
+ netdev_dbg(nic->netdev, "%s rb_cnt %d rb0_ptr %llx rb0_sz %d\n",
+ __func__, cqe_rx->rb_cnt, cqe_rx->rb0_ptr, cqe_rx->rb0_sz);
+
+ for (frag = 0; frag < cqe_rx->rb_cnt; frag++) {
+ payload_len = rb_lens[frag_num(frag)];
+ if (!frag) {
+ /* First fragment */
+ skb = nicvf_rb_ptr_to_skb(nic,
+ *rb_ptrs - cqe_rx->align_pad,
+ payload_len);
+ if (!skb)
+ return NULL;
+ skb_reserve(skb, cqe_rx->align_pad);
+ skb_put(skb, payload_len);
+ } else {
+ /* Add fragments */
+ skb_frag = nicvf_rb_ptr_to_skb(nic, *rb_ptrs,
+ payload_len);
+ if (!skb_frag) {
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+
+ if (!skb_shinfo(skb)->frag_list)
+ skb_shinfo(skb)->frag_list = skb_frag;
+ else
+ prev_frag->next = skb_frag;
+
+ prev_frag = skb_frag;
+ skb->len += payload_len;
+ skb->data_len += payload_len;
+ skb_frag->len = payload_len;
+ }
+ /* Next buffer pointer */
+ rb_ptrs++;
+ }
+ return skb;
+}
+
+/* Enable interrupt */
+void nicvf_enable_intr(struct nicvf *nic, int int_type, int q_idx)
+{
+ u64 reg_val;
+
+ reg_val = nicvf_reg_read(nic, NIC_VF_ENA_W1S);
+
+ switch (int_type) {
+ case NICVF_INTR_CQ:
+ reg_val |= ((1ULL << q_idx) << NICVF_INTR_CQ_SHIFT);
+ break;
+ case NICVF_INTR_SQ:
+ reg_val |= ((1ULL << q_idx) << NICVF_INTR_SQ_SHIFT);
+ break;
+ case NICVF_INTR_RBDR:
+ reg_val |= ((1ULL << q_idx) << NICVF_INTR_RBDR_SHIFT);
+ break;
+ case NICVF_INTR_PKT_DROP:
+ reg_val |= (1ULL << NICVF_INTR_PKT_DROP_SHIFT);
+ break;
+ case NICVF_INTR_TCP_TIMER:
+ reg_val |= (1ULL << NICVF_INTR_TCP_TIMER_SHIFT);
+ break;
+ case NICVF_INTR_MBOX:
+ reg_val |= (1ULL << NICVF_INTR_MBOX_SHIFT);
+ break;
+ case NICVF_INTR_QS_ERR:
+ reg_val |= (1ULL << NICVF_INTR_QS_ERR_SHIFT);
+ break;
+ default:
+ netdev_err(nic->netdev,
+ "Failed to enable interrupt: unknown type\n");
+ break;
+ }
+
+ nicvf_reg_write(nic, NIC_VF_ENA_W1S, reg_val);
+}
+
+/* Disable interrupt */
+void nicvf_disable_intr(struct nicvf *nic, int int_type, int q_idx)
+{
+ u64 reg_val = 0;
+
+ switch (int_type) {
+ case NICVF_INTR_CQ:
+ reg_val |= ((1ULL << q_idx) << NICVF_INTR_CQ_SHIFT);
+ break;
+ case NICVF_INTR_SQ:
+ reg_val |= ((1ULL << q_idx) << NICVF_INTR_SQ_SHIFT);
+ break;
+ case NICVF_INTR_RBDR:
+ reg_val |= ((1ULL << q_idx) << NICVF_INTR_RBDR_SHIFT);
+ break;
+ case NICVF_INTR_PKT_DROP:
+ reg_val |= (1ULL << NICVF_INTR_PKT_DROP_SHIFT);
+ break;
+ case NICVF_INTR_TCP_TIMER:
+ reg_val |= (1ULL << NICVF_INTR_TCP_TIMER_SHIFT);
+ break;
+ case NICVF_INTR_MBOX:
+ reg_val |= (1ULL << NICVF_INTR_MBOX_SHIFT);
+ break;
+ case NICVF_INTR_QS_ERR:
+ reg_val |= (1ULL << NICVF_INTR_QS_ERR_SHIFT);
+ break;
+ default:
+ netdev_err(nic->netdev,
+ "Failed to disable interrupt: unknown type\n");
+ break;
+ }
+
+ nicvf_reg_write(nic, NIC_VF_ENA_W1C, reg_val);
+}
+
+/* Clear interrupt */
+void nicvf_clear_intr(struct nicvf *nic, int int_type, int q_idx)
+{
+ u64 reg_val = 0;
+
+ switch (int_type) {
+ case NICVF_INTR_CQ:
+ reg_val = ((1ULL << q_idx) << NICVF_INTR_CQ_SHIFT);
+ break;
+ case NICVF_INTR_SQ:
+ reg_val = ((1ULL << q_idx) << NICVF_INTR_SQ_SHIFT);
+ break;
+ case NICVF_INTR_RBDR:
+ reg_val = ((1ULL << q_idx) << NICVF_INTR_RBDR_SHIFT);
+ break;
+ case NICVF_INTR_PKT_DROP:
+ reg_val = (1ULL << NICVF_INTR_PKT_DROP_SHIFT);
+ break;
+ case NICVF_INTR_TCP_TIMER:
+ reg_val = (1ULL << NICVF_INTR_TCP_TIMER_SHIFT);
+ break;
+ case NICVF_INTR_MBOX:
+ reg_val = (1ULL << NICVF_INTR_MBOX_SHIFT);
+ break;
+ case NICVF_INTR_QS_ERR:
+ reg_val |= (1ULL << NICVF_INTR_QS_ERR_SHIFT);
+ break;
+ default:
+ netdev_err(nic->netdev,
+ "Failed to clear interrupt: unknown type\n");
+ break;
+ }
+
+ nicvf_reg_write(nic, NIC_VF_INT, reg_val);
+}
+
+/* Check if interrupt is enabled */
+int nicvf_is_intr_enabled(struct nicvf *nic, int int_type, int q_idx)
+{
+ u64 reg_val;
+ u64 mask = 0xff;
+
+ reg_val = nicvf_reg_read(nic, NIC_VF_ENA_W1S);
+
+ switch (int_type) {
+ case NICVF_INTR_CQ:
+ mask = ((1ULL << q_idx) << NICVF_INTR_CQ_SHIFT);
+ break;
+ case NICVF_INTR_SQ:
+ mask = ((1ULL << q_idx) << NICVF_INTR_SQ_SHIFT);
+ break;
+ case NICVF_INTR_RBDR:
+ mask = ((1ULL << q_idx) << NICVF_INTR_RBDR_SHIFT);
+ break;
+ case NICVF_INTR_PKT_DROP:
+ mask = NICVF_INTR_PKT_DROP_MASK;
+ break;
+ case NICVF_INTR_TCP_TIMER:
+ mask = NICVF_INTR_TCP_TIMER_MASK;
+ break;
+ case NICVF_INTR_MBOX:
+ mask = NICVF_INTR_MBOX_MASK;
+ break;
+ case NICVF_INTR_QS_ERR:
+ mask = NICVF_INTR_QS_ERR_MASK;
+ break;
+ default:
+ netdev_err(nic->netdev,
+ "Failed to check interrupt enable: unknown type\n");
+ break;
+ }
+
+ return (reg_val & mask);
+}
+
+void nicvf_update_rq_stats(struct nicvf *nic, int rq_idx)
+{
+ struct rcv_queue *rq;
+
+#define GET_RQ_STATS(reg) \
+ nicvf_reg_read(nic, NIC_QSET_RQ_0_7_STAT_0_1 |\
+ (rq_idx << NIC_Q_NUM_SHIFT) | (reg << 3))
+
+ rq = &nic->qs->rq[rq_idx];
+ rq->stats.bytes = GET_RQ_STATS(RQ_SQ_STATS_OCTS);
+ rq->stats.pkts = GET_RQ_STATS(RQ_SQ_STATS_PKTS);
+}
+
+void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx)
+{
+ struct snd_queue *sq;
+
+#define GET_SQ_STATS(reg) \
+ nicvf_reg_read(nic, NIC_QSET_SQ_0_7_STAT_0_1 |\
+ (sq_idx << NIC_Q_NUM_SHIFT) | (reg << 3))
+
+ sq = &nic->qs->sq[sq_idx];
+ sq->stats.bytes = GET_SQ_STATS(RQ_SQ_STATS_OCTS);
+ sq->stats.pkts = GET_SQ_STATS(RQ_SQ_STATS_PKTS);
+}
+
+/* Check for errors in the receive cmp.queue entry */
+int nicvf_check_cqe_rx_errs(struct nicvf *nic,
+ struct cmp_queue *cq, struct cqe_rx_t *cqe_rx)
+{
+ struct cmp_queue_stats *stats = &cq->stats;
+
+ if (!cqe_rx->err_level && !cqe_rx->err_opcode) {
+ stats->rx.errop.good++;
+ return 0;
+ }
+
+ if (netif_msg_rx_err(nic))
+ netdev_err(nic->netdev,
+ "%s: RX error CQE err_level 0x%x err_opcode 0x%x\n",
+ nic->netdev->name,
+ cqe_rx->err_level, cqe_rx->err_opcode);
+
+ switch (cqe_rx->err_level) {
+ case CQ_ERRLVL_MAC:
+ stats->rx.errlvl.mac_errs++;
+ break;
+ case CQ_ERRLVL_L2:
+ stats->rx.errlvl.l2_errs++;
+ break;
+ case CQ_ERRLVL_L3:
+ stats->rx.errlvl.l3_errs++;
+ break;
+ case CQ_ERRLVL_L4:
+ stats->rx.errlvl.l4_errs++;
+ break;
+ }
+
+ switch (cqe_rx->err_opcode) {
+ case CQ_RX_ERROP_RE_PARTIAL:
+ stats->rx.errop.partial_pkts++;
+ break;
+ case CQ_RX_ERROP_RE_JABBER:
+ stats->rx.errop.jabber_errs++;
+ break;
+ case CQ_RX_ERROP_RE_FCS:
+ stats->rx.errop.fcs_errs++;
+ break;
+ case CQ_RX_ERROP_RE_TERMINATE:
+ stats->rx.errop.terminate_errs++;
+ break;
+ case CQ_RX_ERROP_RE_RX_CTL:
+ stats->rx.errop.bgx_rx_errs++;
+ break;
+ case CQ_RX_ERROP_PREL2_ERR:
+ stats->rx.errop.prel2_errs++;
+ break;
+ case CQ_RX_ERROP_L2_FRAGMENT:
+ stats->rx.errop.l2_frags++;
+ break;
+ case CQ_RX_ERROP_L2_OVERRUN:
+ stats->rx.errop.l2_overruns++;
+ break;
+ case CQ_RX_ERROP_L2_PFCS:
+ stats->rx.errop.l2_pfcs++;
+ break;
+ case CQ_RX_ERROP_L2_PUNY:
+ stats->rx.errop.l2_puny++;
+ break;
+ case CQ_RX_ERROP_L2_MAL:
+ stats->rx.errop.l2_hdr_malformed++;
+ break;
+ case CQ_RX_ERROP_L2_OVERSIZE:
+ stats->rx.errop.l2_oversize++;
+ break;
+ case CQ_RX_ERROP_L2_UNDERSIZE:
+ stats->rx.errop.l2_undersize++;
+ break;
+ case CQ_RX_ERROP_L2_LENMISM:
+ stats->rx.errop.l2_len_mismatch++;
+ break;
+ case CQ_RX_ERROP_L2_PCLP:
+ stats->rx.errop.l2_pclp++;
+ break;
+ case CQ_RX_ERROP_IP_NOT:
+ stats->rx.errop.non_ip++;
+ break;
+ case CQ_RX_ERROP_IP_CSUM_ERR:
+ stats->rx.errop.ip_csum_err++;
+ break;
+ case CQ_RX_ERROP_IP_MAL:
+ stats->rx.errop.ip_hdr_malformed++;
+ break;
+ case CQ_RX_ERROP_IP_MALD:
+ stats->rx.errop.ip_payload_malformed++;
+ break;
+ case CQ_RX_ERROP_IP_HOP:
+ stats->rx.errop.ip_hop_errs++;
+ break;
+ case CQ_RX_ERROP_L3_ICRC:
+ stats->rx.errop.l3_icrc_errs++;
+ break;
+ case CQ_RX_ERROP_L3_PCLP:
+ stats->rx.errop.l3_pclp++;
+ break;
+ case CQ_RX_ERROP_L4_MAL:
+ stats->rx.errop.l4_malformed++;
+ break;
+ case CQ_RX_ERROP_L4_CHK:
+ stats->rx.errop.l4_csum_errs++;
+ break;
+ case CQ_RX_ERROP_UDP_LEN:
+ stats->rx.errop.udp_len_err++;
+ break;
+ case CQ_RX_ERROP_L4_PORT:
+ stats->rx.errop.bad_l4_port++;
+ break;
+ case CQ_RX_ERROP_TCP_FLAG:
+ stats->rx.errop.bad_tcp_flag++;
+ break;
+ case CQ_RX_ERROP_TCP_OFFSET:
+ stats->rx.errop.tcp_offset_errs++;
+ break;
+ case CQ_RX_ERROP_L4_PCLP:
+ stats->rx.errop.l4_pclp++;
+ break;
+ case CQ_RX_ERROP_RBDR_TRUNC:
+ stats->rx.errop.pkt_truncated++;
+ break;
+ }
+
+ return 1;
+}
+
+/* Check for errors in the send cmp.queue entry */
+int nicvf_check_cqe_tx_errs(struct nicvf *nic,
+ struct cmp_queue *cq, struct cqe_send_t *cqe_tx)
+{
+ struct cmp_queue_stats *stats = &cq->stats;
+
+ switch (cqe_tx->send_status) {
+ case CQ_TX_ERROP_GOOD:
+ stats->tx.good++;
+ return 0;
+ case CQ_TX_ERROP_DESC_FAULT:
+ stats->tx.desc_fault++;
+ break;
+ case CQ_TX_ERROP_HDR_CONS_ERR:
+ stats->tx.hdr_cons_err++;
+ break;
+ case CQ_TX_ERROP_SUBDC_ERR:
+ stats->tx.subdesc_err++;
+ break;
+ case CQ_TX_ERROP_IMM_SIZE_OFLOW:
+ stats->tx.imm_size_oflow++;
+ break;
+ case CQ_TX_ERROP_DATA_SEQUENCE_ERR:
+ stats->tx.data_seq_err++;
+ break;
+ case CQ_TX_ERROP_MEM_SEQUENCE_ERR:
+ stats->tx.mem_seq_err++;
+ break;
+ case CQ_TX_ERROP_LOCK_VIOL:
+ stats->tx.lock_viol++;
+ break;
+ case CQ_TX_ERROP_DATA_FAULT:
+ stats->tx.data_fault++;
+ break;
+ case CQ_TX_ERROP_TSTMP_CONFLICT:
+ stats->tx.tstmp_conflict++;
+ break;
+ case CQ_TX_ERROP_TSTMP_TIMEOUT:
+ stats->tx.tstmp_timeout++;
+ break;
+ case CQ_TX_ERROP_MEM_FAULT:
+ stats->tx.mem_fault++;
+ break;
+ case CQ_TX_ERROP_CK_OVERLAP:
+ stats->tx.csum_overlap++;
+ break;
+ case CQ_TX_ERROP_CK_OFLOW:
+ stats->tx.csum_overflow++;
+ break;
+ }
+
+ return 1;
+}
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
new file mode 100644
index 000000000000..8341bdf755d1
--- /dev/null
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2015 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef NICVF_QUEUES_H
+#define NICVF_QUEUES_H
+
+#include <linux/netdevice.h>
+#include "q_struct.h"
+
+#define MAX_QUEUE_SET 128
+#define MAX_RCV_QUEUES_PER_QS 8
+#define MAX_RCV_BUF_DESC_RINGS_PER_QS 2
+#define MAX_SND_QUEUES_PER_QS 8
+#define MAX_CMP_QUEUES_PER_QS 8
+
+/* VF's queue interrupt ranges */
+#define NICVF_INTR_ID_CQ 0
+#define NICVF_INTR_ID_SQ 8
+#define NICVF_INTR_ID_RBDR 16
+#define NICVF_INTR_ID_MISC 18
+#define NICVF_INTR_ID_QS_ERR 19
+
+#define for_each_cq_irq(irq) \
+ for (irq = NICVF_INTR_ID_CQ; irq < NICVF_INTR_ID_SQ; irq++)
+#define for_each_sq_irq(irq) \
+ for (irq = NICVF_INTR_ID_SQ; irq < NICVF_INTR_ID_RBDR; irq++)
+#define for_each_rbdr_irq(irq) \
+ for (irq = NICVF_INTR_ID_RBDR; irq < NICVF_INTR_ID_MISC; irq++)
+
+#define RBDR_SIZE0 0ULL /* 8K entries */
+#define RBDR_SIZE1 1ULL /* 16K entries */
+#define RBDR_SIZE2 2ULL /* 32K entries */
+#define RBDR_SIZE3 3ULL /* 64K entries */
+#define RBDR_SIZE4 4ULL /* 126K entries */
+#define RBDR_SIZE5 5ULL /* 256K entries */
+#define RBDR_SIZE6 6ULL /* 512K entries */
+
+#define SND_QUEUE_SIZE0 0ULL /* 1K entries */
+#define SND_QUEUE_SIZE1 1ULL /* 2K entries */
+#define SND_QUEUE_SIZE2 2ULL /* 4K entries */
+#define SND_QUEUE_SIZE3 3ULL /* 8K entries */
+#define SND_QUEUE_SIZE4 4ULL /* 16K entries */
+#define SND_QUEUE_SIZE5 5ULL /* 32K entries */
+#define SND_QUEUE_SIZE6 6ULL /* 64K entries */
+
+#define CMP_QUEUE_SIZE0 0ULL /* 1K entries */
+#define CMP_QUEUE_SIZE1 1ULL /* 2K entries */
+#define CMP_QUEUE_SIZE2 2ULL /* 4K entries */
+#define CMP_QUEUE_SIZE3 3ULL /* 8K entries */
+#define CMP_QUEUE_SIZE4 4ULL /* 16K entries */
+#define CMP_QUEUE_SIZE5 5ULL /* 32K entries */
+#define CMP_QUEUE_SIZE6 6ULL /* 64K entries */
+
+/* Default queue count per QS, its lengths and threshold values */
+#define RBDR_CNT 1
+#define RCV_QUEUE_CNT 8
+#define SND_QUEUE_CNT 8
+#define CMP_QUEUE_CNT 8 /* Max of RCV and SND qcount */
+
+#define SND_QSIZE SND_QUEUE_SIZE4
+#define SND_QUEUE_LEN (1ULL << (SND_QSIZE + 10))
+#define MAX_SND_QUEUE_LEN (1ULL << (SND_QUEUE_SIZE6 + 10))
+#define SND_QUEUE_THRESH 2ULL
+#define MIN_SQ_DESC_PER_PKT_XMIT 2
+/* Since timestamp not enabled, otherwise 2 */
+#define MAX_CQE_PER_PKT_XMIT 1
+
+#define CMP_QSIZE CMP_QUEUE_SIZE4
+#define CMP_QUEUE_LEN (1ULL << (CMP_QSIZE + 10))
+#define CMP_QUEUE_CQE_THRESH 0
+#define CMP_QUEUE_TIMER_THRESH 220 /* 10usec */
+
+#define RBDR_SIZE RBDR_SIZE0
+#define RCV_BUF_COUNT (1ULL << (RBDR_SIZE + 13))
+#define MAX_RCV_BUF_COUNT (1ULL << (RBDR_SIZE6 + 13))
+#define RBDR_THRESH (RCV_BUF_COUNT / 2)
+#define DMA_BUFFER_LEN 2048 /* In multiples of 128bytes */
+#define RCV_FRAG_LEN (SKB_DATA_ALIGN(DMA_BUFFER_LEN + NET_SKB_PAD) + \
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) + \
+ (NICVF_RCV_BUF_ALIGN_BYTES * 2))
+#define RCV_DATA_OFFSET NICVF_RCV_BUF_ALIGN_BYTES
+
+#define MAX_CQES_FOR_TX ((SND_QUEUE_LEN / MIN_SQ_DESC_PER_PKT_XMIT) * \
+ MAX_CQE_PER_PKT_XMIT)
+#define RQ_CQ_DROP ((CMP_QUEUE_LEN - MAX_CQES_FOR_TX) / 256)
+
+/* Descriptor size in bytes */
+#define SND_QUEUE_DESC_SIZE 16
+#define CMP_QUEUE_DESC_SIZE 512
+
+/* Buffer / descriptor alignments */
+#define NICVF_RCV_BUF_ALIGN 7
+#define NICVF_RCV_BUF_ALIGN_BYTES (1ULL << NICVF_RCV_BUF_ALIGN)
+#define NICVF_CQ_BASE_ALIGN_BYTES 512 /* 9 bits */
+#define NICVF_SQ_BASE_ALIGN_BYTES 128 /* 7 bits */
+
+#define NICVF_ALIGNED_ADDR(ADDR, ALIGN_BYTES) ALIGN(ADDR, ALIGN_BYTES)
+#define NICVF_ADDR_ALIGN_LEN(ADDR, BYTES)\
+ (NICVF_ALIGNED_ADDR(ADDR, BYTES) - BYTES)
+#define NICVF_RCV_BUF_ALIGN_LEN(X)\
+ (NICVF_ALIGNED_ADDR(X, NICVF_RCV_BUF_ALIGN_BYTES) - X)
+
+/* Queue enable/disable */
+#define NICVF_SQ_EN BIT_ULL(19)
+
+/* Queue reset */
+#define NICVF_CQ_RESET BIT_ULL(41)
+#define NICVF_SQ_RESET BIT_ULL(17)
+#define NICVF_RBDR_RESET BIT_ULL(43)
+
+enum CQ_RX_ERRLVL_E {
+ CQ_ERRLVL_MAC,
+ CQ_ERRLVL_L2,
+ CQ_ERRLVL_L3,
+ CQ_ERRLVL_L4,
+};
+
+enum CQ_RX_ERROP_E {
+ CQ_RX_ERROP_RE_NONE = 0x0,
+ CQ_RX_ERROP_RE_PARTIAL = 0x1,
+ CQ_RX_ERROP_RE_JABBER = 0x2,
+ CQ_RX_ERROP_RE_FCS = 0x7,
+ CQ_RX_ERROP_RE_TERMINATE = 0x9,
+ CQ_RX_ERROP_RE_RX_CTL = 0xb,
+ CQ_RX_ERROP_PREL2_ERR = 0x1f,
+ CQ_RX_ERROP_L2_FRAGMENT = 0x20,
+ CQ_RX_ERROP_L2_OVERRUN = 0x21,
+ CQ_RX_ERROP_L2_PFCS = 0x22,
+ CQ_RX_ERROP_L2_PUNY = 0x23,
+ CQ_RX_ERROP_L2_MAL = 0x24,
+ CQ_RX_ERROP_L2_OVERSIZE = 0x25,
+ CQ_RX_ERROP_L2_UNDERSIZE = 0x26,
+ CQ_RX_ERROP_L2_LENMISM = 0x27,
+ CQ_RX_ERROP_L2_PCLP = 0x28,
+ CQ_RX_ERROP_IP_NOT = 0x41,
+ CQ_RX_ERROP_IP_CSUM_ERR = 0x42,
+ CQ_RX_ERROP_IP_MAL = 0x43,
+ CQ_RX_ERROP_IP_MALD = 0x44,
+ CQ_RX_ERROP_IP_HOP = 0x45,
+ CQ_RX_ERROP_L3_ICRC = 0x46,
+ CQ_RX_ERROP_L3_PCLP = 0x47,
+ CQ_RX_ERROP_L4_MAL = 0x61,
+ CQ_RX_ERROP_L4_CHK = 0x62,
+ CQ_RX_ERROP_UDP_LEN = 0x63,
+ CQ_RX_ERROP_L4_PORT = 0x64,
+ CQ_RX_ERROP_TCP_FLAG = 0x65,
+ CQ_RX_ERROP_TCP_OFFSET = 0x66,
+ CQ_RX_ERROP_L4_PCLP = 0x67,
+ CQ_RX_ERROP_RBDR_TRUNC = 0x70,
+};
+
+enum CQ_TX_ERROP_E {
+ CQ_TX_ERROP_GOOD = 0x0,
+ CQ_TX_ERROP_DESC_FAULT = 0x10,
+ CQ_TX_ERROP_HDR_CONS_ERR = 0x11,
+ CQ_TX_ERROP_SUBDC_ERR = 0x12,
+ CQ_TX_ERROP_IMM_SIZE_OFLOW = 0x80,
+ CQ_TX_ERROP_DATA_SEQUENCE_ERR = 0x81,
+ CQ_TX_ERROP_MEM_SEQUENCE_ERR = 0x82,
+ CQ_TX_ERROP_LOCK_VIOL = 0x83,
+ CQ_TX_ERROP_DATA_FAULT = 0x84,
+ CQ_TX_ERROP_TSTMP_CONFLICT = 0x85,
+ CQ_TX_ERROP_TSTMP_TIMEOUT = 0x86,
+ CQ_TX_ERROP_MEM_FAULT = 0x87,
+ CQ_TX_ERROP_CK_OVERLAP = 0x88,
+ CQ_TX_ERROP_CK_OFLOW = 0x89,
+ CQ_TX_ERROP_ENUM_LAST = 0x8a,
+};
+
+struct cmp_queue_stats {
+ struct rx_stats {
+ struct {
+ u64 mac_errs;
+ u64 l2_errs;
+ u64 l3_errs;
+ u64 l4_errs;
+ } errlvl;
+ struct {
+ u64 good;
+ u64 partial_pkts;
+ u64 jabber_errs;
+ u64 fcs_errs;
+ u64 terminate_errs;
+ u64 bgx_rx_errs;
+ u64 prel2_errs;
+ u64 l2_frags;
+ u64 l2_overruns;
+ u64 l2_pfcs;
+ u64 l2_puny;
+ u64 l2_hdr_malformed;
+ u64 l2_oversize;
+ u64 l2_undersize;
+ u64 l2_len_mismatch;
+ u64 l2_pclp;
+ u64 non_ip;
+ u64 ip_csum_err;
+ u64 ip_hdr_malformed;
+ u64 ip_payload_malformed;
+ u64 ip_hop_errs;
+ u64 l3_icrc_errs;
+ u64 l3_pclp;
+ u64 l4_malformed;
+ u64 l4_csum_errs;
+ u64 udp_len_err;
+ u64 bad_l4_port;
+ u64 bad_tcp_flag;
+ u64 tcp_offset_errs;
+ u64 l4_pclp;
+ u64 pkt_truncated;
+ } errop;
+ } rx;
+ struct tx_stats {
+ u64 good;
+ u64 desc_fault;
+ u64 hdr_cons_err;
+ u64 subdesc_err;
+ u64 imm_size_oflow;
+ u64 data_seq_err;
+ u64 mem_seq_err;
+ u64 lock_viol;
+ u64 data_fault;
+ u64 tstmp_conflict;
+ u64 tstmp_timeout;
+ u64 mem_fault;
+ u64 csum_overlap;
+ u64 csum_overflow;
+ } tx;
+} ____cacheline_aligned_in_smp;
+
+enum RQ_SQ_STATS {
+ RQ_SQ_STATS_OCTS,
+ RQ_SQ_STATS_PKTS,
+};
+
+struct rx_tx_queue_stats {
+ u64 bytes;
+ u64 pkts;
+} ____cacheline_aligned_in_smp;
+
+struct q_desc_mem {
+ dma_addr_t dma;
+ u64 size;
+ u16 q_len;
+ dma_addr_t phys_base;
+ void *base;
+ void *unalign_base;
+};
+
+struct rbdr {
+ bool enable;
+ u32 dma_size;
+ u32 frag_len;
+ u32 thresh; /* Threshold level for interrupt */
+ void *desc;
+ u32 head;
+ u32 tail;
+ struct q_desc_mem dmem;
+} ____cacheline_aligned_in_smp;
+
+struct rcv_queue {
+ bool enable;
+ struct rbdr *rbdr_start;
+ struct rbdr *rbdr_cont;
+ bool en_tcp_reassembly;
+ u8 cq_qs; /* CQ's QS to which this RQ is assigned */
+ u8 cq_idx; /* CQ index (0 to 7) in the QS */
+ u8 cont_rbdr_qs; /* Continue buffer ptrs - QS num */
+ u8 cont_qs_rbdr_idx; /* RBDR idx in the cont QS */
+ u8 start_rbdr_qs; /* First buffer ptrs - QS num */
+ u8 start_qs_rbdr_idx; /* RBDR idx in the above QS */
+ u8 caching;
+ struct rx_tx_queue_stats stats;
+} ____cacheline_aligned_in_smp;
+
+struct cmp_queue {
+ bool enable;
+ u16 thresh;
+ spinlock_t lock; /* lock to serialize processing CQEs */
+ void *desc;
+ struct q_desc_mem dmem;
+ struct cmp_queue_stats stats;
+} ____cacheline_aligned_in_smp;
+
+struct snd_queue {
+ bool enable;
+ u8 cq_qs; /* CQ's QS to which this SQ is pointing */
+ u8 cq_idx; /* CQ index (0 to 7) in the above QS */
+ u16 thresh;
+ atomic_t free_cnt;
+ u32 head;
+ u32 tail;
+ u64 *skbuff;
+ void *desc;
+
+#define TSO_HEADER_SIZE 128
+ /* For TSO segment's header */
+ char *tso_hdrs;
+ dma_addr_t tso_hdrs_phys;
+
+ cpumask_t affinity_mask;
+ struct q_desc_mem dmem;
+ struct rx_tx_queue_stats stats;
+} ____cacheline_aligned_in_smp;
+
+struct queue_set {
+ bool enable;
+ bool be_en;
+ u8 vnic_id;
+ u8 rq_cnt;
+ u8 cq_cnt;
+ u64 cq_len;
+ u8 sq_cnt;
+ u64 sq_len;
+ u8 rbdr_cnt;
+ u64 rbdr_len;
+ struct rcv_queue rq[MAX_RCV_QUEUES_PER_QS];
+ struct cmp_queue cq[MAX_CMP_QUEUES_PER_QS];
+ struct snd_queue sq[MAX_SND_QUEUES_PER_QS];
+ struct rbdr rbdr[MAX_RCV_BUF_DESC_RINGS_PER_QS];
+} ____cacheline_aligned_in_smp;
+
+#define GET_RBDR_DESC(RING, idx)\
+ (&(((struct rbdr_entry_t *)((RING)->desc))[idx]))
+#define GET_SQ_DESC(RING, idx)\
+ (&(((struct sq_hdr_subdesc *)((RING)->desc))[idx]))
+#define GET_CQ_DESC(RING, idx)\
+ (&(((union cq_desc_t *)((RING)->desc))[idx]))
+
+/* CQ status bits */
+#define CQ_WR_FULL BIT(26)
+#define CQ_WR_DISABLE BIT(25)
+#define CQ_WR_FAULT BIT(24)
+#define CQ_CQE_COUNT (0xFFFF << 0)
+
+#define CQ_ERR_MASK (CQ_WR_FULL | CQ_WR_DISABLE | CQ_WR_FAULT)
+
+int nicvf_set_qset_resources(struct nicvf *nic);
+int nicvf_config_data_transfer(struct nicvf *nic, bool enable);
+void nicvf_qset_config(struct nicvf *nic, bool enable);
+void nicvf_cmp_queue_config(struct nicvf *nic, struct queue_set *qs,
+ int qidx, bool enable);
+
+void nicvf_sq_enable(struct nicvf *nic, struct snd_queue *sq, int qidx);
+void nicvf_sq_disable(struct nicvf *nic, int qidx);
+void nicvf_put_sq_desc(struct snd_queue *sq, int desc_cnt);
+void nicvf_sq_free_used_descs(struct net_device *netdev,
+ struct snd_queue *sq, int qidx);
+int nicvf_sq_append_skb(struct nicvf *nic, struct sk_buff *skb);
+
+struct sk_buff *nicvf_get_rcv_skb(struct nicvf *nic, struct cqe_rx_t *cqe_rx);
+void nicvf_rbdr_task(unsigned long data);
+void nicvf_rbdr_work(struct work_struct *work);
+
+void nicvf_enable_intr(struct nicvf *nic, int int_type, int q_idx);
+void nicvf_disable_intr(struct nicvf *nic, int int_type, int q_idx);
+void nicvf_clear_intr(struct nicvf *nic, int int_type, int q_idx);
+int nicvf_is_intr_enabled(struct nicvf *nic, int int_type, int q_idx);
+
+/* Register access APIs */
+void nicvf_reg_write(struct nicvf *nic, u64 offset, u64 val);
+u64 nicvf_reg_read(struct nicvf *nic, u64 offset);
+void nicvf_qset_reg_write(struct nicvf *nic, u64 offset, u64 val);
+u64 nicvf_qset_reg_read(struct nicvf *nic, u64 offset);
+void nicvf_queue_reg_write(struct nicvf *nic, u64 offset,
+ u64 qidx, u64 val);
+u64 nicvf_queue_reg_read(struct nicvf *nic,
+ u64 offset, u64 qidx);
+
+/* Stats */
+void nicvf_update_rq_stats(struct nicvf *nic, int rq_idx);
+void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx);
+int nicvf_check_cqe_rx_errs(struct nicvf *nic,
+ struct cmp_queue *cq, struct cqe_rx_t *cqe_rx);
+int nicvf_check_cqe_tx_errs(struct nicvf *nic,
+ struct cmp_queue *cq, struct cqe_send_t *cqe_tx);
+#endif /* NICVF_QUEUES_H */
diff --git a/drivers/net/ethernet/cavium/thunder/q_struct.h b/drivers/net/ethernet/cavium/thunder/q_struct.h
new file mode 100644
index 000000000000..3c1de97b1add
--- /dev/null
+++ b/drivers/net/ethernet/cavium/thunder/q_struct.h
@@ -0,0 +1,701 @@
+/*
+ * This file contains HW queue descriptor formats, config register
+ * structures etc
+ *
+ * Copyright (C) 2015 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef Q_STRUCT_H
+#define Q_STRUCT_H
+
+/* Load transaction types for reading segment bytes specified by
+ * NIC_SEND_GATHER_S[LD_TYPE].
+ */
+enum nic_send_ld_type_e {
+ NIC_SEND_LD_TYPE_E_LDD = 0x0,
+ NIC_SEND_LD_TYPE_E_LDT = 0x1,
+ NIC_SEND_LD_TYPE_E_LDWB = 0x2,
+ NIC_SEND_LD_TYPE_E_ENUM_LAST = 0x3,
+};
+
+enum ether_type_algorithm {
+ ETYPE_ALG_NONE = 0x0,
+ ETYPE_ALG_SKIP = 0x1,
+ ETYPE_ALG_ENDPARSE = 0x2,
+ ETYPE_ALG_VLAN = 0x3,
+ ETYPE_ALG_VLAN_STRIP = 0x4,
+};
+
+enum layer3_type {
+ L3TYPE_NONE = 0x00,
+ L3TYPE_GRH = 0x01,
+ L3TYPE_IPV4 = 0x04,
+ L3TYPE_IPV4_OPTIONS = 0x05,
+ L3TYPE_IPV6 = 0x06,
+ L3TYPE_IPV6_OPTIONS = 0x07,
+ L3TYPE_ET_STOP = 0x0D,
+ L3TYPE_OTHER = 0x0E,
+};
+
+enum layer4_type {
+ L4TYPE_NONE = 0x00,
+ L4TYPE_IPSEC_ESP = 0x01,
+ L4TYPE_IPFRAG = 0x02,
+ L4TYPE_IPCOMP = 0x03,
+ L4TYPE_TCP = 0x04,
+ L4TYPE_UDP = 0x05,
+ L4TYPE_SCTP = 0x06,
+ L4TYPE_GRE = 0x07,
+ L4TYPE_ROCE_BTH = 0x08,
+ L4TYPE_OTHER = 0x0E,
+};
+
+/* CPI and RSSI configuration */
+enum cpi_algorithm_type {
+ CPI_ALG_NONE = 0x0,
+ CPI_ALG_VLAN = 0x1,
+ CPI_ALG_VLAN16 = 0x2,
+ CPI_ALG_DIFF = 0x3,
+};
+
+enum rss_algorithm_type {
+ RSS_ALG_NONE = 0x00,
+ RSS_ALG_PORT = 0x01,
+ RSS_ALG_IP = 0x02,
+ RSS_ALG_TCP_IP = 0x03,
+ RSS_ALG_UDP_IP = 0x04,
+ RSS_ALG_SCTP_IP = 0x05,
+ RSS_ALG_GRE_IP = 0x06,
+ RSS_ALG_ROCE = 0x07,
+};
+
+enum rss_hash_cfg {
+ RSS_HASH_L2ETC = 0x00,
+ RSS_HASH_IP = 0x01,
+ RSS_HASH_TCP = 0x02,
+ RSS_HASH_TCP_SYN_DIS = 0x03,
+ RSS_HASH_UDP = 0x04,
+ RSS_HASH_L4ETC = 0x05,
+ RSS_HASH_ROCE = 0x06,
+ RSS_L3_BIDI = 0x07,
+ RSS_L4_BIDI = 0x08,
+};
+
+/* Completion queue entry types */
+enum cqe_type {
+ CQE_TYPE_INVALID = 0x0,
+ CQE_TYPE_RX = 0x2,
+ CQE_TYPE_RX_SPLIT = 0x3,
+ CQE_TYPE_RX_TCP = 0x4,
+ CQE_TYPE_SEND = 0x8,
+ CQE_TYPE_SEND_PTP = 0x9,
+};
+
+enum cqe_rx_tcp_status {
+ CQE_RX_STATUS_VALID_TCP_CNXT = 0x00,
+ CQE_RX_STATUS_INVALID_TCP_CNXT = 0x0F,
+};
+
+enum cqe_send_status {
+ CQE_SEND_STATUS_GOOD = 0x00,
+ CQE_SEND_STATUS_DESC_FAULT = 0x01,
+ CQE_SEND_STATUS_HDR_CONS_ERR = 0x11,
+ CQE_SEND_STATUS_SUBDESC_ERR = 0x12,
+ CQE_SEND_STATUS_IMM_SIZE_OFLOW = 0x80,
+ CQE_SEND_STATUS_CRC_SEQ_ERR = 0x81,
+ CQE_SEND_STATUS_DATA_SEQ_ERR = 0x82,
+ CQE_SEND_STATUS_MEM_SEQ_ERR = 0x83,
+ CQE_SEND_STATUS_LOCK_VIOL = 0x84,
+ CQE_SEND_STATUS_LOCK_UFLOW = 0x85,
+ CQE_SEND_STATUS_DATA_FAULT = 0x86,
+ CQE_SEND_STATUS_TSTMP_CONFLICT = 0x87,
+ CQE_SEND_STATUS_TSTMP_TIMEOUT = 0x88,
+ CQE_SEND_STATUS_MEM_FAULT = 0x89,
+ CQE_SEND_STATUS_CSUM_OVERLAP = 0x8A,
+ CQE_SEND_STATUS_CSUM_OVERFLOW = 0x8B,
+};
+
+enum cqe_rx_tcp_end_reason {
+ CQE_RX_TCP_END_FIN_FLAG_DET = 0,
+ CQE_RX_TCP_END_INVALID_FLAG = 1,
+ CQE_RX_TCP_END_TIMEOUT = 2,
+ CQE_RX_TCP_END_OUT_OF_SEQ = 3,
+ CQE_RX_TCP_END_PKT_ERR = 4,
+ CQE_RX_TCP_END_QS_DISABLED = 0x0F,
+};
+
+/* Packet protocol level error enumeration */
+enum cqe_rx_err_level {
+ CQE_RX_ERRLVL_RE = 0x0,
+ CQE_RX_ERRLVL_L2 = 0x1,
+ CQE_RX_ERRLVL_L3 = 0x2,
+ CQE_RX_ERRLVL_L4 = 0x3,
+};
+
+/* Packet protocol level error type enumeration */
+enum cqe_rx_err_opcode {
+ CQE_RX_ERR_RE_NONE = 0x0,
+ CQE_RX_ERR_RE_PARTIAL = 0x1,
+ CQE_RX_ERR_RE_JABBER = 0x2,
+ CQE_RX_ERR_RE_FCS = 0x7,
+ CQE_RX_ERR_RE_TERMINATE = 0x9,
+ CQE_RX_ERR_RE_RX_CTL = 0xb,
+ CQE_RX_ERR_PREL2_ERR = 0x1f,
+ CQE_RX_ERR_L2_FRAGMENT = 0x20,
+ CQE_RX_ERR_L2_OVERRUN = 0x21,
+ CQE_RX_ERR_L2_PFCS = 0x22,
+ CQE_RX_ERR_L2_PUNY = 0x23,
+ CQE_RX_ERR_L2_MAL = 0x24,
+ CQE_RX_ERR_L2_OVERSIZE = 0x25,
+ CQE_RX_ERR_L2_UNDERSIZE = 0x26,
+ CQE_RX_ERR_L2_LENMISM = 0x27,
+ CQE_RX_ERR_L2_PCLP = 0x28,
+ CQE_RX_ERR_IP_NOT = 0x41,
+ CQE_RX_ERR_IP_CHK = 0x42,
+ CQE_RX_ERR_IP_MAL = 0x43,
+ CQE_RX_ERR_IP_MALD = 0x44,
+ CQE_RX_ERR_IP_HOP = 0x45,
+ CQE_RX_ERR_L3_ICRC = 0x46,
+ CQE_RX_ERR_L3_PCLP = 0x47,
+ CQE_RX_ERR_L4_MAL = 0x61,
+ CQE_RX_ERR_L4_CHK = 0x62,
+ CQE_RX_ERR_UDP_LEN = 0x63,
+ CQE_RX_ERR_L4_PORT = 0x64,
+ CQE_RX_ERR_TCP_FLAG = 0x65,
+ CQE_RX_ERR_TCP_OFFSET = 0x66,
+ CQE_RX_ERR_L4_PCLP = 0x67,
+ CQE_RX_ERR_RBDR_TRUNC = 0x70,
+};
+
+struct cqe_rx_t {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 cqe_type:4; /* W0 */
+ u64 stdn_fault:1;
+ u64 rsvd0:1;
+ u64 rq_qs:7;
+ u64 rq_idx:3;
+ u64 rsvd1:12;
+ u64 rss_alg:4;
+ u64 rsvd2:4;
+ u64 rb_cnt:4;
+ u64 vlan_found:1;
+ u64 vlan_stripped:1;
+ u64 vlan2_found:1;
+ u64 vlan2_stripped:1;
+ u64 l4_type:4;
+ u64 l3_type:4;
+ u64 l2_present:1;
+ u64 err_level:3;
+ u64 err_opcode:8;
+
+ u64 pkt_len:16; /* W1 */
+ u64 l2_ptr:8;
+ u64 l3_ptr:8;
+ u64 l4_ptr:8;
+ u64 cq_pkt_len:8;
+ u64 align_pad:3;
+ u64 rsvd3:1;
+ u64 chan:12;
+
+ u64 rss_tag:32; /* W2 */
+ u64 vlan_tci:16;
+ u64 vlan_ptr:8;
+ u64 vlan2_ptr:8;
+
+ u64 rb3_sz:16; /* W3 */
+ u64 rb2_sz:16;
+ u64 rb1_sz:16;
+ u64 rb0_sz:16;
+
+ u64 rb7_sz:16; /* W4 */
+ u64 rb6_sz:16;
+ u64 rb5_sz:16;
+ u64 rb4_sz:16;
+
+ u64 rb11_sz:16; /* W5 */
+ u64 rb10_sz:16;
+ u64 rb9_sz:16;
+ u64 rb8_sz:16;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 err_opcode:8;
+ u64 err_level:3;
+ u64 l2_present:1;
+ u64 l3_type:4;
+ u64 l4_type:4;
+ u64 vlan2_stripped:1;
+ u64 vlan2_found:1;
+ u64 vlan_stripped:1;
+ u64 vlan_found:1;
+ u64 rb_cnt:4;
+ u64 rsvd2:4;
+ u64 rss_alg:4;
+ u64 rsvd1:12;
+ u64 rq_idx:3;
+ u64 rq_qs:7;
+ u64 rsvd0:1;
+ u64 stdn_fault:1;
+ u64 cqe_type:4; /* W0 */
+ u64 chan:12;
+ u64 rsvd3:1;
+ u64 align_pad:3;
+ u64 cq_pkt_len:8;
+ u64 l4_ptr:8;
+ u64 l3_ptr:8;
+ u64 l2_ptr:8;
+ u64 pkt_len:16; /* W1 */
+ u64 vlan2_ptr:8;
+ u64 vlan_ptr:8;
+ u64 vlan_tci:16;
+ u64 rss_tag:32; /* W2 */
+ u64 rb0_sz:16;
+ u64 rb1_sz:16;
+ u64 rb2_sz:16;
+ u64 rb3_sz:16; /* W3 */
+ u64 rb4_sz:16;
+ u64 rb5_sz:16;
+ u64 rb6_sz:16;
+ u64 rb7_sz:16; /* W4 */
+ u64 rb8_sz:16;
+ u64 rb9_sz:16;
+ u64 rb10_sz:16;
+ u64 rb11_sz:16; /* W5 */
+#endif
+ u64 rb0_ptr:64;
+ u64 rb1_ptr:64;
+ u64 rb2_ptr:64;
+ u64 rb3_ptr:64;
+ u64 rb4_ptr:64;
+ u64 rb5_ptr:64;
+ u64 rb6_ptr:64;
+ u64 rb7_ptr:64;
+ u64 rb8_ptr:64;
+ u64 rb9_ptr:64;
+ u64 rb10_ptr:64;
+ u64 rb11_ptr:64;
+};
+
+struct cqe_rx_tcp_err_t {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 cqe_type:4; /* W0 */
+ u64 rsvd0:60;
+
+ u64 rsvd1:4; /* W1 */
+ u64 partial_first:1;
+ u64 rsvd2:27;
+ u64 rbdr_bytes:8;
+ u64 rsvd3:24;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 rsvd0:60;
+ u64 cqe_type:4;
+
+ u64 rsvd3:24;
+ u64 rbdr_bytes:8;
+ u64 rsvd2:27;
+ u64 partial_first:1;
+ u64 rsvd1:4;
+#endif
+};
+
+struct cqe_rx_tcp_t {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 cqe_type:4; /* W0 */
+ u64 rsvd0:52;
+ u64 cq_tcp_status:8;
+
+ u64 rsvd1:32; /* W1 */
+ u64 tcp_cntx_bytes:8;
+ u64 rsvd2:8;
+ u64 tcp_err_bytes:16;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 cq_tcp_status:8;
+ u64 rsvd0:52;
+ u64 cqe_type:4; /* W0 */
+
+ u64 tcp_err_bytes:16;
+ u64 rsvd2:8;
+ u64 tcp_cntx_bytes:8;
+ u64 rsvd1:32; /* W1 */
+#endif
+};
+
+struct cqe_send_t {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 cqe_type:4; /* W0 */
+ u64 rsvd0:4;
+ u64 sqe_ptr:16;
+ u64 rsvd1:4;
+ u64 rsvd2:10;
+ u64 sq_qs:7;
+ u64 sq_idx:3;
+ u64 rsvd3:8;
+ u64 send_status:8;
+
+ u64 ptp_timestamp:64; /* W1 */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 send_status:8;
+ u64 rsvd3:8;
+ u64 sq_idx:3;
+ u64 sq_qs:7;
+ u64 rsvd2:10;
+ u64 rsvd1:4;
+ u64 sqe_ptr:16;
+ u64 rsvd0:4;
+ u64 cqe_type:4; /* W0 */
+
+ u64 ptp_timestamp:64; /* W1 */
+#endif
+};
+
+union cq_desc_t {
+ u64 u[64];
+ struct cqe_send_t snd_hdr;
+ struct cqe_rx_t rx_hdr;
+ struct cqe_rx_tcp_t rx_tcp_hdr;
+ struct cqe_rx_tcp_err_t rx_tcp_err_hdr;
+};
+
+struct rbdr_entry_t {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 rsvd0:15;
+ u64 buf_addr:42;
+ u64 cache_align:7;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 cache_align:7;
+ u64 buf_addr:42;
+ u64 rsvd0:15;
+#endif
+};
+
+/* TCP reassembly context */
+struct rbe_tcp_cnxt_t {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 tcp_pkt_cnt:12;
+ u64 rsvd1:4;
+ u64 align_hdr_bytes:4;
+ u64 align_ptr_bytes:4;
+ u64 ptr_bytes:16;
+ u64 rsvd2:24;
+ u64 cqe_type:4;
+ u64 rsvd0:54;
+ u64 tcp_end_reason:2;
+ u64 tcp_status:4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 tcp_status:4;
+ u64 tcp_end_reason:2;
+ u64 rsvd0:54;
+ u64 cqe_type:4;
+ u64 rsvd2:24;
+ u64 ptr_bytes:16;
+ u64 align_ptr_bytes:4;
+ u64 align_hdr_bytes:4;
+ u64 rsvd1:4;
+ u64 tcp_pkt_cnt:12;
+#endif
+};
+
+/* Always Big endian */
+struct rx_hdr_t {
+ u64 opaque:32;
+ u64 rss_flow:8;
+ u64 skip_length:6;
+ u64 disable_rss:1;
+ u64 disable_tcp_reassembly:1;
+ u64 nodrop:1;
+ u64 dest_alg:2;
+ u64 rsvd0:2;
+ u64 dest_rq:11;
+};
+
+enum send_l4_csum_type {
+ SEND_L4_CSUM_DISABLE = 0x00,
+ SEND_L4_CSUM_UDP = 0x01,
+ SEND_L4_CSUM_TCP = 0x02,
+ SEND_L4_CSUM_SCTP = 0x03,
+};
+
+enum send_crc_alg {
+ SEND_CRCALG_CRC32 = 0x00,
+ SEND_CRCALG_CRC32C = 0x01,
+ SEND_CRCALG_ICRC = 0x02,
+};
+
+enum send_load_type {
+ SEND_LD_TYPE_LDD = 0x00,
+ SEND_LD_TYPE_LDT = 0x01,
+ SEND_LD_TYPE_LDWB = 0x02,
+};
+
+enum send_mem_alg_type {
+ SEND_MEMALG_SET = 0x00,
+ SEND_MEMALG_ADD = 0x08,
+ SEND_MEMALG_SUB = 0x09,
+ SEND_MEMALG_ADDLEN = 0x0A,
+ SEND_MEMALG_SUBLEN = 0x0B,
+};
+
+enum send_mem_dsz_type {
+ SEND_MEMDSZ_B64 = 0x00,
+ SEND_MEMDSZ_B32 = 0x01,
+ SEND_MEMDSZ_B8 = 0x03,
+};
+
+enum sq_subdesc_type {
+ SQ_DESC_TYPE_INVALID = 0x00,
+ SQ_DESC_TYPE_HEADER = 0x01,
+ SQ_DESC_TYPE_CRC = 0x02,
+ SQ_DESC_TYPE_IMMEDIATE = 0x03,
+ SQ_DESC_TYPE_GATHER = 0x04,
+ SQ_DESC_TYPE_MEMORY = 0x05,
+};
+
+struct sq_crc_subdesc {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 rsvd1:32;
+ u64 crc_ival:32;
+ u64 subdesc_type:4;
+ u64 crc_alg:2;
+ u64 rsvd0:10;
+ u64 crc_insert_pos:16;
+ u64 hdr_start:16;
+ u64 crc_len:16;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 crc_len:16;
+ u64 hdr_start:16;
+ u64 crc_insert_pos:16;
+ u64 rsvd0:10;
+ u64 crc_alg:2;
+ u64 subdesc_type:4;
+ u64 crc_ival:32;
+ u64 rsvd1:32;
+#endif
+};
+
+struct sq_gather_subdesc {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 subdesc_type:4; /* W0 */
+ u64 ld_type:2;
+ u64 rsvd0:42;
+ u64 size:16;
+
+ u64 rsvd1:15; /* W1 */
+ u64 addr:49;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 size:16;
+ u64 rsvd0:42;
+ u64 ld_type:2;
+ u64 subdesc_type:4; /* W0 */
+
+ u64 addr:49;
+ u64 rsvd1:15; /* W1 */
+#endif
+};
+
+/* SQ immediate subdescriptor */
+struct sq_imm_subdesc {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 subdesc_type:4; /* W0 */
+ u64 rsvd0:46;
+ u64 len:14;
+
+ u64 data:64; /* W1 */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 len:14;
+ u64 rsvd0:46;
+ u64 subdesc_type:4; /* W0 */
+
+ u64 data:64; /* W1 */
+#endif
+};
+
+struct sq_mem_subdesc {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 subdesc_type:4; /* W0 */
+ u64 mem_alg:4;
+ u64 mem_dsz:2;
+ u64 wmem:1;
+ u64 rsvd0:21;
+ u64 offset:32;
+
+ u64 rsvd1:15; /* W1 */
+ u64 addr:49;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 offset:32;
+ u64 rsvd0:21;
+ u64 wmem:1;
+ u64 mem_dsz:2;
+ u64 mem_alg:4;
+ u64 subdesc_type:4; /* W0 */
+
+ u64 addr:49;
+ u64 rsvd1:15; /* W1 */
+#endif
+};
+
+struct sq_hdr_subdesc {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 subdesc_type:4;
+ u64 tso:1;
+ u64 post_cqe:1; /* Post CQE on no error also */
+ u64 dont_send:1;
+ u64 tstmp:1;
+ u64 subdesc_cnt:8;
+ u64 csum_l4:2;
+ u64 csum_l3:1;
+ u64 rsvd0:5;
+ u64 l4_offset:8;
+ u64 l3_offset:8;
+ u64 rsvd1:4;
+ u64 tot_len:20; /* W0 */
+
+ u64 tso_sdc_cont:8;
+ u64 tso_sdc_first:8;
+ u64 tso_l4_offset:8;
+ u64 tso_flags_last:12;
+ u64 tso_flags_first:12;
+ u64 rsvd2:2;
+ u64 tso_max_paysize:14; /* W1 */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 tot_len:20;
+ u64 rsvd1:4;
+ u64 l3_offset:8;
+ u64 l4_offset:8;
+ u64 rsvd0:5;
+ u64 csum_l3:1;
+ u64 csum_l4:2;
+ u64 subdesc_cnt:8;
+ u64 tstmp:1;
+ u64 dont_send:1;
+ u64 post_cqe:1; /* Post CQE on no error also */
+ u64 tso:1;
+ u64 subdesc_type:4; /* W0 */
+
+ u64 tso_max_paysize:14;
+ u64 rsvd2:2;
+ u64 tso_flags_first:12;
+ u64 tso_flags_last:12;
+ u64 tso_l4_offset:8;
+ u64 tso_sdc_first:8;
+ u64 tso_sdc_cont:8; /* W1 */
+#endif
+};
+
+/* Queue config register formats */
+struct rq_cfg {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 reserved_2_63:62;
+ u64 ena:1;
+ u64 tcp_ena:1;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 tcp_ena:1;
+ u64 ena:1;
+ u64 reserved_2_63:62;
+#endif
+};
+
+struct cq_cfg {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 reserved_43_63:21;
+ u64 ena:1;
+ u64 reset:1;
+ u64 caching:1;
+ u64 reserved_35_39:5;
+ u64 qsize:3;
+ u64 reserved_25_31:7;
+ u64 avg_con:9;
+ u64 reserved_0_15:16;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 reserved_0_15:16;
+ u64 avg_con:9;
+ u64 reserved_25_31:7;
+ u64 qsize:3;
+ u64 reserved_35_39:5;
+ u64 caching:1;
+ u64 reset:1;
+ u64 ena:1;
+ u64 reserved_43_63:21;
+#endif
+};
+
+struct sq_cfg {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 reserved_20_63:44;
+ u64 ena:1;
+ u64 reserved_18_18:1;
+ u64 reset:1;
+ u64 ldwb:1;
+ u64 reserved_11_15:5;
+ u64 qsize:3;
+ u64 reserved_3_7:5;
+ u64 tstmp_bgx_intf:3;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 tstmp_bgx_intf:3;
+ u64 reserved_3_7:5;
+ u64 qsize:3;
+ u64 reserved_11_15:5;
+ u64 ldwb:1;
+ u64 reset:1;
+ u64 reserved_18_18:1;
+ u64 ena:1;
+ u64 reserved_20_63:44;
+#endif
+};
+
+struct rbdr_cfg {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 reserved_45_63:19;
+ u64 ena:1;
+ u64 reset:1;
+ u64 ldwb:1;
+ u64 reserved_36_41:6;
+ u64 qsize:4;
+ u64 reserved_25_31:7;
+ u64 avg_con:9;
+ u64 reserved_12_15:4;
+ u64 lines:12;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 lines:12;
+ u64 reserved_12_15:4;
+ u64 avg_con:9;
+ u64 reserved_25_31:7;
+ u64 qsize:4;
+ u64 reserved_36_41:6;
+ u64 ldwb:1;
+ u64 reset:1;
+ u64 ena: 1;
+ u64 reserved_45_63:19;
+#endif
+};
+
+struct qs_cfg {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 reserved_32_63:32;
+ u64 ena:1;
+ u64 reserved_27_30:4;
+ u64 sq_ins_ena:1;
+ u64 sq_ins_pos:6;
+ u64 lock_ena:1;
+ u64 lock_viol_cqe_ena:1;
+ u64 send_tstmp_ena:1;
+ u64 be:1;
+ u64 reserved_7_15:9;
+ u64 vnic:7;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u64 vnic:7;
+ u64 reserved_7_15:9;
+ u64 be:1;
+ u64 send_tstmp_ena:1;
+ u64 lock_viol_cqe_ena:1;
+ u64 lock_ena:1;
+ u64 sq_ins_pos:6;
+ u64 sq_ins_ena:1;
+ u64 reserved_27_30:4;
+ u64 ena:1;
+ u64 reserved_32_63:32;
+#endif
+};
+
+#endif /* Q_STRUCT_H */
diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
new file mode 100644
index 000000000000..633ec05dfe05
--- /dev/null
+++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
@@ -0,0 +1,966 @@
+/*
+ * Copyright (C) 2015 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/phy.h>
+#include <linux/of.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+
+#include "nic_reg.h"
+#include "nic.h"
+#include "thunder_bgx.h"
+
+#define DRV_NAME "thunder-BGX"
+#define DRV_VERSION "1.0"
+
+struct lmac {
+ struct bgx *bgx;
+ int dmac;
+ unsigned char mac[ETH_ALEN];
+ bool link_up;
+ int lmacid; /* ID within BGX */
+ int lmacid_bd; /* ID on board */
+ struct net_device netdev;
+ struct phy_device *phydev;
+ unsigned int last_duplex;
+ unsigned int last_link;
+ unsigned int last_speed;
+ bool is_sgmii;
+ struct delayed_work dwork;
+ struct workqueue_struct *check_link;
+};
+
+struct bgx {
+ u8 bgx_id;
+ u8 qlm_mode;
+ struct lmac lmac[MAX_LMAC_PER_BGX];
+ int lmac_count;
+ int lmac_type;
+ int lane_to_sds;
+ int use_training;
+ void __iomem *reg_base;
+ struct pci_dev *pdev;
+};
+
+static struct bgx *bgx_vnic[MAX_BGX_THUNDER];
+static int lmac_count; /* Total no of LMACs in system */
+
+static int bgx_xaui_check_link(struct lmac *lmac);
+
+/* Supported devices */
+static const struct pci_device_id bgx_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_BGX) },
+ { 0, } /* end of table */
+};
+
+MODULE_AUTHOR("Cavium Inc");
+MODULE_DESCRIPTION("Cavium Thunder BGX/MAC Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, bgx_id_table);
+
+/* The Cavium ThunderX network controller can *only* be found in SoCs
+ * containing the ThunderX ARM64 CPU implementation. All accesses to the device
+ * registers on this platform are implicitly strongly ordered with respect
+ * to memory accesses. So writeq_relaxed() and readq_relaxed() are safe to use
+ * with no memory barriers in this driver. The readq()/writeq() functions add
+ * explicit ordering operation which in this case are redundant, and only
+ * add overhead.
+ */
+
+/* Register read/write APIs */
+static u64 bgx_reg_read(struct bgx *bgx, u8 lmac, u64 offset)
+{
+ void __iomem *addr = bgx->reg_base + ((u32)lmac << 20) + offset;
+
+ return readq_relaxed(addr);
+}
+
+static void bgx_reg_write(struct bgx *bgx, u8 lmac, u64 offset, u64 val)
+{
+ void __iomem *addr = bgx->reg_base + ((u32)lmac << 20) + offset;
+
+ writeq_relaxed(val, addr);
+}
+
+static void bgx_reg_modify(struct bgx *bgx, u8 lmac, u64 offset, u64 val)
+{
+ void __iomem *addr = bgx->reg_base + ((u32)lmac << 20) + offset;
+
+ writeq_relaxed(val | readq_relaxed(addr), addr);
+}
+
+static int bgx_poll_reg(struct bgx *bgx, u8 lmac, u64 reg, u64 mask, bool zero)
+{
+ int timeout = 100;
+ u64 reg_val;
+
+ while (timeout) {
+ reg_val = bgx_reg_read(bgx, lmac, reg);
+ if (zero && !(reg_val & mask))
+ return 0;
+ if (!zero && (reg_val & mask))
+ return 0;
+ usleep_range(1000, 2000);
+ timeout--;
+ }
+ return 1;
+}
+
+/* Return number of BGX present in HW */
+unsigned bgx_get_map(int node)
+{
+ int i;
+ unsigned map = 0;
+
+ for (i = 0; i < MAX_BGX_PER_CN88XX; i++) {
+ if (bgx_vnic[(node * MAX_BGX_PER_CN88XX) + i])
+ map |= (1 << i);
+ }
+
+ return map;
+}
+EXPORT_SYMBOL(bgx_get_map);
+
+/* Return number of LMAC configured for this BGX */
+int bgx_get_lmac_count(int node, int bgx_idx)
+{
+ struct bgx *bgx;
+
+ bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
+ if (bgx)
+ return bgx->lmac_count;
+
+ return 0;
+}
+EXPORT_SYMBOL(bgx_get_lmac_count);
+
+/* Returns the current link status of LMAC */
+void bgx_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status)
+{
+ struct bgx_link_status *link = (struct bgx_link_status *)status;
+ struct bgx *bgx;
+ struct lmac *lmac;
+
+ bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
+ if (!bgx)
+ return;
+
+ lmac = &bgx->lmac[lmacid];
+ link->link_up = lmac->link_up;
+ link->duplex = lmac->last_duplex;
+ link->speed = lmac->last_speed;
+}
+EXPORT_SYMBOL(bgx_get_lmac_link_state);
+
+const u8 *bgx_get_lmac_mac(int node, int bgx_idx, int lmacid)
+{
+ struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
+
+ if (bgx)
+ return bgx->lmac[lmacid].mac;
+
+ return NULL;
+}
+EXPORT_SYMBOL(bgx_get_lmac_mac);
+
+void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac)
+{
+ struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
+
+ if (!bgx)
+ return;
+
+ ether_addr_copy(bgx->lmac[lmacid].mac, mac);
+}
+EXPORT_SYMBOL(bgx_set_lmac_mac);
+
+static void bgx_sgmii_change_link_state(struct lmac *lmac)
+{
+ struct bgx *bgx = lmac->bgx;
+ u64 cmr_cfg;
+ u64 port_cfg = 0;
+ u64 misc_ctl = 0;
+
+ cmr_cfg = bgx_reg_read(bgx, lmac->lmacid, BGX_CMRX_CFG);
+ cmr_cfg &= ~CMR_EN;
+ bgx_reg_write(bgx, lmac->lmacid, BGX_CMRX_CFG, cmr_cfg);
+
+ port_cfg = bgx_reg_read(bgx, lmac->lmacid, BGX_GMP_GMI_PRTX_CFG);
+ misc_ctl = bgx_reg_read(bgx, lmac->lmacid, BGX_GMP_PCS_MISCX_CTL);
+
+ if (lmac->link_up) {
+ misc_ctl &= ~PCS_MISC_CTL_GMX_ENO;
+ port_cfg &= ~GMI_PORT_CFG_DUPLEX;
+ port_cfg |= (lmac->last_duplex << 2);
+ } else {
+ misc_ctl |= PCS_MISC_CTL_GMX_ENO;
+ }
+
+ switch (lmac->last_speed) {
+ case 10:
+ port_cfg &= ~GMI_PORT_CFG_SPEED; /* speed 0 */
+ port_cfg |= GMI_PORT_CFG_SPEED_MSB; /* speed_msb 1 */
+ port_cfg &= ~GMI_PORT_CFG_SLOT_TIME; /* slottime 0 */
+ misc_ctl &= ~PCS_MISC_CTL_SAMP_PT_MASK;
+ misc_ctl |= 50; /* samp_pt */
+ bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_GMI_TXX_SLOT, 64);
+ bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_GMI_TXX_BURST, 0);
+ break;
+ case 100:
+ port_cfg &= ~GMI_PORT_CFG_SPEED; /* speed 0 */
+ port_cfg &= ~GMI_PORT_CFG_SPEED_MSB; /* speed_msb 0 */
+ port_cfg &= ~GMI_PORT_CFG_SLOT_TIME; /* slottime 0 */
+ misc_ctl &= ~PCS_MISC_CTL_SAMP_PT_MASK;
+ misc_ctl |= 5; /* samp_pt */
+ bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_GMI_TXX_SLOT, 64);
+ bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_GMI_TXX_BURST, 0);
+ break;
+ case 1000:
+ port_cfg |= GMI_PORT_CFG_SPEED; /* speed 1 */
+ port_cfg &= ~GMI_PORT_CFG_SPEED_MSB; /* speed_msb 0 */
+ port_cfg |= GMI_PORT_CFG_SLOT_TIME; /* slottime 1 */
+ misc_ctl &= ~PCS_MISC_CTL_SAMP_PT_MASK;
+ misc_ctl |= 1; /* samp_pt */
+ bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_GMI_TXX_SLOT, 512);
+ if (lmac->last_duplex)
+ bgx_reg_write(bgx, lmac->lmacid,
+ BGX_GMP_GMI_TXX_BURST, 0);
+ else
+ bgx_reg_write(bgx, lmac->lmacid,
+ BGX_GMP_GMI_TXX_BURST, 8192);
+ break;
+ default:
+ break;
+ }
+ bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_PCS_MISCX_CTL, misc_ctl);
+ bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_GMI_PRTX_CFG, port_cfg);
+
+ port_cfg = bgx_reg_read(bgx, lmac->lmacid, BGX_GMP_GMI_PRTX_CFG);
+
+ /* renable lmac */
+ cmr_cfg |= CMR_EN;
+ bgx_reg_write(bgx, lmac->lmacid, BGX_CMRX_CFG, cmr_cfg);
+}
+
+static void bgx_lmac_handler(struct net_device *netdev)
+{
+ struct lmac *lmac = container_of(netdev, struct lmac, netdev);
+ struct phy_device *phydev = lmac->phydev;
+ int link_changed = 0;
+
+ if (!lmac)
+ return;
+
+ if (!phydev->link && lmac->last_link)
+ link_changed = -1;
+
+ if (phydev->link &&
+ (lmac->last_duplex != phydev->duplex ||
+ lmac->last_link != phydev->link ||
+ lmac->last_speed != phydev->speed)) {
+ link_changed = 1;
+ }
+
+ lmac->last_link = phydev->link;
+ lmac->last_speed = phydev->speed;
+ lmac->last_duplex = phydev->duplex;
+
+ if (!link_changed)
+ return;
+
+ if (link_changed > 0)
+ lmac->link_up = true;
+ else
+ lmac->link_up = false;
+
+ if (lmac->is_sgmii)
+ bgx_sgmii_change_link_state(lmac);
+ else
+ bgx_xaui_check_link(lmac);
+}
+
+u64 bgx_get_rx_stats(int node, int bgx_idx, int lmac, int idx)
+{
+ struct bgx *bgx;
+
+ bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
+ if (!bgx)
+ return 0;
+
+ if (idx > 8)
+ lmac = 0;
+ return bgx_reg_read(bgx, lmac, BGX_CMRX_RX_STAT0 + (idx * 8));
+}
+EXPORT_SYMBOL(bgx_get_rx_stats);
+
+u64 bgx_get_tx_stats(int node, int bgx_idx, int lmac, int idx)
+{
+ struct bgx *bgx;
+
+ bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
+ if (!bgx)
+ return 0;
+
+ return bgx_reg_read(bgx, lmac, BGX_CMRX_TX_STAT0 + (idx * 8));
+}
+EXPORT_SYMBOL(bgx_get_tx_stats);
+
+static void bgx_flush_dmac_addrs(struct bgx *bgx, int lmac)
+{
+ u64 offset;
+
+ while (bgx->lmac[lmac].dmac > 0) {
+ offset = ((bgx->lmac[lmac].dmac - 1) * sizeof(u64)) +
+ (lmac * MAX_DMAC_PER_LMAC * sizeof(u64));
+ bgx_reg_write(bgx, 0, BGX_CMR_RX_DMACX_CAM + offset, 0);
+ bgx->lmac[lmac].dmac--;
+ }
+}
+
+static int bgx_lmac_sgmii_init(struct bgx *bgx, int lmacid)
+{
+ u64 cfg;
+
+ bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_TXX_THRESH, 0x30);
+ /* max packet size */
+ bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_RXX_JABBER, MAX_FRAME_SIZE);
+
+ /* Disable frame alignment if using preamble */
+ cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_GMI_TXX_APPEND);
+ if (cfg & 1)
+ bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_SGMII_CTL, 0);
+
+ /* Enable lmac */
+ bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, CMR_EN);
+
+ /* PCS reset */
+ bgx_reg_modify(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, PCS_MRX_CTL_RESET);
+ if (bgx_poll_reg(bgx, lmacid, BGX_GMP_PCS_MRX_CTL,
+ PCS_MRX_CTL_RESET, true)) {
+ dev_err(&bgx->pdev->dev, "BGX PCS reset not completed\n");
+ return -1;
+ }
+
+ /* power down, reset autoneg, autoneg enable */
+ cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MRX_CTL);
+ cfg &= ~PCS_MRX_CTL_PWR_DN;
+ cfg |= (PCS_MRX_CTL_RST_AN | PCS_MRX_CTL_AN_EN);
+ bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, cfg);
+
+ if (bgx_poll_reg(bgx, lmacid, BGX_GMP_PCS_MRX_STATUS,
+ PCS_MRX_STATUS_AN_CPT, false)) {
+ dev_err(&bgx->pdev->dev, "BGX AN_CPT not completed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int bgx_lmac_xaui_init(struct bgx *bgx, int lmacid, int lmac_type)
+{
+ u64 cfg;
+
+ /* Reset SPU */
+ bgx_reg_modify(bgx, lmacid, BGX_SPUX_CONTROL1, SPU_CTL_RESET);
+ if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_CONTROL1, SPU_CTL_RESET, true)) {
+ dev_err(&bgx->pdev->dev, "BGX SPU reset not completed\n");
+ return -1;
+ }
+
+ /* Disable LMAC */
+ cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
+ cfg &= ~CMR_EN;
+ bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
+
+ bgx_reg_modify(bgx, lmacid, BGX_SPUX_CONTROL1, SPU_CTL_LOW_POWER);
+ /* Set interleaved running disparity for RXAUI */
+ if (bgx->lmac_type != BGX_MODE_RXAUI)
+ bgx_reg_modify(bgx, lmacid,
+ BGX_SPUX_MISC_CONTROL, SPU_MISC_CTL_RX_DIS);
+ else
+ bgx_reg_modify(bgx, lmacid, BGX_SPUX_MISC_CONTROL,
+ SPU_MISC_CTL_RX_DIS | SPU_MISC_CTL_INTLV_RDISP);
+
+ /* clear all interrupts */
+ cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_RX_INT);
+ bgx_reg_write(bgx, lmacid, BGX_SMUX_RX_INT, cfg);
+ cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_TX_INT);
+ bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_INT, cfg);
+ cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_INT);
+ bgx_reg_write(bgx, lmacid, BGX_SPUX_INT, cfg);
+
+ if (bgx->use_training) {
+ bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_LP_CUP, 0x00);
+ bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_LD_CUP, 0x00);
+ bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_LD_REP, 0x00);
+ /* training enable */
+ bgx_reg_modify(bgx, lmacid,
+ BGX_SPUX_BR_PMD_CRTL, SPU_PMD_CRTL_TRAIN_EN);
+ }
+
+ /* Append FCS to each packet */
+ bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_APPEND, SMU_TX_APPEND_FCS_D);
+
+ /* Disable forward error correction */
+ cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_FEC_CONTROL);
+ cfg &= ~SPU_FEC_CTL_FEC_EN;
+ bgx_reg_write(bgx, lmacid, BGX_SPUX_FEC_CONTROL, cfg);
+
+ /* Disable autoneg */
+ cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_AN_CONTROL);
+ cfg = cfg & ~(SPU_AN_CTL_AN_EN | SPU_AN_CTL_XNP_EN);
+ bgx_reg_write(bgx, lmacid, BGX_SPUX_AN_CONTROL, cfg);
+
+ cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_AN_ADV);
+ if (bgx->lmac_type == BGX_MODE_10G_KR)
+ cfg |= (1 << 23);
+ else if (bgx->lmac_type == BGX_MODE_40G_KR)
+ cfg |= (1 << 24);
+ else
+ cfg &= ~((1 << 23) | (1 << 24));
+ cfg = cfg & (~((1ULL << 25) | (1ULL << 22) | (1ULL << 12)));
+ bgx_reg_write(bgx, lmacid, BGX_SPUX_AN_ADV, cfg);
+
+ cfg = bgx_reg_read(bgx, 0, BGX_SPU_DBG_CONTROL);
+ cfg &= ~SPU_DBG_CTL_AN_ARB_LINK_CHK_EN;
+ bgx_reg_write(bgx, 0, BGX_SPU_DBG_CONTROL, cfg);
+
+ /* Enable lmac */
+ bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, CMR_EN);
+
+ cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_CONTROL1);
+ cfg &= ~SPU_CTL_LOW_POWER;
+ bgx_reg_write(bgx, lmacid, BGX_SPUX_CONTROL1, cfg);
+
+ cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_TX_CTL);
+ cfg &= ~SMU_TX_CTL_UNI_EN;
+ cfg |= SMU_TX_CTL_DIC_EN;
+ bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_CTL, cfg);
+
+ /* take lmac_count into account */
+ bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_THRESH, (0x100 - 1));
+ /* max packet size */
+ bgx_reg_modify(bgx, lmacid, BGX_SMUX_RX_JABBER, MAX_FRAME_SIZE);
+
+ return 0;
+}
+
+static int bgx_xaui_check_link(struct lmac *lmac)
+{
+ struct bgx *bgx = lmac->bgx;
+ int lmacid = lmac->lmacid;
+ int lmac_type = bgx->lmac_type;
+ u64 cfg;
+
+ bgx_reg_modify(bgx, lmacid, BGX_SPUX_MISC_CONTROL, SPU_MISC_CTL_RX_DIS);
+ if (bgx->use_training) {
+ cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_INT);
+ if (!(cfg & (1ull << 13))) {
+ cfg = (1ull << 13) | (1ull << 14);
+ bgx_reg_write(bgx, lmacid, BGX_SPUX_INT, cfg);
+ cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_BR_PMD_CRTL);
+ cfg |= (1ull << 0);
+ bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_CRTL, cfg);
+ return -1;
+ }
+ }
+
+ /* wait for PCS to come out of reset */
+ if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_CONTROL1, SPU_CTL_RESET, true)) {
+ dev_err(&bgx->pdev->dev, "BGX SPU reset not completed\n");
+ return -1;
+ }
+
+ if ((lmac_type == BGX_MODE_10G_KR) || (lmac_type == BGX_MODE_XFI) ||
+ (lmac_type == BGX_MODE_40G_KR) || (lmac_type == BGX_MODE_XLAUI)) {
+ if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_BR_STATUS1,
+ SPU_BR_STATUS_BLK_LOCK, false)) {
+ dev_err(&bgx->pdev->dev,
+ "SPU_BR_STATUS_BLK_LOCK not completed\n");
+ return -1;
+ }
+ } else {
+ if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_BX_STATUS,
+ SPU_BX_STATUS_RX_ALIGN, false)) {
+ dev_err(&bgx->pdev->dev,
+ "SPU_BX_STATUS_RX_ALIGN not completed\n");
+ return -1;
+ }
+ }
+
+ /* Clear rcvflt bit (latching high) and read it back */
+ bgx_reg_modify(bgx, lmacid, BGX_SPUX_STATUS2, SPU_STATUS2_RCVFLT);
+ if (bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS2) & SPU_STATUS2_RCVFLT) {
+ dev_err(&bgx->pdev->dev, "Receive fault, retry training\n");
+ if (bgx->use_training) {
+ cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_INT);
+ if (!(cfg & (1ull << 13))) {
+ cfg = (1ull << 13) | (1ull << 14);
+ bgx_reg_write(bgx, lmacid, BGX_SPUX_INT, cfg);
+ cfg = bgx_reg_read(bgx, lmacid,
+ BGX_SPUX_BR_PMD_CRTL);
+ cfg |= (1ull << 0);
+ bgx_reg_write(bgx, lmacid,
+ BGX_SPUX_BR_PMD_CRTL, cfg);
+ return -1;
+ }
+ }
+ return -1;
+ }
+
+ /* Wait for MAC RX to be ready */
+ if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_RX_CTL,
+ SMU_RX_CTL_STATUS, true)) {
+ dev_err(&bgx->pdev->dev, "SMU RX link not okay\n");
+ return -1;
+ }
+
+ /* Wait for BGX RX to be idle */
+ if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_CTL, SMU_CTL_RX_IDLE, false)) {
+ dev_err(&bgx->pdev->dev, "SMU RX not idle\n");
+ return -1;
+ }
+
+ /* Wait for BGX TX to be idle */
+ if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_CTL, SMU_CTL_TX_IDLE, false)) {
+ dev_err(&bgx->pdev->dev, "SMU TX not idle\n");
+ return -1;
+ }
+
+ if (bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS2) & SPU_STATUS2_RCVFLT) {
+ dev_err(&bgx->pdev->dev, "Receive fault\n");
+ return -1;
+ }
+
+ /* Receive link is latching low. Force it high and verify it */
+ bgx_reg_modify(bgx, lmacid, BGX_SPUX_STATUS1, SPU_STATUS1_RCV_LNK);
+ if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_STATUS1,
+ SPU_STATUS1_RCV_LNK, false)) {
+ dev_err(&bgx->pdev->dev, "SPU receive link down\n");
+ return -1;
+ }
+
+ cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_MISC_CONTROL);
+ cfg &= ~SPU_MISC_CTL_RX_DIS;
+ bgx_reg_write(bgx, lmacid, BGX_SPUX_MISC_CONTROL, cfg);
+ return 0;
+}
+
+static void bgx_poll_for_link(struct work_struct *work)
+{
+ struct lmac *lmac;
+ u64 link;
+
+ lmac = container_of(work, struct lmac, dwork.work);
+
+ /* Receive link is latching low. Force it high and verify it */
+ bgx_reg_modify(lmac->bgx, lmac->lmacid,
+ BGX_SPUX_STATUS1, SPU_STATUS1_RCV_LNK);
+ bgx_poll_reg(lmac->bgx, lmac->lmacid, BGX_SPUX_STATUS1,
+ SPU_STATUS1_RCV_LNK, false);
+
+ link = bgx_reg_read(lmac->bgx, lmac->lmacid, BGX_SPUX_STATUS1);
+ if (link & SPU_STATUS1_RCV_LNK) {
+ lmac->link_up = 1;
+ if (lmac->bgx->lmac_type == BGX_MODE_XLAUI)
+ lmac->last_speed = 40000;
+ else
+ lmac->last_speed = 10000;
+ lmac->last_duplex = 1;
+ } else {
+ lmac->link_up = 0;
+ }
+
+ if (lmac->last_link != lmac->link_up) {
+ lmac->last_link = lmac->link_up;
+ if (lmac->link_up)
+ bgx_xaui_check_link(lmac);
+ }
+
+ queue_delayed_work(lmac->check_link, &lmac->dwork, HZ * 2);
+}
+
+static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid)
+{
+ struct lmac *lmac;
+ u64 cfg;
+
+ lmac = &bgx->lmac[lmacid];
+ lmac->bgx = bgx;
+
+ if (bgx->lmac_type == BGX_MODE_SGMII) {
+ lmac->is_sgmii = 1;
+ if (bgx_lmac_sgmii_init(bgx, lmacid))
+ return -1;
+ } else {
+ lmac->is_sgmii = 0;
+ if (bgx_lmac_xaui_init(bgx, lmacid, bgx->lmac_type))
+ return -1;
+ }
+
+ if (lmac->is_sgmii) {
+ cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_GMI_TXX_APPEND);
+ cfg |= ((1ull << 2) | (1ull << 1)); /* FCS and PAD */
+ bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_TXX_APPEND, cfg);
+ bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_MIN_PKT, 60 - 1);
+ } else {
+ cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_TX_APPEND);
+ cfg |= ((1ull << 2) | (1ull << 1)); /* FCS and PAD */
+ bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_APPEND, cfg);
+ bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_MIN_PKT, 60 + 4);
+ }
+
+ /* Enable lmac */
+ bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG,
+ CMR_EN | CMR_PKT_RX_EN | CMR_PKT_TX_EN);
+
+ /* Restore default cfg, incase low level firmware changed it */
+ bgx_reg_write(bgx, lmacid, BGX_CMRX_RX_DMAC_CTL, 0x03);
+
+ if ((bgx->lmac_type != BGX_MODE_XFI) &&
+ (bgx->lmac_type != BGX_MODE_XLAUI) &&
+ (bgx->lmac_type != BGX_MODE_40G_KR) &&
+ (bgx->lmac_type != BGX_MODE_10G_KR)) {
+ if (!lmac->phydev)
+ return -ENODEV;
+
+ lmac->phydev->dev_flags = 0;
+
+ if (phy_connect_direct(&lmac->netdev, lmac->phydev,
+ bgx_lmac_handler,
+ PHY_INTERFACE_MODE_SGMII))
+ return -ENODEV;
+
+ phy_start_aneg(lmac->phydev);
+ } else {
+ lmac->check_link = alloc_workqueue("check_link", WQ_UNBOUND |
+ WQ_MEM_RECLAIM, 1);
+ if (!lmac->check_link)
+ return -ENOMEM;
+ INIT_DELAYED_WORK(&lmac->dwork, bgx_poll_for_link);
+ queue_delayed_work(lmac->check_link, &lmac->dwork, 0);
+ }
+
+ return 0;
+}
+
+static void bgx_lmac_disable(struct bgx *bgx, u8 lmacid)
+{
+ struct lmac *lmac;
+ u64 cmrx_cfg;
+
+ lmac = &bgx->lmac[lmacid];
+ if (lmac->check_link) {
+ /* Destroy work queue */
+ cancel_delayed_work(&lmac->dwork);
+ flush_workqueue(lmac->check_link);
+ destroy_workqueue(lmac->check_link);
+ }
+
+ cmrx_cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
+ cmrx_cfg &= ~(1 << 15);
+ bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cmrx_cfg);
+ bgx_flush_dmac_addrs(bgx, lmacid);
+
+ if (lmac->phydev)
+ phy_disconnect(lmac->phydev);
+
+ lmac->phydev = NULL;
+}
+
+static void bgx_set_num_ports(struct bgx *bgx)
+{
+ u64 lmac_count;
+
+ switch (bgx->qlm_mode) {
+ case QLM_MODE_SGMII:
+ bgx->lmac_count = 4;
+ bgx->lmac_type = BGX_MODE_SGMII;
+ bgx->lane_to_sds = 0;
+ break;
+ case QLM_MODE_XAUI_1X4:
+ bgx->lmac_count = 1;
+ bgx->lmac_type = BGX_MODE_XAUI;
+ bgx->lane_to_sds = 0xE4;
+ break;
+ case QLM_MODE_RXAUI_2X2:
+ bgx->lmac_count = 2;
+ bgx->lmac_type = BGX_MODE_RXAUI;
+ bgx->lane_to_sds = 0xE4;
+ break;
+ case QLM_MODE_XFI_4X1:
+ bgx->lmac_count = 4;
+ bgx->lmac_type = BGX_MODE_XFI;
+ bgx->lane_to_sds = 0;
+ break;
+ case QLM_MODE_XLAUI_1X4:
+ bgx->lmac_count = 1;
+ bgx->lmac_type = BGX_MODE_XLAUI;
+ bgx->lane_to_sds = 0xE4;
+ break;
+ case QLM_MODE_10G_KR_4X1:
+ bgx->lmac_count = 4;
+ bgx->lmac_type = BGX_MODE_10G_KR;
+ bgx->lane_to_sds = 0;
+ bgx->use_training = 1;
+ break;
+ case QLM_MODE_40G_KR4_1X4:
+ bgx->lmac_count = 1;
+ bgx->lmac_type = BGX_MODE_40G_KR;
+ bgx->lane_to_sds = 0xE4;
+ bgx->use_training = 1;
+ break;
+ default:
+ bgx->lmac_count = 0;
+ break;
+ }
+
+ /* Check if low level firmware has programmed LMAC count
+ * based on board type, if yes consider that otherwise
+ * the default static values
+ */
+ lmac_count = bgx_reg_read(bgx, 0, BGX_CMR_RX_LMACS) & 0x7;
+ if (lmac_count != 4)
+ bgx->lmac_count = lmac_count;
+}
+
+static void bgx_init_hw(struct bgx *bgx)
+{
+ int i;
+
+ bgx_set_num_ports(bgx);
+
+ bgx_reg_modify(bgx, 0, BGX_CMR_GLOBAL_CFG, CMR_GLOBAL_CFG_FCS_STRIP);
+ if (bgx_reg_read(bgx, 0, BGX_CMR_BIST_STATUS))
+ dev_err(&bgx->pdev->dev, "BGX%d BIST failed\n", bgx->bgx_id);
+
+ /* Set lmac type and lane2serdes mapping */
+ for (i = 0; i < bgx->lmac_count; i++) {
+ if (bgx->lmac_type == BGX_MODE_RXAUI) {
+ if (i)
+ bgx->lane_to_sds = 0x0e;
+ else
+ bgx->lane_to_sds = 0x04;
+ bgx_reg_write(bgx, i, BGX_CMRX_CFG,
+ (bgx->lmac_type << 8) | bgx->lane_to_sds);
+ continue;
+ }
+ bgx_reg_write(bgx, i, BGX_CMRX_CFG,
+ (bgx->lmac_type << 8) | (bgx->lane_to_sds + i));
+ bgx->lmac[i].lmacid_bd = lmac_count;
+ lmac_count++;
+ }
+
+ bgx_reg_write(bgx, 0, BGX_CMR_TX_LMACS, bgx->lmac_count);
+ bgx_reg_write(bgx, 0, BGX_CMR_RX_LMACS, bgx->lmac_count);
+
+ /* Set the backpressure AND mask */
+ for (i = 0; i < bgx->lmac_count; i++)
+ bgx_reg_modify(bgx, 0, BGX_CMR_CHAN_MSK_AND,
+ ((1ULL << MAX_BGX_CHANS_PER_LMAC) - 1) <<
+ (i * MAX_BGX_CHANS_PER_LMAC));
+
+ /* Disable all MAC filtering */
+ for (i = 0; i < RX_DMAC_COUNT; i++)
+ bgx_reg_write(bgx, 0, BGX_CMR_RX_DMACX_CAM + (i * 8), 0x00);
+
+ /* Disable MAC steering (NCSI traffic) */
+ for (i = 0; i < RX_TRAFFIC_STEER_RULE_COUNT; i++)
+ bgx_reg_write(bgx, 0, BGX_CMR_RX_STREERING + (i * 8), 0x00);
+}
+
+static void bgx_get_qlm_mode(struct bgx *bgx)
+{
+ struct device *dev = &bgx->pdev->dev;
+ int lmac_type;
+ int train_en;
+
+ /* Read LMAC0 type to figure out QLM mode
+ * This is configured by low level firmware
+ */
+ lmac_type = bgx_reg_read(bgx, 0, BGX_CMRX_CFG);
+ lmac_type = (lmac_type >> 8) & 0x07;
+
+ train_en = bgx_reg_read(bgx, 0, BGX_SPUX_BR_PMD_CRTL) &
+ SPU_PMD_CRTL_TRAIN_EN;
+
+ switch (lmac_type) {
+ case BGX_MODE_SGMII:
+ bgx->qlm_mode = QLM_MODE_SGMII;
+ dev_info(dev, "BGX%d QLM mode: SGMII\n", bgx->bgx_id);
+ break;
+ case BGX_MODE_XAUI:
+ bgx->qlm_mode = QLM_MODE_XAUI_1X4;
+ dev_info(dev, "BGX%d QLM mode: XAUI\n", bgx->bgx_id);
+ break;
+ case BGX_MODE_RXAUI:
+ bgx->qlm_mode = QLM_MODE_RXAUI_2X2;
+ dev_info(dev, "BGX%d QLM mode: RXAUI\n", bgx->bgx_id);
+ break;
+ case BGX_MODE_XFI:
+ if (!train_en) {
+ bgx->qlm_mode = QLM_MODE_XFI_4X1;
+ dev_info(dev, "BGX%d QLM mode: XFI\n", bgx->bgx_id);
+ } else {
+ bgx->qlm_mode = QLM_MODE_10G_KR_4X1;
+ dev_info(dev, "BGX%d QLM mode: 10G_KR\n", bgx->bgx_id);
+ }
+ break;
+ case BGX_MODE_XLAUI:
+ if (!train_en) {
+ bgx->qlm_mode = QLM_MODE_XLAUI_1X4;
+ dev_info(dev, "BGX%d QLM mode: XLAUI\n", bgx->bgx_id);
+ } else {
+ bgx->qlm_mode = QLM_MODE_40G_KR4_1X4;
+ dev_info(dev, "BGX%d QLM mode: 40G_KR4\n", bgx->bgx_id);
+ }
+ break;
+ default:
+ bgx->qlm_mode = QLM_MODE_SGMII;
+ dev_info(dev, "BGX%d QLM default mode: SGMII\n", bgx->bgx_id);
+ }
+}
+
+static void bgx_init_of(struct bgx *bgx, struct device_node *np)
+{
+ struct device_node *np_child;
+ u8 lmac = 0;
+
+ for_each_child_of_node(np, np_child) {
+ struct device_node *phy_np;
+ const char *mac;
+
+ phy_np = of_parse_phandle(np_child, "phy-handle", 0);
+ if (phy_np)
+ bgx->lmac[lmac].phydev = of_phy_find_device(phy_np);
+
+ mac = of_get_mac_address(np_child);
+ if (mac)
+ ether_addr_copy(bgx->lmac[lmac].mac, mac);
+
+ SET_NETDEV_DEV(&bgx->lmac[lmac].netdev, &bgx->pdev->dev);
+ bgx->lmac[lmac].lmacid = lmac;
+ lmac++;
+ if (lmac == MAX_LMAC_PER_BGX)
+ break;
+ }
+}
+
+static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err;
+ struct device *dev = &pdev->dev;
+ struct bgx *bgx = NULL;
+ struct device_node *np;
+ char bgx_sel[5];
+ u8 lmac;
+
+ bgx = devm_kzalloc(dev, sizeof(*bgx), GFP_KERNEL);
+ if (!bgx)
+ return -ENOMEM;
+ bgx->pdev = pdev;
+
+ pci_set_drvdata(pdev, bgx);
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(dev, "Failed to enable PCI device\n");
+ pci_set_drvdata(pdev, NULL);
+ return err;
+ }
+
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err) {
+ dev_err(dev, "PCI request regions failed 0x%x\n", err);
+ goto err_disable_device;
+ }
+
+ /* MAP configuration registers */
+ bgx->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0);
+ if (!bgx->reg_base) {
+ dev_err(dev, "BGX: Cannot map CSR memory space, aborting\n");
+ err = -ENOMEM;
+ goto err_release_regions;
+ }
+ bgx->bgx_id = (pci_resource_start(pdev, PCI_CFG_REG_BAR_NUM) >> 24) & 1;
+ bgx->bgx_id += nic_get_node_id(pdev) * MAX_BGX_PER_CN88XX;
+
+ bgx_vnic[bgx->bgx_id] = bgx;
+ bgx_get_qlm_mode(bgx);
+
+ snprintf(bgx_sel, 5, "bgx%d", bgx->bgx_id);
+ np = of_find_node_by_name(NULL, bgx_sel);
+ if (np)
+ bgx_init_of(bgx, np);
+
+ bgx_init_hw(bgx);
+
+ /* Enable all LMACs */
+ for (lmac = 0; lmac < bgx->lmac_count; lmac++) {
+ err = bgx_lmac_enable(bgx, lmac);
+ if (err) {
+ dev_err(dev, "BGX%d failed to enable lmac%d\n",
+ bgx->bgx_id, lmac);
+ goto err_enable;
+ }
+ }
+
+ return 0;
+
+err_enable:
+ bgx_vnic[bgx->bgx_id] = NULL;
+err_release_regions:
+ pci_release_regions(pdev);
+err_disable_device:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ return err;
+}
+
+static void bgx_remove(struct pci_dev *pdev)
+{
+ struct bgx *bgx = pci_get_drvdata(pdev);
+ u8 lmac;
+
+ /* Disable all LMACs */
+ for (lmac = 0; lmac < bgx->lmac_count; lmac++)
+ bgx_lmac_disable(bgx, lmac);
+
+ bgx_vnic[bgx->bgx_id] = NULL;
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+static struct pci_driver bgx_driver = {
+ .name = DRV_NAME,
+ .id_table = bgx_id_table,
+ .probe = bgx_probe,
+ .remove = bgx_remove,
+};
+
+static int __init bgx_init_module(void)
+{
+ pr_info("%s, ver %s\n", DRV_NAME, DRV_VERSION);
+
+ return pci_register_driver(&bgx_driver);
+}
+
+static void __exit bgx_cleanup_module(void)
+{
+ pci_unregister_driver(&bgx_driver);
+}
+
+module_init(bgx_init_module);
+module_exit(bgx_cleanup_module);
diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
new file mode 100644
index 000000000000..ba4f53b7cc2c
--- /dev/null
+++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2015 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef THUNDER_BGX_H
+#define THUNDER_BGX_H
+
+#define MAX_BGX_THUNDER 8 /* Max 4 nodes, 2 per node */
+#define MAX_BGX_PER_CN88XX 2
+#define MAX_LMAC_PER_BGX 4
+#define MAX_BGX_CHANS_PER_LMAC 16
+#define MAX_DMAC_PER_LMAC 8
+#define MAX_FRAME_SIZE 9216
+
+#define MAX_DMAC_PER_LMAC_TNS_BYPASS_MODE 2
+
+#define MAX_LMAC (MAX_BGX_PER_CN88XX * MAX_LMAC_PER_BGX)
+
+/* Registers */
+#define BGX_CMRX_CFG 0x00
+#define CMR_PKT_TX_EN BIT_ULL(13)
+#define CMR_PKT_RX_EN BIT_ULL(14)
+#define CMR_EN BIT_ULL(15)
+#define BGX_CMR_GLOBAL_CFG 0x08
+#define CMR_GLOBAL_CFG_FCS_STRIP BIT_ULL(6)
+#define BGX_CMRX_RX_ID_MAP 0x60
+#define BGX_CMRX_RX_STAT0 0x70
+#define BGX_CMRX_RX_STAT1 0x78
+#define BGX_CMRX_RX_STAT2 0x80
+#define BGX_CMRX_RX_STAT3 0x88
+#define BGX_CMRX_RX_STAT4 0x90
+#define BGX_CMRX_RX_STAT5 0x98
+#define BGX_CMRX_RX_STAT6 0xA0
+#define BGX_CMRX_RX_STAT7 0xA8
+#define BGX_CMRX_RX_STAT8 0xB0
+#define BGX_CMRX_RX_STAT9 0xB8
+#define BGX_CMRX_RX_STAT10 0xC0
+#define BGX_CMRX_RX_BP_DROP 0xC8
+#define BGX_CMRX_RX_DMAC_CTL 0x0E8
+#define BGX_CMR_RX_DMACX_CAM 0x200
+#define RX_DMACX_CAM_EN BIT_ULL(48)
+#define RX_DMACX_CAM_LMACID(x) (x << 49)
+#define RX_DMAC_COUNT 32
+#define BGX_CMR_RX_STREERING 0x300
+#define RX_TRAFFIC_STEER_RULE_COUNT 8
+#define BGX_CMR_CHAN_MSK_AND 0x450
+#define BGX_CMR_BIST_STATUS 0x460
+#define BGX_CMR_RX_LMACS 0x468
+#define BGX_CMRX_TX_STAT0 0x600
+#define BGX_CMRX_TX_STAT1 0x608
+#define BGX_CMRX_TX_STAT2 0x610
+#define BGX_CMRX_TX_STAT3 0x618
+#define BGX_CMRX_TX_STAT4 0x620
+#define BGX_CMRX_TX_STAT5 0x628
+#define BGX_CMRX_TX_STAT6 0x630
+#define BGX_CMRX_TX_STAT7 0x638
+#define BGX_CMRX_TX_STAT8 0x640
+#define BGX_CMRX_TX_STAT9 0x648
+#define BGX_CMRX_TX_STAT10 0x650
+#define BGX_CMRX_TX_STAT11 0x658
+#define BGX_CMRX_TX_STAT12 0x660
+#define BGX_CMRX_TX_STAT13 0x668
+#define BGX_CMRX_TX_STAT14 0x670
+#define BGX_CMRX_TX_STAT15 0x678
+#define BGX_CMRX_TX_STAT16 0x680
+#define BGX_CMRX_TX_STAT17 0x688
+#define BGX_CMR_TX_LMACS 0x1000
+
+#define BGX_SPUX_CONTROL1 0x10000
+#define SPU_CTL_LOW_POWER BIT_ULL(11)
+#define SPU_CTL_RESET BIT_ULL(15)
+#define BGX_SPUX_STATUS1 0x10008
+#define SPU_STATUS1_RCV_LNK BIT_ULL(2)
+#define BGX_SPUX_STATUS2 0x10020
+#define SPU_STATUS2_RCVFLT BIT_ULL(10)
+#define BGX_SPUX_BX_STATUS 0x10028
+#define SPU_BX_STATUS_RX_ALIGN BIT_ULL(12)
+#define BGX_SPUX_BR_STATUS1 0x10030
+#define SPU_BR_STATUS_BLK_LOCK BIT_ULL(0)
+#define SPU_BR_STATUS_RCV_LNK BIT_ULL(12)
+#define BGX_SPUX_BR_PMD_CRTL 0x10068
+#define SPU_PMD_CRTL_TRAIN_EN BIT_ULL(1)
+#define BGX_SPUX_BR_PMD_LP_CUP 0x10078
+#define BGX_SPUX_BR_PMD_LD_CUP 0x10088
+#define BGX_SPUX_BR_PMD_LD_REP 0x10090
+#define BGX_SPUX_FEC_CONTROL 0x100A0
+#define SPU_FEC_CTL_FEC_EN BIT_ULL(0)
+#define SPU_FEC_CTL_ERR_EN BIT_ULL(1)
+#define BGX_SPUX_AN_CONTROL 0x100C8
+#define SPU_AN_CTL_AN_EN BIT_ULL(12)
+#define SPU_AN_CTL_XNP_EN BIT_ULL(13)
+#define BGX_SPUX_AN_ADV 0x100D8
+#define BGX_SPUX_MISC_CONTROL 0x10218
+#define SPU_MISC_CTL_INTLV_RDISP BIT_ULL(10)
+#define SPU_MISC_CTL_RX_DIS BIT_ULL(12)
+#define BGX_SPUX_INT 0x10220 /* +(0..3) << 20 */
+#define BGX_SPUX_INT_W1S 0x10228
+#define BGX_SPUX_INT_ENA_W1C 0x10230
+#define BGX_SPUX_INT_ENA_W1S 0x10238
+#define BGX_SPU_DBG_CONTROL 0x10300
+#define SPU_DBG_CTL_AN_ARB_LINK_CHK_EN BIT_ULL(18)
+#define SPU_DBG_CTL_AN_NONCE_MCT_DIS BIT_ULL(29)
+
+#define BGX_SMUX_RX_INT 0x20000
+#define BGX_SMUX_RX_JABBER 0x20030
+#define BGX_SMUX_RX_CTL 0x20048
+#define SMU_RX_CTL_STATUS (3ull << 0)
+#define BGX_SMUX_TX_APPEND 0x20100
+#define SMU_TX_APPEND_FCS_D BIT_ULL(2)
+#define BGX_SMUX_TX_MIN_PKT 0x20118
+#define BGX_SMUX_TX_INT 0x20140
+#define BGX_SMUX_TX_CTL 0x20178
+#define SMU_TX_CTL_DIC_EN BIT_ULL(0)
+#define SMU_TX_CTL_UNI_EN BIT_ULL(1)
+#define SMU_TX_CTL_LNK_STATUS (3ull << 4)
+#define BGX_SMUX_TX_THRESH 0x20180
+#define BGX_SMUX_CTL 0x20200
+#define SMU_CTL_RX_IDLE BIT_ULL(0)
+#define SMU_CTL_TX_IDLE BIT_ULL(1)
+
+#define BGX_GMP_PCS_MRX_CTL 0x30000
+#define PCS_MRX_CTL_RST_AN BIT_ULL(9)
+#define PCS_MRX_CTL_PWR_DN BIT_ULL(11)
+#define PCS_MRX_CTL_AN_EN BIT_ULL(12)
+#define PCS_MRX_CTL_RESET BIT_ULL(15)
+#define BGX_GMP_PCS_MRX_STATUS 0x30008
+#define PCS_MRX_STATUS_AN_CPT BIT_ULL(5)
+#define BGX_GMP_PCS_ANX_AN_RESULTS 0x30020
+#define BGX_GMP_PCS_SGM_AN_ADV 0x30068
+#define BGX_GMP_PCS_MISCX_CTL 0x30078
+#define PCS_MISC_CTL_GMX_ENO BIT_ULL(11)
+#define PCS_MISC_CTL_SAMP_PT_MASK 0x7Full
+#define BGX_GMP_GMI_PRTX_CFG 0x38020
+#define GMI_PORT_CFG_SPEED BIT_ULL(1)
+#define GMI_PORT_CFG_DUPLEX BIT_ULL(2)
+#define GMI_PORT_CFG_SLOT_TIME BIT_ULL(3)
+#define GMI_PORT_CFG_SPEED_MSB BIT_ULL(8)
+#define BGX_GMP_GMI_RXX_JABBER 0x38038
+#define BGX_GMP_GMI_TXX_THRESH 0x38210
+#define BGX_GMP_GMI_TXX_APPEND 0x38218
+#define BGX_GMP_GMI_TXX_SLOT 0x38220
+#define BGX_GMP_GMI_TXX_BURST 0x38228
+#define BGX_GMP_GMI_TXX_MIN_PKT 0x38240
+#define BGX_GMP_GMI_TXX_SGMII_CTL 0x38300
+
+#define BGX_MSIX_VEC_0_29_ADDR 0x400000 /* +(0..29) << 4 */
+#define BGX_MSIX_VEC_0_29_CTL 0x400008
+#define BGX_MSIX_PBA_0 0x4F0000
+
+/* MSI-X interrupts */
+#define BGX_MSIX_VECTORS 30
+#define BGX_LMAC_VEC_OFFSET 7
+#define BGX_MSIX_VEC_SHIFT 4
+
+#define CMRX_INT 0
+#define SPUX_INT 1
+#define SMUX_RX_INT 2
+#define SMUX_TX_INT 3
+#define GMPX_PCS_INT 4
+#define GMPX_GMI_RX_INT 5
+#define GMPX_GMI_TX_INT 6
+#define CMR_MEM_INT 28
+#define SPU_MEM_INT 29
+
+#define LMAC_INTR_LINK_UP BIT(0)
+#define LMAC_INTR_LINK_DOWN BIT(1)
+
+/* RX_DMAC_CTL configuration*/
+enum MCAST_MODE {
+ MCAST_MODE_REJECT,
+ MCAST_MODE_ACCEPT,
+ MCAST_MODE_CAM_FILTER,
+ RSVD
+};
+
+#define BCAST_ACCEPT 1
+#define CAM_ACCEPT 1
+
+void bgx_add_dmac_addr(u64 dmac, int node, int bgx_idx, int lmac);
+unsigned bgx_get_map(int node);
+int bgx_get_lmac_count(int node, int bgx);
+const u8 *bgx_get_lmac_mac(int node, int bgx_idx, int lmacid);
+void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac);
+void bgx_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status);
+u64 bgx_get_rx_stats(int node, int bgx_idx, int lmac, int idx);
+u64 bgx_get_tx_stats(int node, int bgx_idx, int lmac, int idx);
+#define BGX_RX_STATS_COUNT 11
+#define BGX_TX_STATS_COUNT 18
+
+struct bgx_stats {
+ u64 rx_stats[BGX_RX_STATS_COUNT];
+ u64 tx_stats[BGX_TX_STATS_COUNT];
+};
+
+enum LMAC_TYPE {
+ BGX_MODE_SGMII = 0, /* 1 lane, 1.250 Gbaud */
+ BGX_MODE_XAUI = 1, /* 4 lanes, 3.125 Gbaud */
+ BGX_MODE_DXAUI = 1, /* 4 lanes, 6.250 Gbaud */
+ BGX_MODE_RXAUI = 2, /* 2 lanes, 6.250 Gbaud */
+ BGX_MODE_XFI = 3, /* 1 lane, 10.3125 Gbaud */
+ BGX_MODE_XLAUI = 4, /* 4 lanes, 10.3125 Gbaud */
+ BGX_MODE_10G_KR = 3,/* 1 lane, 10.3125 Gbaud */
+ BGX_MODE_40G_KR = 4,/* 4 lanes, 10.3125 Gbaud */
+};
+
+enum qlm_mode {
+ QLM_MODE_SGMII, /* SGMII, each lane independent */
+ QLM_MODE_XAUI_1X4, /* 1 XAUI or DXAUI, 4 lanes */
+ QLM_MODE_RXAUI_2X2, /* 2 RXAUI, 2 lanes each */
+ QLM_MODE_XFI_4X1, /* 4 XFI, 1 lane each */
+ QLM_MODE_XLAUI_1X4, /* 1 XLAUI, 4 lanes each */
+ QLM_MODE_10G_KR_4X1, /* 4 10GBASE-KR, 1 lane each */
+ QLM_MODE_40G_KR4_1X4, /* 1 40GBASE-KR4, 4 lanes each */
+};
+
+#endif /* THUNDER_BGX_H */
diff --git a/drivers/net/ethernet/chelsio/Kconfig b/drivers/net/ethernet/chelsio/Kconfig
index 7daa088a9bb7..a79813a17b6e 100644
--- a/drivers/net/ethernet/chelsio/Kconfig
+++ b/drivers/net/ethernet/chelsio/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_CHELSIO
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
index b96e4bfcac41..8f7aa53a4c4b 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
@@ -1025,19 +1025,19 @@ 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];
+ const char *fw_name;
u32 csum;
const __be32 *p;
u16 *cache = phy->phy_cache;
- int i, ret;
-
- snprintf(buf, sizeof(buf), get_edc_fw_name(edc_idx));
+ int i, ret = -EINVAL;
- ret = request_firmware(&fw, buf, &adapter->pdev->dev);
+ fw_name = get_edc_fw_name(edc_idx);
+ if (fw_name)
+ ret = request_firmware(&fw, fw_name, &adapter->pdev->dev);
if (ret < 0) {
dev_err(&adapter->pdev->dev,
"could not upgrade firmware: unable to load %s\n",
- buf);
+ fw_name);
return ret;
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index e052f05558c7..629f75d70353 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -46,17 +46,19 @@
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/vmalloc.h>
+#include <linux/etherdevice.h>
#include <asm/io.h>
#include "cxgb4_uld.h"
#define CH_WARN(adap, fmt, ...) dev_warn(adap->pdev_dev, fmt, ## __VA_ARGS__)
enum {
- MAX_NPORTS = 4, /* max # of ports */
- SERNUM_LEN = 24, /* Serial # length */
- EC_LEN = 16, /* E/C length */
- ID_LEN = 16, /* ID length */
- PN_LEN = 16, /* Part Number length */
+ MAX_NPORTS = 4, /* max # of ports */
+ SERNUM_LEN = 24, /* Serial # length */
+ EC_LEN = 16, /* E/C length */
+ ID_LEN = 16, /* ID length */
+ PN_LEN = 16, /* Part Number length */
+ MACADDR_LEN = 12, /* MAC Address length */
};
enum {
@@ -198,23 +200,45 @@ struct lb_port_stats {
};
struct tp_tcp_stats {
- u32 tcpOutRsts;
- u64 tcpInSegs;
- u64 tcpOutSegs;
- u64 tcpRetransSegs;
+ u32 tcp_out_rsts;
+ u64 tcp_in_segs;
+ u64 tcp_out_segs;
+ u64 tcp_retrans_segs;
+};
+
+struct tp_usm_stats {
+ u32 frames;
+ u32 drops;
+ u64 octets;
+};
+
+struct tp_fcoe_stats {
+ u32 frames_ddp;
+ u32 frames_drop;
+ u64 octets_ddp;
};
struct tp_err_stats {
- u32 macInErrs[4];
- u32 hdrInErrs[4];
- u32 tcpInErrs[4];
- u32 tnlCongDrops[4];
- u32 ofldChanDrops[4];
- u32 tnlTxDrops[4];
- u32 ofldVlanDrops[4];
- u32 tcp6InErrs[4];
- u32 ofldNoNeigh;
- u32 ofldCongDefer;
+ u32 mac_in_errs[4];
+ u32 hdr_in_errs[4];
+ u32 tcp_in_errs[4];
+ u32 tnl_cong_drops[4];
+ u32 ofld_chan_drops[4];
+ u32 tnl_tx_drops[4];
+ u32 ofld_vlan_drops[4];
+ u32 tcp6_in_errs[4];
+ u32 ofld_no_neigh;
+ u32 ofld_cong_defer;
+};
+
+struct tp_cpl_stats {
+ u32 req[4];
+ u32 rsp[4];
+};
+
+struct tp_rdma_stats {
+ u32 rqe_dfr_pkt;
+ u32 rqe_dfr_mod;
};
struct sge_params {
@@ -224,7 +248,6 @@ struct sge_params {
};
struct tp_params {
- unsigned int ntxchan; /* # of Tx channels */
unsigned int tre; /* log2 of core clocks per TP tick */
unsigned int la_mask; /* what events are recorded by TP LA */
unsigned short tx_modq_map; /* TX modulation scheduler queue to */
@@ -259,6 +282,7 @@ struct vpd_params {
u8 sn[SERNUM_LEN + 1];
u8 id[ID_LEN + 1];
u8 pn[PN_LEN + 1];
+ u8 na[MACADDR_LEN + 1];
};
struct pci_params {
@@ -273,6 +297,7 @@ struct pci_params {
#define CHELSIO_T4 0x4
#define CHELSIO_T5 0x5
+#define CHELSIO_T6 0x6
enum chip_type {
T4_A1 = CHELSIO_CHIP_CODE(CHELSIO_T4, 1),
@@ -284,6 +309,10 @@ enum chip_type {
T5_A1 = CHELSIO_CHIP_CODE(CHELSIO_T5, 1),
T5_FIRST_REV = T5_A0,
T5_LAST_REV = T5_A1,
+
+ T6_A0 = CHELSIO_CHIP_CODE(CHELSIO_T6, 0),
+ T6_FIRST_REV = T6_A0,
+ T6_LAST_REV = T6_A0,
};
struct devlog_params {
@@ -292,6 +321,15 @@ struct devlog_params {
u32 size; /* size of log */
};
+/* Stores chip specific parameters */
+struct arch_specific_params {
+ u8 nchan;
+ u16 mps_rplc_size;
+ u16 vfcount;
+ u32 sge_fl_db;
+ u16 mps_tcam_size;
+};
+
struct adapter_params {
struct sge_params sge;
struct tp_params tp;
@@ -317,6 +355,7 @@ struct adapter_params {
unsigned char nports; /* # of ethernet ports */
unsigned char portvec;
enum chip_type chip; /* chip code */
+ struct arch_specific_params arch; /* chip specific params */
unsigned char offload;
unsigned char bypass;
@@ -328,6 +367,17 @@ struct adapter_params {
unsigned int max_ird_adapter; /* Max read depth per adapter */
};
+/* State needed to monitor the forward progress of SGE Ingress DMA activities
+ * and possible hangs.
+ */
+struct sge_idma_monitor_state {
+ unsigned int idma_1s_thresh; /* 1s threshold in Core Clock ticks */
+ unsigned int idma_stalled[2]; /* synthesized stalled timers in HZ */
+ unsigned int idma_state[2]; /* IDMA Hang detect state */
+ unsigned int idma_qid[2]; /* IDMA Hung Ingress Queue ID */
+ unsigned int idma_warn[2]; /* time to warning in HZ */
+};
+
#include "t4fw_api.h"
#define FW_VERSION(chip) ( \
@@ -421,6 +471,7 @@ struct port_info {
u8 rss_mode;
struct link_config link_cfg;
u16 *rss;
+ struct port_stats stats_base;
#ifdef CONFIG_CHELSIO_T4_DCB
struct port_dcb_info dcb; /* Data Center Bridging support */
#endif
@@ -630,12 +681,7 @@ struct sge {
u32 fl_align; /* response queue message alignment */
u32 fl_starve_thres; /* Free List starvation threshold */
- /* State variables for detecting an SGE Ingress DMA hang */
- unsigned int idma_1s_thresh;/* SGE same State Counter 1s threshold */
- unsigned int idma_stalled[2];/* SGE synthesized stalled timers in HZ */
- unsigned int idma_state[2]; /* SGE IDMA Hang detect state */
- unsigned int idma_qid[2]; /* SGE IDMA Hung Ingress Queue ID */
-
+ struct sge_idma_monitor_state idma_monitor;
unsigned int egr_start;
unsigned int egr_sz;
unsigned int ingr_start;
@@ -644,6 +690,7 @@ struct sge {
struct sge_rspq **ingr_map; /* qid->queue ingress queue map */
unsigned long *starving_fl;
unsigned long *txq_maperr;
+ unsigned long *blocked_fl;
struct timer_list rx_timer; /* refills starving FLs */
struct timer_list tx_timer; /* checks Tx queues */
};
@@ -665,6 +712,12 @@ struct l2t_data;
#endif
+struct doorbell_stats {
+ u32 db_drop;
+ u32 db_empty;
+ u32 db_full;
+};
+
struct adapter {
void __iomem *regs;
void __iomem *bar2;
@@ -672,7 +725,7 @@ struct adapter {
struct pci_dev *pdev;
struct device *pdev_dev;
unsigned int mbox;
- unsigned int fn;
+ unsigned int pf;
unsigned int flags;
enum chip_type chip;
@@ -682,13 +735,12 @@ struct adapter {
struct cxgb4_virt_res vres;
unsigned int swintr;
- unsigned int wol;
-
struct {
unsigned short vec;
char desc[IFNAMSIZ + 10];
} msix_info[MAX_INGQ + 1];
+ struct doorbell_stats db_stats;
struct sge sge;
struct net_device *port[MAX_NPORTS];
@@ -843,6 +895,16 @@ enum {
VLAN_REWRITE
};
+static inline int is_offload(const struct adapter *adap)
+{
+ return adap->params.offload;
+}
+
+static inline int is_t6(enum chip_type chip)
+{
+ return CHELSIO_CHIP_VERSION(chip) == CHELSIO_T6;
+}
+
static inline int is_t5(enum chip_type chip)
{
return CHELSIO_CHIP_VERSION(chip) == CHELSIO_T5;
@@ -887,6 +949,22 @@ static inline void t4_write_reg64(struct adapter *adap, u32 reg_addr, u64 val)
}
/**
+ * t4_set_hw_addr - store a port's MAC address in SW
+ * @adapter: the adapter
+ * @port_idx: the port index
+ * @hw_addr: the Ethernet address
+ *
+ * Store the Ethernet address of the given port in SW. Called by the common
+ * code when it retrieves a port's Ethernet address from EEPROM.
+ */
+static inline void t4_set_hw_addr(struct adapter *adapter, int port_idx,
+ u8 hw_addr[])
+{
+ ether_addr_copy(adapter->port[port_idx]->dev_addr, hw_addr);
+ ether_addr_copy(adapter->port[port_idx]->perm_addr, hw_addr);
+}
+
+/**
* netdev2pinfo - return the port_info structure associated with a net_device
* @dev: the netdev
*
@@ -1055,7 +1133,7 @@ int t4_mgmt_tx(struct adapter *adap, struct sk_buff *skb);
int t4_ofld_send(struct adapter *adap, struct sk_buff *skb);
int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
struct net_device *dev, int intr_idx,
- struct sge_fl *fl, rspq_handler_t hnd);
+ struct sge_fl *fl, rspq_handler_t hnd, int cong);
int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
struct net_device *dev, struct netdev_queue *netdevq,
unsigned int iqid);
@@ -1095,6 +1173,19 @@ static inline int is_bypass_device(int device)
}
}
+static inline int is_10gbt_device(int device)
+{
+ /* this should be set based upon device capabilities */
+ switch (device) {
+ case 0x4409:
+ case 0x4486:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
static inline unsigned int core_ticks_per_usec(const struct adapter *adap)
{
return adap->params.vpd.cclk / 1000;
@@ -1117,9 +1208,19 @@ static inline unsigned int core_ticks_to_us(const struct adapter *adapter,
void t4_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask,
u32 val);
+int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox, const void *cmd,
+ int size, void *rpl, bool sleep_ok, int timeout);
int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
void *rpl, bool sleep_ok);
+static inline int t4_wr_mbox_timeout(struct adapter *adap, int mbox,
+ const void *cmd, int size, void *rpl,
+ int timeout)
+{
+ return t4_wr_mbox_meat_timeout(adap, mbox, cmd, size, rpl, true,
+ timeout);
+}
+
static inline int t4_wr_mbox(struct adapter *adap, int mbox, const void *cmd,
int size, void *rpl)
{
@@ -1147,10 +1248,14 @@ void t4_intr_disable(struct adapter *adapter);
int t4_slow_intr_handler(struct adapter *adapter);
int t4_wait_dev_ready(void __iomem *regs);
-int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port,
+int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port,
struct link_config *lc);
int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port);
+u32 t4_read_pcie_cfg4(struct adapter *adap, int reg);
+u32 t4_get_util_window(struct adapter *adap);
+void t4_setup_memwin(struct adapter *adap, u32 memwin_base, u32 window);
+
#define T4_MEMORY_WRITE 0
#define T4_MEMORY_READ 1
int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, u32 len,
@@ -1165,10 +1270,16 @@ unsigned int t4_get_regs_len(struct adapter *adapter);
void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size);
int t4_seeprom_wp(struct adapter *adapter, bool enable);
-int get_vpd_params(struct adapter *adapter, struct vpd_params *p);
+int t4_get_raw_vpd_params(struct adapter *adapter, struct vpd_params *p);
+int t4_get_vpd_params(struct adapter *adapter, struct vpd_params *p);
int t4_read_flash(struct adapter *adapter, unsigned int addr,
unsigned int nwords, u32 *data, int byte_oriented);
int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size);
+int t4_load_phy_fw(struct adapter *adap,
+ int win, spinlock_t *lock,
+ int (*phy_fw_version)(const u8 *, size_t),
+ const u8 *phy_fw_data, size_t phy_fw_size);
+int t4_phy_fw_ver(struct adapter *adap, int *phy_fw_ver);
int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op);
int t4_fw_upgrade(struct adapter *adap, unsigned int mbox,
const u8 *fw_data, unsigned int size, int force);
@@ -1182,7 +1293,7 @@ int t4_prep_fw(struct adapter *adap, struct fw_info *fw_info,
int t4_prep_adapter(struct adapter *adapter);
enum t4_bar2_qtype { T4_BAR2_QTYPE_EGRESS, T4_BAR2_QTYPE_INGRESS };
-int cxgb4_t4_bar2_sge_qregs(struct adapter *adapter,
+int t4_bar2_sge_qregs(struct adapter *adapter,
unsigned int qid,
enum t4_bar2_qtype qtype,
int user,
@@ -1196,12 +1307,15 @@ int t4_init_devlog_params(struct adapter *adapter);
int t4_init_sge_params(struct adapter *adapter);
int t4_init_tp_params(struct adapter *adap);
int t4_filter_field_shift(const struct adapter *adap, int filter_sel);
+int t4_init_rss_mode(struct adapter *adap, int mbox);
int t4_port_init(struct adapter *adap, int mbox, int pf, int vf);
void t4_fatal_err(struct adapter *adapter);
int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid,
int start, int n, const u16 *rspq, unsigned int nrspq);
int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode,
unsigned int flags);
+int t4_config_vi_rss(struct adapter *adapter, int mbox, unsigned int viid,
+ unsigned int flags, unsigned int defq);
int t4_read_rss(struct adapter *adapter, u16 *entries);
void t4_read_rss_key(struct adapter *adapter, u32 *key);
void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx);
@@ -1212,10 +1326,7 @@ void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index,
u32 t4_read_rss_pf_map(struct adapter *adapter);
u32 t4_read_rss_pf_mask(struct adapter *adapter);
-int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data,
- u64 *parity);
-int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data,
- u64 *parity);
+unsigned int t4_get_mps_bg_map(struct adapter *adapter, int idx);
void t4_pmtx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]);
void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]);
int t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data,
@@ -1227,21 +1338,36 @@ int t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n,
int t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n,
const unsigned int *valp);
int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr);
+void t4_cim_read_pif_la(struct adapter *adap, u32 *pif_req, u32 *pif_rsp,
+ unsigned int *pif_req_wrptr,
+ unsigned int *pif_rsp_wrptr);
+void t4_cim_read_ma_la(struct adapter *adap, u32 *ma_req, u32 *ma_rsp);
void t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres);
const char *t4_get_port_type_description(enum fw_port_type port_type);
void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p);
+void t4_get_port_stats_offset(struct adapter *adap, int idx,
+ struct port_stats *stats,
+ struct port_stats *offset);
+void t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p);
void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log);
void t4_read_cong_tbl(struct adapter *adap, u16 incr[NMTUS][NCCTRL_WIN]);
void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr,
unsigned int mask, unsigned int val);
void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr);
+void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st);
+void t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st);
+void t4_tp_get_rdma_stats(struct adapter *adap, struct tp_rdma_stats *st);
+void t4_get_usm_stats(struct adapter *adap, struct tp_usm_stats *st);
void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
struct tp_tcp_stats *v6);
+void t4_get_fcoe_stats(struct adapter *adap, unsigned int idx,
+ struct tp_fcoe_stats *st);
void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
const unsigned short *alpha, const unsigned short *beta);
void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf);
+void t4_get_chan_txrate(struct adapter *adap, u64 *nic_rate, u64 *ofld_rate);
void t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid);
void t4_wol_magic_enable(struct adapter *adap, unsigned int port,
@@ -1260,13 +1386,16 @@ int t4_fw_initialize(struct adapter *adap, unsigned int mbox);
int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int nparams, const u32 *params,
u32 *val);
+int t4_query_params_rw(struct adapter *adap, unsigned int mbox, unsigned int pf,
+ unsigned int vf, unsigned int nparams, const u32 *params,
+ u32 *val, int rw);
+int t4_set_params_timeout(struct adapter *adap, unsigned int mbox,
+ unsigned int pf, unsigned int vf,
+ unsigned int nparams, const u32 *params,
+ const u32 *val, int timeout);
int t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int nparams, const u32 *params,
const u32 *val);
-int t4_set_params_nosleep(struct adapter *adap, unsigned int mbox,
- unsigned int pf, unsigned int vf,
- unsigned int nparams, const u32 *params,
- const u32 *val);
int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int txq, unsigned int txq_eth_ctrl,
unsigned int rxqi, unsigned int rxq, unsigned int tc,
@@ -1275,6 +1404,9 @@ int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf,
int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port,
unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac,
unsigned int *rss_size);
+int t4_free_vi(struct adapter *adap, unsigned int mbox,
+ unsigned int pf, unsigned int vf,
+ unsigned int viid);
int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
int mtu, int promisc, int all_multi, int bcast, int vlanex,
bool sleep_ok);
@@ -1304,6 +1436,7 @@ int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int eqid);
int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int eqid);
+int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox);
int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl);
void t4_db_full(struct adapter *adapter);
void t4_db_dropped(struct adapter *adapter);
@@ -1311,4 +1444,9 @@ int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
u32 addr, u32 val);
void t4_sge_decode_idma_state(struct adapter *adapter, int state);
void t4_free_mem(void *addr);
+void t4_idma_monitor_init(struct adapter *adapter,
+ struct sge_idma_monitor_state *idma);
+void t4_idma_monitor(struct adapter *adapter,
+ struct sge_idma_monitor_state *idma,
+ int hz, int ticks);
#endif /* __CXGB4_H__ */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
index 371f75e782e5..484eb8c37489 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
@@ -182,6 +182,95 @@ static const struct file_operations cim_la_fops = {
.release = seq_release_private
};
+static int cim_pif_la_show(struct seq_file *seq, void *v, int idx)
+{
+ const u32 *p = v;
+
+ if (v == SEQ_START_TOKEN) {
+ seq_puts(seq, "Cntl ID DataBE Addr Data\n");
+ } else if (idx < CIM_PIFLA_SIZE) {
+ seq_printf(seq, " %02x %02x %04x %08x %08x%08x%08x%08x\n",
+ (p[5] >> 22) & 0xff, (p[5] >> 16) & 0x3f,
+ p[5] & 0xffff, p[4], p[3], p[2], p[1], p[0]);
+ } else {
+ if (idx == CIM_PIFLA_SIZE)
+ seq_puts(seq, "\nCntl ID Data\n");
+ seq_printf(seq, " %02x %02x %08x%08x%08x%08x\n",
+ (p[4] >> 6) & 0xff, p[4] & 0x3f,
+ p[3], p[2], p[1], p[0]);
+ }
+ return 0;
+}
+
+static int cim_pif_la_open(struct inode *inode, struct file *file)
+{
+ struct seq_tab *p;
+ struct adapter *adap = inode->i_private;
+
+ p = seq_open_tab(file, 2 * CIM_PIFLA_SIZE, 6 * sizeof(u32), 1,
+ cim_pif_la_show);
+ if (!p)
+ return -ENOMEM;
+
+ t4_cim_read_pif_la(adap, (u32 *)p->data,
+ (u32 *)p->data + 6 * CIM_PIFLA_SIZE, NULL, NULL);
+ return 0;
+}
+
+static const struct file_operations cim_pif_la_fops = {
+ .owner = THIS_MODULE,
+ .open = cim_pif_la_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private
+};
+
+static int cim_ma_la_show(struct seq_file *seq, void *v, int idx)
+{
+ const u32 *p = v;
+
+ if (v == SEQ_START_TOKEN) {
+ seq_puts(seq, "\n");
+ } else if (idx < CIM_MALA_SIZE) {
+ seq_printf(seq, "%02x%08x%08x%08x%08x\n",
+ p[4], p[3], p[2], p[1], p[0]);
+ } else {
+ if (idx == CIM_MALA_SIZE)
+ seq_puts(seq,
+ "\nCnt ID Tag UE Data RDY VLD\n");
+ seq_printf(seq, "%3u %2u %x %u %08x%08x %u %u\n",
+ (p[2] >> 10) & 0xff, (p[2] >> 7) & 7,
+ (p[2] >> 3) & 0xf, (p[2] >> 2) & 1,
+ (p[1] >> 2) | ((p[2] & 3) << 30),
+ (p[0] >> 2) | ((p[1] & 3) << 30), (p[0] >> 1) & 1,
+ p[0] & 1);
+ }
+ return 0;
+}
+
+static int cim_ma_la_open(struct inode *inode, struct file *file)
+{
+ struct seq_tab *p;
+ struct adapter *adap = inode->i_private;
+
+ p = seq_open_tab(file, 2 * CIM_MALA_SIZE, 5 * sizeof(u32), 1,
+ cim_ma_la_show);
+ if (!p)
+ return -ENOMEM;
+
+ t4_cim_read_ma_la(adap, (u32 *)p->data,
+ (u32 *)p->data + 5 * CIM_MALA_SIZE);
+ return 0;
+}
+
+static const struct file_operations cim_ma_la_fops = {
+ .owner = THIS_MODULE,
+ .open = cim_ma_la_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private
+};
+
static int cim_qcfg_show(struct seq_file *seq, void *v)
{
static const char * const qname[] = {
@@ -663,6 +752,39 @@ static const struct file_operations pm_stats_debugfs_fops = {
.write = pm_stats_clear
};
+static int tx_rate_show(struct seq_file *seq, void *v)
+{
+ u64 nrate[NCHAN], orate[NCHAN];
+ struct adapter *adap = seq->private;
+
+ t4_get_chan_txrate(adap, nrate, orate);
+ if (adap->params.arch.nchan == NCHAN) {
+ seq_puts(seq, " channel 0 channel 1 "
+ "channel 2 channel 3\n");
+ seq_printf(seq, "NIC B/s: %10llu %10llu %10llu %10llu\n",
+ (unsigned long long)nrate[0],
+ (unsigned long long)nrate[1],
+ (unsigned long long)nrate[2],
+ (unsigned long long)nrate[3]);
+ seq_printf(seq, "Offload B/s: %10llu %10llu %10llu %10llu\n",
+ (unsigned long long)orate[0],
+ (unsigned long long)orate[1],
+ (unsigned long long)orate[2],
+ (unsigned long long)orate[3]);
+ } else {
+ seq_puts(seq, " channel 0 channel 1\n");
+ seq_printf(seq, "NIC B/s: %10llu %10llu\n",
+ (unsigned long long)nrate[0],
+ (unsigned long long)nrate[1]);
+ seq_printf(seq, "Offload B/s: %10llu %10llu\n",
+ (unsigned long long)orate[0],
+ (unsigned long long)orate[1]);
+ }
+ return 0;
+}
+
+DEFINE_SIMPLE_DEBUGFS_FILE(tx_rate);
+
static int cctrl_tbl_show(struct seq_file *seq, void *v)
{
static const char * const dec_fac[] = {
@@ -1084,41 +1206,89 @@ static inline void tcamxy2valmask(u64 x, u64 y, u8 *addr, u64 *mask)
static int mps_tcam_show(struct seq_file *seq, void *v)
{
- if (v == SEQ_START_TOKEN)
- seq_puts(seq, "Idx Ethernet address Mask Vld Ports PF"
- " VF Replication "
- "P0 P1 P2 P3 ML\n");
- else {
+ struct adapter *adap = seq->private;
+ unsigned int chip_ver = CHELSIO_CHIP_VERSION(adap->params.chip);
+
+ if (v == SEQ_START_TOKEN) {
+ if (adap->params.arch.mps_rplc_size > 128)
+ seq_puts(seq, "Idx Ethernet address Mask "
+ "Vld Ports PF VF "
+ "Replication "
+ " P0 P1 P2 P3 ML\n");
+ else
+ seq_puts(seq, "Idx Ethernet address Mask "
+ "Vld Ports PF VF Replication"
+ " P0 P1 P2 P3 ML\n");
+ } else {
u64 mask;
u8 addr[ETH_ALEN];
- struct adapter *adap = seq->private;
+ bool replicate;
unsigned int idx = (uintptr_t)v - 2;
- u64 tcamy = t4_read_reg64(adap, MPS_CLS_TCAM_Y_L(idx));
- u64 tcamx = t4_read_reg64(adap, MPS_CLS_TCAM_X_L(idx));
- u32 cls_lo = t4_read_reg(adap, MPS_CLS_SRAM_L(idx));
- u32 cls_hi = t4_read_reg(adap, MPS_CLS_SRAM_H(idx));
- u32 rplc[4] = {0, 0, 0, 0};
+ u64 tcamy, tcamx, val;
+ u32 cls_lo, cls_hi, ctl;
+ u32 rplc[8] = {0};
+
+ if (chip_ver > CHELSIO_T5) {
+ /* CtlCmdType - 0: Read, 1: Write
+ * CtlTcamSel - 0: TCAM0, 1: TCAM1
+ * CtlXYBitSel- 0: Y bit, 1: X bit
+ */
+
+ /* Read tcamy */
+ ctl = CTLCMDTYPE_V(0) | CTLXYBITSEL_V(0);
+ if (idx < 256)
+ ctl |= CTLTCAMINDEX_V(idx) | CTLTCAMSEL_V(0);
+ else
+ ctl |= CTLTCAMINDEX_V(idx - 256) |
+ CTLTCAMSEL_V(1);
+ t4_write_reg(adap, MPS_CLS_TCAM_DATA2_CTL_A, ctl);
+ val = t4_read_reg(adap, MPS_CLS_TCAM_DATA1_A);
+ tcamy = DMACH_G(val) << 32;
+ tcamy |= t4_read_reg(adap, MPS_CLS_TCAM_DATA0_A);
+
+ /* Read tcamx. Change the control param */
+ ctl |= CTLXYBITSEL_V(1);
+ t4_write_reg(adap, MPS_CLS_TCAM_DATA2_CTL_A, ctl);
+ val = t4_read_reg(adap, MPS_CLS_TCAM_DATA1_A);
+ tcamx = DMACH_G(val) << 32;
+ tcamx |= t4_read_reg(adap, MPS_CLS_TCAM_DATA0_A);
+ } else {
+ tcamy = t4_read_reg64(adap, MPS_CLS_TCAM_Y_L(idx));
+ tcamx = t4_read_reg64(adap, MPS_CLS_TCAM_X_L(idx));
+ }
+
+ cls_lo = t4_read_reg(adap, MPS_CLS_SRAM_L(idx));
+ cls_hi = t4_read_reg(adap, MPS_CLS_SRAM_H(idx));
if (tcamx & tcamy) {
seq_printf(seq, "%3u -\n", idx);
goto out;
}
- if (cls_lo & REPLICATE_F) {
+ rplc[0] = rplc[1] = rplc[2] = rplc[3] = 0;
+ if (chip_ver > CHELSIO_T5)
+ replicate = (cls_lo & T6_REPLICATE_F);
+ else
+ replicate = (cls_lo & REPLICATE_F);
+
+ if (replicate) {
struct fw_ldst_cmd ldst_cmd;
int ret;
+ struct fw_ldst_mps_rplc mps_rplc;
+ u32 ldst_addrspc;
memset(&ldst_cmd, 0, sizeof(ldst_cmd));
+ ldst_addrspc =
+ FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_MPS);
ldst_cmd.op_to_addrspace =
htonl(FW_CMD_OP_V(FW_LDST_CMD) |
FW_CMD_REQUEST_F |
FW_CMD_READ_F |
- FW_LDST_CMD_ADDRSPACE_V(
- FW_LDST_ADDRSPC_MPS));
+ ldst_addrspc);
ldst_cmd.cycles_to_len16 = htonl(FW_LEN16(ldst_cmd));
- ldst_cmd.u.mps.fid_ctl =
+ ldst_cmd.u.mps.rplc.fid_idx =
htons(FW_LDST_CMD_FID_V(FW_LDST_MPS_RPLC) |
- FW_LDST_CMD_CTL_V(idx));
+ FW_LDST_CMD_IDX_V(idx));
ret = t4_wr_mbox(adap, adap->mbox, &ldst_cmd,
sizeof(ldst_cmd), &ldst_cmd);
if (ret)
@@ -1126,30 +1296,69 @@ static int mps_tcam_show(struct seq_file *seq, void *v)
"replication map for idx %d: %d\n",
idx, -ret);
else {
- rplc[0] = ntohl(ldst_cmd.u.mps.rplc31_0);
- rplc[1] = ntohl(ldst_cmd.u.mps.rplc63_32);
- rplc[2] = ntohl(ldst_cmd.u.mps.rplc95_64);
- rplc[3] = ntohl(ldst_cmd.u.mps.rplc127_96);
+ mps_rplc = ldst_cmd.u.mps.rplc;
+ rplc[0] = ntohl(mps_rplc.rplc31_0);
+ rplc[1] = ntohl(mps_rplc.rplc63_32);
+ rplc[2] = ntohl(mps_rplc.rplc95_64);
+ rplc[3] = ntohl(mps_rplc.rplc127_96);
+ if (adap->params.arch.mps_rplc_size > 128) {
+ rplc[4] = ntohl(mps_rplc.rplc159_128);
+ rplc[5] = ntohl(mps_rplc.rplc191_160);
+ rplc[6] = ntohl(mps_rplc.rplc223_192);
+ rplc[7] = ntohl(mps_rplc.rplc255_224);
+ }
}
}
tcamxy2valmask(tcamx, tcamy, addr, &mask);
- seq_printf(seq, "%3u %02x:%02x:%02x:%02x:%02x:%02x %012llx"
- "%3c %#x%4u%4d",
- idx, addr[0], addr[1], addr[2], addr[3], addr[4],
- addr[5], (unsigned long long)mask,
- (cls_lo & SRAM_VLD_F) ? 'Y' : 'N', PORTMAP_G(cls_hi),
- PF_G(cls_lo),
- (cls_lo & VF_VALID_F) ? VF_G(cls_lo) : -1);
- if (cls_lo & REPLICATE_F)
- seq_printf(seq, " %08x %08x %08x %08x",
- rplc[3], rplc[2], rplc[1], rplc[0]);
+ if (chip_ver > CHELSIO_T5)
+ seq_printf(seq, "%3u %02x:%02x:%02x:%02x:%02x:%02x "
+ "%012llx%3c %#x%4u%4d",
+ idx, addr[0], addr[1], addr[2], addr[3],
+ addr[4], addr[5], (unsigned long long)mask,
+ (cls_lo & T6_SRAM_VLD_F) ? 'Y' : 'N',
+ PORTMAP_G(cls_hi),
+ T6_PF_G(cls_lo),
+ (cls_lo & T6_VF_VALID_F) ?
+ T6_VF_G(cls_lo) : -1);
else
- seq_printf(seq, "%36c", ' ');
- seq_printf(seq, "%4u%3u%3u%3u %#x\n",
- SRAM_PRIO0_G(cls_lo), SRAM_PRIO1_G(cls_lo),
- SRAM_PRIO2_G(cls_lo), SRAM_PRIO3_G(cls_lo),
- (cls_lo >> MULTILISTEN0_S) & 0xf);
+ seq_printf(seq, "%3u %02x:%02x:%02x:%02x:%02x:%02x "
+ "%012llx%3c %#x%4u%4d",
+ idx, addr[0], addr[1], addr[2], addr[3],
+ addr[4], addr[5], (unsigned long long)mask,
+ (cls_lo & SRAM_VLD_F) ? 'Y' : 'N',
+ PORTMAP_G(cls_hi),
+ PF_G(cls_lo),
+ (cls_lo & VF_VALID_F) ? VF_G(cls_lo) : -1);
+
+ if (replicate) {
+ if (adap->params.arch.mps_rplc_size > 128)
+ seq_printf(seq, " %08x %08x %08x %08x "
+ "%08x %08x %08x %08x",
+ rplc[7], rplc[6], rplc[5], rplc[4],
+ rplc[3], rplc[2], rplc[1], rplc[0]);
+ else
+ seq_printf(seq, " %08x %08x %08x %08x",
+ rplc[3], rplc[2], rplc[1], rplc[0]);
+ } else {
+ if (adap->params.arch.mps_rplc_size > 128)
+ seq_printf(seq, "%72c", ' ');
+ else
+ seq_printf(seq, "%36c", ' ');
+ }
+
+ if (chip_ver > CHELSIO_T5)
+ seq_printf(seq, "%4u%3u%3u%3u %#x\n",
+ T6_SRAM_PRIO0_G(cls_lo),
+ T6_SRAM_PRIO1_G(cls_lo),
+ T6_SRAM_PRIO2_G(cls_lo),
+ T6_SRAM_PRIO3_G(cls_lo),
+ (cls_lo >> T6_MULTILISTEN0_S) & 0xf);
+ else
+ seq_printf(seq, "%4u%3u%3u%3u %#x\n",
+ SRAM_PRIO0_G(cls_lo), SRAM_PRIO1_G(cls_lo),
+ SRAM_PRIO2_G(cls_lo), SRAM_PRIO3_G(cls_lo),
+ (cls_lo >> MULTILISTEN0_S) & 0xf);
}
out: return 0;
}
@@ -1222,7 +1431,7 @@ static int sensors_show(struct seq_file *seq, void *v)
param[1] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DIAG) |
FW_PARAMS_PARAM_Y_V(FW_PARAM_DEV_DIAG_VDD));
- ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2,
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2,
param, val);
if (ret < 0 || val[0] == 0)
@@ -1416,6 +1625,9 @@ static int rss_config_show(struct seq_file *seq, void *v)
seq_printf(seq, " HashDelay: %3d\n", HASHDELAY_G(rssconf));
if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5)
seq_printf(seq, " VfWrAddr: %3d\n", VFWRADDR_G(rssconf));
+ else
+ seq_printf(seq, " VfWrAddr: %3d\n",
+ T6_VFWRADDR_G(rssconf));
seq_printf(seq, " KeyMode: %s\n", keymode[KEYMODE_G(rssconf)]);
seq_printf(seq, " VfWrEn: %3s\n", yesno(rssconf & VFWREN_F));
seq_printf(seq, " KeyWrEn: %3s\n", yesno(rssconf & KEYWREN_F));
@@ -1634,14 +1846,14 @@ static int rss_vf_config_open(struct inode *inode, struct file *file)
struct adapter *adapter = inode->i_private;
struct seq_tab *p;
struct rss_vf_conf *vfconf;
- int vf;
+ int vf, vfcount = adapter->params.arch.vfcount;
- p = seq_open_tab(file, 128, sizeof(*vfconf), 1, rss_vf_config_show);
+ p = seq_open_tab(file, vfcount, sizeof(*vfconf), 1, rss_vf_config_show);
if (!p)
return -ENOMEM;
vfconf = (struct rss_vf_conf *)p->data;
- for (vf = 0; vf < 128; vf++) {
+ for (vf = 0; vf < vfcount; vf++) {
t4_read_rss_vf_config(adapter, vf, &vfconf[vf].rss_vf_vfl,
&vfconf[vf].rss_vf_vfh);
}
@@ -1959,6 +2171,61 @@ static void add_debugfs_mem(struct adapter *adap, const char *name,
size_mb << 20);
}
+static int blocked_fl_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t blocked_fl_read(struct file *filp, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ int len;
+ const struct adapter *adap = filp->private_data;
+ char *buf;
+ ssize_t size = (adap->sge.egr_sz + 3) / 4 +
+ adap->sge.egr_sz / 32 + 2; /* includes ,/\n/\0 */
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ len = snprintf(buf, size - 1, "%*pb\n",
+ adap->sge.egr_sz, adap->sge.blocked_fl);
+ len += sprintf(buf + len, "\n");
+ size = simple_read_from_buffer(ubuf, count, ppos, buf, len);
+ t4_free_mem(buf);
+ return size;
+}
+
+static ssize_t blocked_fl_write(struct file *filp, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ int err;
+ unsigned long *t;
+ struct adapter *adap = filp->private_data;
+
+ t = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz), sizeof(long), GFP_KERNEL);
+ if (!t)
+ return -ENOMEM;
+
+ err = bitmap_parse_user(ubuf, count, t, adap->sge.egr_sz);
+ if (err)
+ return err;
+
+ bitmap_copy(adap->sge.blocked_fl, t, adap->sge.egr_sz);
+ t4_free_mem(t);
+ return count;
+}
+
+static const struct file_operations blocked_fl_fops = {
+ .owner = THIS_MODULE,
+ .open = blocked_fl_open,
+ .read = blocked_fl_read,
+ .write = blocked_fl_write,
+ .llseek = generic_file_llseek,
+};
+
/* Add an array of Debug FS files.
*/
void add_debugfs_files(struct adapter *adap,
@@ -1978,11 +2245,13 @@ void add_debugfs_files(struct adapter *adap,
int t4_setup_debugfs(struct adapter *adap)
{
int i;
- u32 size;
+ u32 size = 0;
struct dentry *de;
static struct t4_debugfs_entry t4_debugfs_files[] = {
{ "cim_la", &cim_la_fops, S_IRUSR, 0 },
+ { "cim_pif_la", &cim_pif_la_fops, S_IRUSR, 0 },
+ { "cim_ma_la", &cim_ma_la_fops, S_IRUSR, 0 },
{ "cim_qcfg", &cim_qcfg_fops, S_IRUSR, 0 },
{ "clk", &clk_debugfs_fops, S_IRUSR, 0 },
{ "devlog", &devlog_fops, S_IRUSR, 0 },
@@ -2018,10 +2287,12 @@ int t4_setup_debugfs(struct adapter *adap)
{ "ulprx_la", &ulprx_la_fops, S_IRUSR, 0 },
{ "sensors", &sensors_debugfs_fops, S_IRUSR, 0 },
{ "pm_stats", &pm_stats_debugfs_fops, S_IRUSR, 0 },
+ { "tx_rate", &tx_rate_debugfs_fops, S_IRUSR, 0 },
{ "cctrl", &cctrl_tbl_debugfs_fops, S_IRUSR, 0 },
#if IS_ENABLED(CONFIG_IPV6)
{ "clip_tbl", &clip_tbl_debugfs_fops, S_IRUSR, 0 },
#endif
+ { "blocked_fl", &blocked_fl_fops, S_IRUSR | S_IWUSR, 0 },
};
/* Debug FS nodes common to all T5 and later adapters.
@@ -2048,12 +2319,7 @@ int t4_setup_debugfs(struct adapter *adap)
size = t4_read_reg(adap, MA_EDRAM1_BAR_A);
add_debugfs_mem(adap, "edc1", MEM_EDC1, EDRAM1_SIZE_G(size));
}
- if (is_t4(adap->params.chip)) {
- size = t4_read_reg(adap, MA_EXT_MEMORY_BAR_A);
- if (i & EXT_MEM_ENABLE_F)
- add_debugfs_mem(adap, "mc", MEM_MC,
- EXT_MEM_SIZE_G(size));
- } else {
+ if (is_t5(adap->params.chip)) {
if (i & EXT_MEM0_ENABLE_F) {
size = t4_read_reg(adap, MA_EXT_MEMORY0_BAR_A);
add_debugfs_mem(adap, "mc0", MEM_MC0,
@@ -2064,6 +2330,11 @@ int t4_setup_debugfs(struct adapter *adap)
add_debugfs_mem(adap, "mc1", MEM_MC1,
EXT_MEM1_SIZE_G(size));
}
+ } else {
+ if (i & EXT_MEM_ENABLE_F)
+ size = t4_read_reg(adap, MA_EXT_MEMORY_BAR_A);
+ add_debugfs_mem(adap, "mc", MEM_MC,
+ EXT_MEM_SIZE_G(size));
}
de = debugfs_create_file_size("flash", S_IRUSR, adap->debugfs_root, adap,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
index 10d82b51d7ef..687acf71fa15 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
@@ -108,15 +108,82 @@ static const char stats_strings[][ETH_GSTRING_LEN] = {
"VLANinsertions ",
"GROpackets ",
"GROmerged ",
- "WriteCoalSuccess ",
- "WriteCoalFail ",
+};
+
+static char adapter_stats_strings[][ETH_GSTRING_LEN] = {
+ "db_drop ",
+ "db_full ",
+ "db_empty ",
+ "tcp_ipv4_out_rsts ",
+ "tcp_ipv4_in_segs ",
+ "tcp_ipv4_out_segs ",
+ "tcp_ipv4_retrans_segs ",
+ "tcp_ipv6_out_rsts ",
+ "tcp_ipv6_in_segs ",
+ "tcp_ipv6_out_segs ",
+ "tcp_ipv6_retrans_segs ",
+ "usm_ddp_frames ",
+ "usm_ddp_octets ",
+ "usm_ddp_drops ",
+ "rdma_no_rqe_mod_defer ",
+ "rdma_no_rqe_pkt_defer ",
+ "tp_err_ofld_no_neigh ",
+ "tp_err_ofld_cong_defer ",
+ "write_coal_success ",
+ "write_coal_fail ",
+};
+
+static char channel_stats_strings[][ETH_GSTRING_LEN] = {
+ "--------Channel--------- ",
+ "tp_cpl_requests ",
+ "tp_cpl_responses ",
+ "tp_mac_in_errs ",
+ "tp_hdr_in_errs ",
+ "tp_tcp_in_errs ",
+ "tp_tcp6_in_errs ",
+ "tp_tnl_cong_drops ",
+ "tp_tnl_tx_drops ",
+ "tp_ofld_vlan_drops ",
+ "tp_ofld_chan_drops ",
+ "fcoe_octets_ddp ",
+ "fcoe_frames_ddp ",
+ "fcoe_frames_drop ",
+};
+
+static char loopback_stats_strings[][ETH_GSTRING_LEN] = {
+ "-------Loopback----------- ",
+ "octets_ok ",
+ "frames_ok ",
+ "bcast_frames ",
+ "mcast_frames ",
+ "ucast_frames ",
+ "error_frames ",
+ "frames_64 ",
+ "frames_65_to_127 ",
+ "frames_128_to_255 ",
+ "frames_256_to_511 ",
+ "frames_512_to_1023 ",
+ "frames_1024_to_1518 ",
+ "frames_1519_to_max ",
+ "frames_dropped ",
+ "bg0_frames_dropped ",
+ "bg1_frames_dropped ",
+ "bg2_frames_dropped ",
+ "bg3_frames_dropped ",
+ "bg0_frames_trunc ",
+ "bg1_frames_trunc ",
+ "bg2_frames_trunc ",
+ "bg3_frames_trunc ",
};
static int get_sset_count(struct net_device *dev, int sset)
{
switch (sset) {
case ETH_SS_STATS:
- return ARRAY_SIZE(stats_strings);
+ return ARRAY_SIZE(stats_strings) +
+ ARRAY_SIZE(adapter_stats_strings) +
+ ARRAY_SIZE(channel_stats_strings) +
+ ARRAY_SIZE(loopback_stats_strings);
default:
return -EOPNOTSUPP;
}
@@ -168,8 +235,18 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
static void get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
- if (stringset == ETH_SS_STATS)
+ if (stringset == ETH_SS_STATS) {
memcpy(data, stats_strings, sizeof(stats_strings));
+ data += sizeof(stats_strings);
+ memcpy(data, adapter_stats_strings,
+ sizeof(adapter_stats_strings));
+ data += sizeof(adapter_stats_strings);
+ memcpy(data, channel_stats_strings,
+ sizeof(channel_stats_strings));
+ data += sizeof(channel_stats_strings);
+ memcpy(data, loopback_stats_strings,
+ sizeof(loopback_stats_strings));
+ }
}
/* port stats maintained per queue of the port. They should be in the same
@@ -185,6 +262,45 @@ struct queue_port_stats {
u64 gro_merged;
};
+struct adapter_stats {
+ u64 db_drop;
+ u64 db_full;
+ u64 db_empty;
+ u64 tcp_v4_out_rsts;
+ u64 tcp_v4_in_segs;
+ u64 tcp_v4_out_segs;
+ u64 tcp_v4_retrans_segs;
+ u64 tcp_v6_out_rsts;
+ u64 tcp_v6_in_segs;
+ u64 tcp_v6_out_segs;
+ u64 tcp_v6_retrans_segs;
+ u64 frames;
+ u64 octets;
+ u64 drops;
+ u64 rqe_dfr_mod;
+ u64 rqe_dfr_pkt;
+ u64 ofld_no_neigh;
+ u64 ofld_cong_defer;
+ u64 wc_success;
+ u64 wc_fail;
+};
+
+struct channel_stats {
+ u64 cpl_req;
+ u64 cpl_rsp;
+ u64 mac_in_errs;
+ u64 hdr_in_errs;
+ u64 tcp_in_errs;
+ u64 tcp6_in_errs;
+ u64 tnl_cong_drops;
+ u64 tnl_tx_drops;
+ u64 ofld_vlan_drops;
+ u64 ofld_chan_drops;
+ u64 octets_ddp;
+ u64 frames_ddp;
+ u64 frames_drop;
+};
+
static void collect_sge_port_stats(const struct adapter *adap,
const struct port_info *p,
struct queue_port_stats *s)
@@ -205,30 +321,121 @@ static void collect_sge_port_stats(const struct adapter *adap,
}
}
+static void collect_adapter_stats(struct adapter *adap, struct adapter_stats *s)
+{
+ struct tp_tcp_stats v4, v6;
+ struct tp_rdma_stats rdma_stats;
+ struct tp_err_stats err_stats;
+ struct tp_usm_stats usm_stats;
+ u64 val1, val2;
+
+ memset(s, 0, sizeof(*s));
+
+ spin_lock(&adap->stats_lock);
+ t4_tp_get_tcp_stats(adap, &v4, &v6);
+ t4_tp_get_rdma_stats(adap, &rdma_stats);
+ t4_get_usm_stats(adap, &usm_stats);
+ t4_tp_get_err_stats(adap, &err_stats);
+ spin_unlock(&adap->stats_lock);
+
+ s->db_drop = adap->db_stats.db_drop;
+ s->db_full = adap->db_stats.db_full;
+ s->db_empty = adap->db_stats.db_empty;
+
+ s->tcp_v4_out_rsts = v4.tcp_out_rsts;
+ s->tcp_v4_in_segs = v4.tcp_in_segs;
+ s->tcp_v4_out_segs = v4.tcp_out_segs;
+ s->tcp_v4_retrans_segs = v4.tcp_retrans_segs;
+ s->tcp_v6_out_rsts = v6.tcp_out_rsts;
+ s->tcp_v6_in_segs = v6.tcp_in_segs;
+ s->tcp_v6_out_segs = v6.tcp_out_segs;
+ s->tcp_v6_retrans_segs = v6.tcp_retrans_segs;
+
+ if (is_offload(adap)) {
+ s->frames = usm_stats.frames;
+ s->octets = usm_stats.octets;
+ s->drops = usm_stats.drops;
+ s->rqe_dfr_mod = rdma_stats.rqe_dfr_mod;
+ s->rqe_dfr_pkt = rdma_stats.rqe_dfr_pkt;
+ }
+
+ s->ofld_no_neigh = err_stats.ofld_no_neigh;
+ s->ofld_cong_defer = err_stats.ofld_cong_defer;
+
+ if (!is_t4(adap->params.chip)) {
+ int v;
+
+ v = t4_read_reg(adap, SGE_STAT_CFG_A);
+ if (STATSOURCE_T5_G(v) == 7) {
+ val2 = t4_read_reg(adap, SGE_STAT_MATCH_A);
+ val1 = t4_read_reg(adap, SGE_STAT_TOTAL_A);
+ s->wc_success = val1 - val2;
+ s->wc_fail = val2;
+ }
+ }
+}
+
+static void collect_channel_stats(struct adapter *adap, struct channel_stats *s,
+ u8 i)
+{
+ struct tp_cpl_stats cpl_stats;
+ struct tp_err_stats err_stats;
+ struct tp_fcoe_stats fcoe_stats;
+
+ memset(s, 0, sizeof(*s));
+
+ spin_lock(&adap->stats_lock);
+ t4_tp_get_cpl_stats(adap, &cpl_stats);
+ t4_tp_get_err_stats(adap, &err_stats);
+ t4_get_fcoe_stats(adap, i, &fcoe_stats);
+ spin_unlock(&adap->stats_lock);
+
+ s->cpl_req = cpl_stats.req[i];
+ s->cpl_rsp = cpl_stats.rsp[i];
+ s->mac_in_errs = err_stats.mac_in_errs[i];
+ s->hdr_in_errs = err_stats.hdr_in_errs[i];
+ s->tcp_in_errs = err_stats.tcp_in_errs[i];
+ s->tcp6_in_errs = err_stats.tcp6_in_errs[i];
+ s->tnl_cong_drops = err_stats.tnl_cong_drops[i];
+ s->tnl_tx_drops = err_stats.tnl_tx_drops[i];
+ s->ofld_vlan_drops = err_stats.ofld_vlan_drops[i];
+ s->ofld_chan_drops = err_stats.ofld_chan_drops[i];
+ s->octets_ddp = fcoe_stats.octets_ddp;
+ s->frames_ddp = fcoe_stats.frames_ddp;
+ s->frames_drop = fcoe_stats.frames_drop;
+}
+
static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
u64 *data)
{
struct port_info *pi = netdev_priv(dev);
struct adapter *adapter = pi->adapter;
- u32 val1, val2;
+ struct lb_port_stats s;
+ int i;
+ u64 *p0;
- t4_get_port_stats(adapter, pi->tx_chan, (struct port_stats *)data);
+ t4_get_port_stats_offset(adapter, pi->tx_chan,
+ (struct port_stats *)data,
+ &pi->stats_base);
data += sizeof(struct port_stats) / sizeof(u64);
collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data);
data += sizeof(struct queue_port_stats) / sizeof(u64);
- if (!is_t4(adapter->params.chip)) {
- t4_write_reg(adapter, SGE_STAT_CFG_A, STATSOURCE_T5_V(7));
- val1 = t4_read_reg(adapter, SGE_STAT_TOTAL_A);
- val2 = t4_read_reg(adapter, SGE_STAT_MATCH_A);
- *data = val1 - val2;
- data++;
- *data = val2;
- data++;
- } else {
- memset(data, 0, 2 * sizeof(u64));
- *data += 2;
- }
+ collect_adapter_stats(adapter, (struct adapter_stats *)data);
+ data += sizeof(struct adapter_stats) / sizeof(u64);
+
+ *data++ = (u64)pi->port_id;
+ collect_channel_stats(adapter, (struct channel_stats *)data,
+ pi->port_id);
+ data += sizeof(struct channel_stats) / sizeof(u64);
+
+ *data++ = (u64)pi->port_id;
+ memset(&s, 0, sizeof(s));
+ t4_get_lb_stats(adapter, pi->port_id, &s);
+
+ p0 = &s.octets;
+ for (i = 0; i < ARRAY_SIZE(loopback_stats_strings) - 1; i++)
+ *data++ = (unsigned long long)*p0++;
}
static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
@@ -250,7 +457,7 @@ static int restart_autoneg(struct net_device *dev)
return -EAGAIN;
if (p->link_cfg.autoneg != AUTONEG_ENABLE)
return -EINVAL;
- t4_restart_aneg(p->adapter, p->adapter->fn, p->tx_chan);
+ t4_restart_aneg(p->adapter, p->adapter->pf, p->tx_chan);
return 0;
}
@@ -267,7 +474,7 @@ static int identify_port(struct net_device *dev,
else
return -EINVAL;
- return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid, val);
+ return t4_identify_port(adap, adap->pf, netdev2pinfo(dev)->viid, val);
}
static unsigned int from_fw_linkcaps(enum fw_port_type type, unsigned int caps)
@@ -439,7 +646,7 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
lc->autoneg = cmd->autoneg;
if (netif_running(dev))
- return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan,
+ return t4_link_l1cfg(p->adapter, p->adapter->pf, p->tx_chan,
lc);
return 0;
}
@@ -472,7 +679,7 @@ static int set_pauseparam(struct net_device *dev,
if (epause->tx_pause)
lc->requested_fc |= PAUSE_TX;
if (netif_running(dev))
- return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan,
+ return t4_link_l1cfg(p->adapter, p->adapter->pf, p->tx_chan,
lc);
return 0;
}
@@ -578,7 +785,7 @@ static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
const struct sge_rspq *rq = &adap->sge.ethrxq[pi->first_qset].rspq;
c->rx_coalesce_usecs = qtimer_val(adap, rq);
- c->rx_max_coalesced_frames = (rq->intr_params & QINTR_CNT_EN) ?
+ c->rx_max_coalesced_frames = (rq->intr_params & QINTR_CNT_EN_F) ?
adap->sge.counter_val[rq->pktcnt_idx] : 0;
c->use_adaptive_rx_coalesce = get_adaptive_rx_setting(dev);
return 0;
@@ -617,7 +824,7 @@ static int eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz)
*/
static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v)
{
- int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE);
+ int vaddr = eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE);
if (vaddr >= 0)
vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v);
@@ -626,7 +833,7 @@ static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v)
static int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v)
{
- int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE);
+ int vaddr = eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE);
if (vaddr >= 0)
vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v);
@@ -669,8 +876,8 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
aligned_offset = eeprom->offset & ~3;
aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
- if (adapter->fn > 0) {
- u32 start = 1024 + adapter->fn * EEPROMPFSIZE;
+ if (adapter->pf > 0) {
+ u32 start = 1024 + adapter->pf * EEPROMPFSIZE;
if (aligned_offset < start ||
aligned_offset + aligned_len > start + EEPROMPFSIZE)
@@ -740,37 +947,6 @@ static int set_flash(struct net_device *netdev, struct ethtool_flash *ef)
return ret;
}
-#define WOL_SUPPORTED (WAKE_BCAST | WAKE_MAGIC)
-#define BCAST_CRC 0xa0ccc1a6
-
-static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
- wol->supported = WAKE_BCAST | WAKE_MAGIC;
- wol->wolopts = netdev2adap(dev)->wol;
- memset(&wol->sopass, 0, sizeof(wol->sopass));
-}
-
-static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
- int err = 0;
- struct port_info *pi = netdev_priv(dev);
-
- if (wol->wolopts & ~WOL_SUPPORTED)
- return -EINVAL;
- t4_wol_magic_enable(pi->adapter, pi->tx_chan,
- (wol->wolopts & WAKE_MAGIC) ? dev->dev_addr : NULL);
- if (wol->wolopts & WAKE_BCAST) {
- err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0xfe, ~0ULL,
- ~0ULL, 0, false);
- if (!err)
- err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 1,
- ~6ULL, ~0ULL, BCAST_CRC, true);
- } else {
- t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0, 0, 0, 0, false);
- }
- return err;
-}
-
static u32 get_rss_table_size(struct net_device *dev)
{
const struct port_info *pi = netdev_priv(dev);
@@ -900,8 +1076,6 @@ static const struct ethtool_ops cxgb_ethtool_ops = {
.get_ethtool_stats = get_stats,
.get_regs_len = get_regs_len,
.get_regs = get_regs,
- .get_wol = get_wol,
- .set_wol = set_wol,
.get_rxnfc = get_rxnfc,
.get_rxfh_indir_size = get_rss_table_size,
.get_rxfh = get_rss_table,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index a9355593e65e..c64b5a99bfef 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -135,8 +135,14 @@ struct filter_entry {
#define FW4_FNAME "cxgb4/t4fw.bin"
#define FW5_FNAME "cxgb4/t5fw.bin"
+#define FW6_FNAME "cxgb4/t6fw.bin"
#define FW4_CFNAME "cxgb4/t4-config.txt"
#define FW5_CFNAME "cxgb4/t5-config.txt"
+#define FW6_CFNAME "cxgb4/t6-config.txt"
+#define PHY_AQ1202_FIRMWARE "cxgb4/aq1202_fw.cld"
+#define PHY_BCM84834_FIRMWARE "cxgb4/bcm8483.bin"
+#define PHY_AQ1202_DEVICEID 0x4409
+#define PHY_BCM84834_DEVICEID 0x4486
MODULE_DESCRIPTION(DRV_DESC);
MODULE_AUTHOR("Chelsio Communications");
@@ -318,8 +324,9 @@ static void dcb_tx_queue_prio_enable(struct net_device *dev, int enable)
* level") we need to issue the Set Parameters Commannd
* without sleeping (timeout < 0).
*/
- err = t4_set_params_nosleep(adap, adap->mbox, adap->fn, 0, 1,
- &name, &value);
+ err = t4_set_params_timeout(adap, adap->mbox, adap->pf, 0, 1,
+ &name, &value,
+ -FW_CMD_MAX_TIMEOUT);
if (err)
dev_err(adap->pdev_dev,
@@ -382,7 +389,7 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
int uc_cnt = netdev_uc_count(dev);
int mc_cnt = netdev_mc_count(dev);
const struct port_info *pi = netdev_priv(dev);
- unsigned int mb = pi->adapter->fn;
+ unsigned int mb = pi->adapter->pf;
/* first do the secondary unicast addresses */
netdev_for_each_uc_addr(ha, dev) {
@@ -439,7 +446,7 @@ static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
ret = set_addr_filters(dev, sleep_ok);
if (ret == 0)
- ret = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, mtu,
+ ret = t4_set_rxmode(pi->adapter, pi->adapter->pf, pi->viid, mtu,
(dev->flags & IFF_PROMISC) ? 1 : 0,
(dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1,
sleep_ok);
@@ -456,7 +463,7 @@ static int link_start(struct net_device *dev)
{
int ret;
struct port_info *pi = netdev_priv(dev);
- unsigned int mb = pi->adapter->fn;
+ unsigned int mb = pi->adapter->pf;
/*
* We do not set address filters and promiscuity here, the stack does
@@ -474,7 +481,7 @@ static int link_start(struct net_device *dev)
}
}
if (ret == 0)
- ret = t4_link_start(pi->adapter, mb, pi->tx_chan,
+ ret = t4_link_l1cfg(pi->adapter, mb, pi->tx_chan,
&pi->link_cfg);
if (ret == 0) {
local_bh_disable();
@@ -856,23 +863,39 @@ static void free_msix_queue_irqs(struct adapter *adap)
*
* Sets up the portion of the HW RSS table for the port's VI to distribute
* packets to the Rx queues in @queues.
+ * Should never be called before setting up sge eth rx queues
*/
int cxgb4_write_rss(const struct port_info *pi, const u16 *queues)
{
u16 *rss;
int i, err;
- const struct sge_eth_rxq *q = &pi->adapter->sge.ethrxq[pi->first_qset];
+ struct adapter *adapter = pi->adapter;
+ const struct sge_eth_rxq *rxq;
+ rxq = &adapter->sge.ethrxq[pi->first_qset];
rss = kmalloc(pi->rss_size * sizeof(u16), GFP_KERNEL);
if (!rss)
return -ENOMEM;
/* map the queue indices to queue ids */
for (i = 0; i < pi->rss_size; i++, queues++)
- rss[i] = q[*queues].rspq.abs_id;
+ rss[i] = rxq[*queues].rspq.abs_id;
- err = t4_config_rss_range(pi->adapter, pi->adapter->fn, pi->viid, 0,
+ err = t4_config_rss_range(adapter, adapter->pf, pi->viid, 0,
pi->rss_size, rss, pi->rss_size);
+ /* If Tunnel All Lookup isn't specified in the global RSS
+ * Configuration, then we need to specify a default Ingress
+ * Queue for any ingress packets which aren't hashed. We'll
+ * use our first ingress queue ...
+ */
+ if (!err)
+ err = t4_config_vi_rss(adapter, adapter->mbox, pi->viid,
+ FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F |
+ FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F |
+ FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F |
+ FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F |
+ FW_RSS_VI_CONFIG_CMD_UDPEN_F,
+ rss[0]);
kfree(rss);
return err;
}
@@ -885,11 +908,15 @@ int cxgb4_write_rss(const struct port_info *pi, const u16 *queues)
*/
static int setup_rss(struct adapter *adap)
{
- int i, err;
+ int i, j, err;
for_each_port(adap, i) {
const struct port_info *pi = adap2pinfo(adap, i);
+ /* Fill default values with equal distribution */
+ for (j = 0; j < pi->rss_size; j++)
+ pi->rss[j] = j % pi->nqsets;
+
err = cxgb4_write_rss(pi, pi->rss);
if (err)
return err;
@@ -977,7 +1004,7 @@ static int alloc_ofld_rxqs(struct adapter *adap, struct sge_ofld_rxq *q,
err = t4_sge_alloc_rxq(adap, &q->rspq, false,
adap->port[i / per_chan],
msi_idx, q->fl.size ? &q->fl : NULL,
- uldrx_handler);
+ uldrx_handler, 0);
if (err)
return err;
memset(&q->stats, 0, sizeof(q->stats));
@@ -1007,7 +1034,7 @@ static int setup_sge_queues(struct adapter *adap)
msi_idx = 1; /* vector 0 is for non-queue interrupts */
else {
err = t4_sge_alloc_rxq(adap, &s->intrq, false, adap->port[0], 0,
- NULL, NULL);
+ NULL, NULL, -1);
if (err)
return err;
msi_idx = -((int)s->intrq.abs_id + 1);
@@ -1027,7 +1054,7 @@ static int setup_sge_queues(struct adapter *adap)
* new/deleted queues.
*/
err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0],
- msi_idx, NULL, fwevtq_handler);
+ msi_idx, NULL, fwevtq_handler, -1);
if (err) {
freeout: t4_free_sge_resources(adap);
return err;
@@ -1044,7 +1071,9 @@ freeout: t4_free_sge_resources(adap);
msi_idx++;
err = t4_sge_alloc_rxq(adap, &q->rspq, false, dev,
msi_idx, &q->fl,
- t4_ethrx_handler);
+ t4_ethrx_handler,
+ t4_get_mps_bg_map(adap,
+ pi->tx_chan));
if (err)
goto freeout;
q->rspq.idx = j;
@@ -1324,11 +1353,6 @@ static u16 cxgb_select_queue(struct net_device *dev, struct sk_buff *skb,
return fallback(dev, skb) % dev->real_num_tx_queues;
}
-static inline int is_offload(const struct adapter *adap)
-{
- return adap->params.offload;
-}
-
static int closest_timer(const struct sge *s, int time)
{
int i, delta, match = 0, min_delta = INT_MAX;
@@ -1389,8 +1413,8 @@ int cxgb4_set_rspq_intr_params(struct sge_rspq *q,
FW_PARAMS_PARAM_X_V(
FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH) |
FW_PARAMS_PARAM_YZ_V(q->cntxt_id);
- err = t4_set_params(adap, adap->fn, adap->fn, 0, 1, &v,
- &new_idx);
+ err = t4_set_params(adap, adap->mbox, adap->pf, 0, 1,
+ &v, &new_idx);
if (err)
return err;
}
@@ -1398,7 +1422,7 @@ int cxgb4_set_rspq_intr_params(struct sge_rspq *q,
}
us = us == 0 ? 6 : closest_timer(&adap->sge, us);
- q->intr_params = QINTR_TIMER_IDX(us) | (cnt > 0 ? QINTR_CNT_EN : 0);
+ q->intr_params = QINTR_TIMER_IDX_V(us) | QINTR_CNT_EN_V(cnt > 0);
return 0;
}
@@ -1411,7 +1435,7 @@ static int cxgb_set_features(struct net_device *dev, netdev_features_t features)
if (!(changed & NETIF_F_HW_VLAN_CTAG_RX))
return 0;
- err = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1,
+ err = t4_set_rxmode(pi->adapter, pi->adapter->pf, pi->viid, -1,
-1, -1, -1,
!!(features & NETIF_F_HW_VLAN_CTAG_RX), true);
if (unlikely(err))
@@ -1694,7 +1718,7 @@ static int tid_init(struct tid_info *t)
bitmap_zero(t->stid_bmap, t->nstids + t->nsftids);
/* Reserve stid 0 for T4/T5 adapters */
if (!t->stid_base &&
- (is_t4(adap->params.chip) || is_t5(adap->params.chip)))
+ (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5))
__set_bit(0, t->stid_bmap);
return 0;
@@ -1983,11 +2007,8 @@ EXPORT_SYMBOL(cxgb4_iscsi_init);
int cxgb4_flush_eq_cache(struct net_device *dev)
{
struct adapter *adap = netdev2adap(dev);
- int ret;
- ret = t4_fwaddrspace_write(adap, adap->mbox,
- 0xe1000000 + SGE_CTXT_CMD_A, 0x20000000);
- return ret;
+ return t4_sge_ctxt_flush(adap, adap->mbox);
}
EXPORT_SYMBOL(cxgb4_flush_eq_cache);
@@ -2042,25 +2063,6 @@ out:
}
EXPORT_SYMBOL(cxgb4_sync_txq_pidx);
-void cxgb4_disable_db_coalescing(struct net_device *dev)
-{
- struct adapter *adap;
-
- adap = netdev2adap(dev);
- t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, NOCOALESCE_F,
- NOCOALESCE_F);
-}
-EXPORT_SYMBOL(cxgb4_disable_db_coalescing);
-
-void cxgb4_enable_db_coalescing(struct net_device *dev)
-{
- struct adapter *adap;
-
- adap = netdev2adap(dev);
- t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, NOCOALESCE_F, 0);
-}
-EXPORT_SYMBOL(cxgb4_enable_db_coalescing);
-
int cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte)
{
struct adapter *adap;
@@ -2100,10 +2102,7 @@ int cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte)
if (offset < mc0_end) {
memtype = MEM_MC0;
memaddr = offset - edc1_end;
- } else if (is_t4(adap->params.chip)) {
- /* T4 only has a single memory channel */
- goto err;
- } else {
+ } else if (is_t5(adap->params.chip)) {
size = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A);
mc1_size = EXT_MEM1_SIZE_G(size) << 20;
mc1_end = mc0_end + mc1_size;
@@ -2114,6 +2113,9 @@ int cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte)
/* offset beyond the end of any memory */
goto err;
}
+ } else {
+ /* T4/T6 only has a single memory channel */
+ goto err;
}
}
@@ -2149,7 +2151,7 @@ int cxgb4_bar2_sge_qregs(struct net_device *dev,
u64 *pbar2_qoffset,
unsigned int *pbar2_qid)
{
- return cxgb4_t4_bar2_sge_qregs(netdev2adap(dev),
+ return t4_bar2_sge_qregs(netdev2adap(dev),
qid,
(qtype == CXGB4_BAR2_QTYPE_EGRESS
? T4_BAR2_QTYPE_EGRESS
@@ -2280,9 +2282,13 @@ static void process_db_full(struct work_struct *work)
drain_db_fifo(adap, dbfifo_drain_delay);
enable_dbs(adap);
notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
- t4_set_reg_field(adap, SGE_INT_ENABLE3_A,
- DBFIFO_HP_INT_F | DBFIFO_LP_INT_F,
- DBFIFO_HP_INT_F | DBFIFO_LP_INT_F);
+ if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5)
+ t4_set_reg_field(adap, SGE_INT_ENABLE3_A,
+ DBFIFO_HP_INT_F | DBFIFO_LP_INT_F,
+ DBFIFO_HP_INT_F | DBFIFO_LP_INT_F);
+ else
+ t4_set_reg_field(adap, SGE_INT_ENABLE3_A,
+ DBFIFO_LP_INT_F, DBFIFO_LP_INT_F);
}
static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q)
@@ -2344,7 +2350,7 @@ static void process_db_drop(struct work_struct *work)
drain_db_fifo(adap, dbfifo_drain_delay);
enable_dbs(adap);
notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
- } else {
+ } else if (is_t5(adap->params.chip)) {
u32 dropped_db = t4_read_reg(adap, 0x010ac);
u16 qid = (dropped_db >> 15) & 0x1ffff;
u16 pidx_inc = dropped_db & 0x1fff;
@@ -2352,8 +2358,8 @@ static void process_db_drop(struct work_struct *work)
unsigned int bar2_qid;
int ret;
- ret = cxgb4_t4_bar2_sge_qregs(adap, qid, T4_BAR2_QTYPE_EGRESS,
- 0, &bar2_qoffset, &bar2_qid);
+ ret = t4_bar2_sge_qregs(adap, qid, T4_BAR2_QTYPE_EGRESS,
+ 0, &bar2_qoffset, &bar2_qid);
if (ret)
dev_err(adap->pdev_dev, "doorbell drop recovery: "
"qid=%d, pidx_inc=%d\n", qid, pidx_inc);
@@ -2365,7 +2371,8 @@ static void process_db_drop(struct work_struct *work)
t4_set_reg_field(adap, 0x10b0, 1<<15, 1<<15);
}
- t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, DROPPED_DB_F, 0);
+ if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5)
+ t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, DROPPED_DB_F, 0);
}
void t4_db_full(struct adapter *adap)
@@ -2395,7 +2402,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
unsigned short i;
lli.pdev = adap->pdev;
- lli.pf = adap->fn;
+ lli.pf = adap->pf;
lli.l2t = adap->l2t;
lli.tids = &adap->tids;
lli.ports = adap->port;
@@ -2434,6 +2441,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
lli.max_ordird_qp = adap->params.max_ordird_qp;
lli.max_ird_adapter = adap->params.max_ird_adapter;
lli.ulptx_memwrite_dsgl = adap->params.ulptx_memwrite_dsgl;
+ lli.nodeid = dev_to_node(adap->pdev_dev);
handle = ulds[uld].add(&lli);
if (IS_ERR(handle)) {
@@ -2731,7 +2739,7 @@ static int cxgb_close(struct net_device *dev)
netif_tx_stop_all_queues(dev);
netif_carrier_off(dev);
- return t4_enable_vi(adapter, adapter->fn, pi->viid, false, false);
+ return t4_enable_vi(adapter, adapter->pf, pi->viid, false, false);
}
/* Return an error number if the indicated filter isn't writable ...
@@ -2875,7 +2883,8 @@ static struct rtnl_link_stats64 *cxgb_get_stats(struct net_device *dev,
spin_unlock(&adapter->stats_lock);
return ns;
}
- t4_get_port_stats(adapter, p->tx_chan, &stats);
+ t4_get_port_stats_offset(adapter, p->tx_chan, &stats,
+ &p->stats_base);
spin_unlock(&adapter->stats_lock);
ns->tx_bytes = stats.tx_octets;
@@ -2934,7 +2943,7 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
} else
return -EINVAL;
- mbox = pi->adapter->fn;
+ mbox = pi->adapter->pf;
if (cmd == SIOCGMIIREG)
ret = t4_mdio_rd(pi->adapter, mbox, prtad, devad,
data->reg_num, &data->val_out);
@@ -2961,7 +2970,7 @@ static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
if (new_mtu < 81 || new_mtu > MAX_MTU) /* accommodate SACK */
return -EINVAL;
- ret = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, new_mtu, -1,
+ ret = t4_set_rxmode(pi->adapter, pi->adapter->pf, pi->viid, new_mtu, -1,
-1, -1, -1, true);
if (!ret)
dev->mtu = new_mtu;
@@ -2977,7 +2986,7 @@ static int cxgb_set_mac_addr(struct net_device *dev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
- ret = t4_change_mac(pi->adapter, pi->adapter->fn, pi->viid,
+ ret = t4_change_mac(pi->adapter, pi->adapter->pf, pi->viid,
pi->xact_addr_filt, addr->sa_data, true, true);
if (ret < 0)
return ret;
@@ -3036,86 +3045,11 @@ void t4_fatal_err(struct adapter *adap)
dev_alert(adap->pdev_dev, "encountered fatal error, adapter stopped\n");
}
-/* Return the specified PCI-E Configuration Space register from our Physical
- * Function. We try first via a Firmware LDST Command since we prefer to let
- * the firmware own all of these registers, but if that fails we go for it
- * directly ourselves.
- */
-static u32 t4_read_pcie_cfg4(struct adapter *adap, int reg)
-{
- struct fw_ldst_cmd ldst_cmd;
- u32 val;
- int ret;
-
- /* Construct and send the Firmware LDST Command to retrieve the
- * specified PCI-E Configuration Space register.
- */
- memset(&ldst_cmd, 0, sizeof(ldst_cmd));
- ldst_cmd.op_to_addrspace =
- htonl(FW_CMD_OP_V(FW_LDST_CMD) |
- FW_CMD_REQUEST_F |
- FW_CMD_READ_F |
- FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_FUNC_PCIE));
- ldst_cmd.cycles_to_len16 = htonl(FW_LEN16(ldst_cmd));
- ldst_cmd.u.pcie.select_naccess = FW_LDST_CMD_NACCESS_V(1);
- ldst_cmd.u.pcie.ctrl_to_fn =
- (FW_LDST_CMD_LC_F | FW_LDST_CMD_FN_V(adap->fn));
- ldst_cmd.u.pcie.r = reg;
- ret = t4_wr_mbox(adap, adap->mbox, &ldst_cmd, sizeof(ldst_cmd),
- &ldst_cmd);
-
- /* If the LDST Command suucceeded, exctract the returned register
- * value. Otherwise read it directly ourself.
- */
- if (ret == 0)
- val = ntohl(ldst_cmd.u.pcie.data[0]);
- else
- t4_hw_pci_read_cfg4(adap, reg, &val);
-
- return val;
-}
-
static void setup_memwin(struct adapter *adap)
{
- u32 mem_win0_base, mem_win1_base, mem_win2_base, mem_win2_aperture;
+ u32 nic_win_base = t4_get_util_window(adap);
- if (is_t4(adap->params.chip)) {
- u32 bar0;
-
- /* Truncation intentional: we only read the bottom 32-bits of
- * the 64-bit BAR0/BAR1 ... We use the hardware backdoor
- * mechanism to read BAR0 instead of using
- * pci_resource_start() because we could be operating from
- * within a Virtual Machine which is trapping our accesses to
- * our Configuration Space and we need to set up the PCI-E
- * Memory Window decoders with the actual addresses which will
- * be coming across the PCI-E link.
- */
- bar0 = t4_read_pcie_cfg4(adap, PCI_BASE_ADDRESS_0);
- bar0 &= PCI_BASE_ADDRESS_MEM_MASK;
- adap->t4_bar0 = bar0;
-
- mem_win0_base = bar0 + MEMWIN0_BASE;
- mem_win1_base = bar0 + MEMWIN1_BASE;
- mem_win2_base = bar0 + MEMWIN2_BASE;
- mem_win2_aperture = MEMWIN2_APERTURE;
- } else {
- /* For T5, only relative offset inside the PCIe BAR is passed */
- mem_win0_base = MEMWIN0_BASE;
- mem_win1_base = MEMWIN1_BASE;
- mem_win2_base = MEMWIN2_BASE_T5;
- mem_win2_aperture = MEMWIN2_APERTURE_T5;
- }
- t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 0),
- mem_win0_base | BIR_V(0) |
- WINDOW_V(ilog2(MEMWIN0_APERTURE) - 10));
- t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 1),
- mem_win1_base | BIR_V(0) |
- WINDOW_V(ilog2(MEMWIN1_APERTURE) - 10));
- t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 2),
- mem_win2_base | BIR_V(0) |
- WINDOW_V(ilog2(mem_win2_aperture) - 10));
- t4_read_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 2));
+ t4_setup_memwin(adap, nic_win_base, MEMWIN_NIC);
}
static void setup_memwin_rdma(struct adapter *adap)
@@ -3149,7 +3083,7 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
c->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
FW_CMD_REQUEST_F | FW_CMD_READ_F);
c->cfvalid_to_len16 = htonl(FW_LEN16(*c));
- ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), c);
+ ret = t4_wr_mbox(adap, adap->mbox, c, sizeof(*c), c);
if (ret < 0)
return ret;
@@ -3165,18 +3099,18 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
}
c->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
- ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), NULL);
+ ret = t4_wr_mbox(adap, adap->mbox, c, sizeof(*c), NULL);
if (ret < 0)
return ret;
- ret = t4_config_glbl_rss(adap, adap->fn,
+ ret = t4_config_glbl_rss(adap, adap->pf,
FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL,
FW_RSS_GLB_CONFIG_CMD_TNLMAPEN_F |
FW_RSS_GLB_CONFIG_CMD_TNLALLLKP_F);
if (ret < 0)
return ret;
- ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, adap->sge.egr_sz, 64,
+ ret = t4_cfg_pfvf(adap, adap->mbox, adap->pf, 0, adap->sge.egr_sz, 64,
MAX_INGQ, 0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF,
FW_CMD_CAP_PF);
if (ret < 0)
@@ -3220,7 +3154,7 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
}
/* get basic stuff going */
- return t4_early_init(adap, adap->fn);
+ return t4_early_init(adap, adap->pf);
}
/*
@@ -3276,6 +3210,142 @@ static int adap_init0_tweaks(struct adapter *adapter)
return 0;
}
+/* 10Gb/s-BT PHY Support. chip-external 10Gb/s-BT PHYs are complex chips
+ * unto themselves and they contain their own firmware to perform their
+ * tasks ...
+ */
+static int phy_aq1202_version(const u8 *phy_fw_data,
+ size_t phy_fw_size)
+{
+ int offset;
+
+ /* At offset 0x8 you're looking for the primary image's
+ * starting offset which is 3 Bytes wide
+ *
+ * At offset 0xa of the primary image, you look for the offset
+ * of the DRAM segment which is 3 Bytes wide.
+ *
+ * The FW version is at offset 0x27e of the DRAM and is 2 Bytes
+ * wide
+ */
+ #define be16(__p) (((__p)[0] << 8) | (__p)[1])
+ #define le16(__p) ((__p)[0] | ((__p)[1] << 8))
+ #define le24(__p) (le16(__p) | ((__p)[2] << 16))
+
+ offset = le24(phy_fw_data + 0x8) << 12;
+ offset = le24(phy_fw_data + offset + 0xa);
+ return be16(phy_fw_data + offset + 0x27e);
+
+ #undef be16
+ #undef le16
+ #undef le24
+}
+
+static struct info_10gbt_phy_fw {
+ unsigned int phy_fw_id; /* PCI Device ID */
+ char *phy_fw_file; /* /lib/firmware/ PHY Firmware file */
+ int (*phy_fw_version)(const u8 *phy_fw_data, size_t phy_fw_size);
+ int phy_flash; /* Has FLASH for PHY Firmware */
+} phy_info_array[] = {
+ {
+ PHY_AQ1202_DEVICEID,
+ PHY_AQ1202_FIRMWARE,
+ phy_aq1202_version,
+ 1,
+ },
+ {
+ PHY_BCM84834_DEVICEID,
+ PHY_BCM84834_FIRMWARE,
+ NULL,
+ 0,
+ },
+ { 0, NULL, NULL },
+};
+
+static struct info_10gbt_phy_fw *find_phy_info(int devid)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(phy_info_array); i++) {
+ if (phy_info_array[i].phy_fw_id == devid)
+ return &phy_info_array[i];
+ }
+ return NULL;
+}
+
+/* Handle updating of chip-external 10Gb/s-BT PHY firmware. This needs to
+ * happen after the FW_RESET_CMD but before the FW_INITIALIZE_CMD. On error
+ * we return a negative error number. If we transfer new firmware we return 1
+ * (from t4_load_phy_fw()). If we don't do anything we return 0.
+ */
+static int adap_init0_phy(struct adapter *adap)
+{
+ const struct firmware *phyf;
+ int ret;
+ struct info_10gbt_phy_fw *phy_info;
+
+ /* Use the device ID to determine which PHY file to flash.
+ */
+ phy_info = find_phy_info(adap->pdev->device);
+ if (!phy_info) {
+ dev_warn(adap->pdev_dev,
+ "No PHY Firmware file found for this PHY\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* If we have a T4 PHY firmware file under /lib/firmware/cxgb4/, then
+ * use that. The adapter firmware provides us with a memory buffer
+ * where we can load a PHY firmware file from the host if we want to
+ * override the PHY firmware File in flash.
+ */
+ ret = request_firmware_direct(&phyf, phy_info->phy_fw_file,
+ adap->pdev_dev);
+ if (ret < 0) {
+ /* For adapters without FLASH attached to PHY for their
+ * firmware, it's obviously a fatal error if we can't get the
+ * firmware to the adapter. For adapters with PHY firmware
+ * FLASH storage, it's worth a warning if we can't find the
+ * PHY Firmware but we'll neuter the error ...
+ */
+ dev_err(adap->pdev_dev, "unable to find PHY Firmware image "
+ "/lib/firmware/%s, error %d\n",
+ phy_info->phy_fw_file, -ret);
+ if (phy_info->phy_flash) {
+ int cur_phy_fw_ver = 0;
+
+ t4_phy_fw_ver(adap, &cur_phy_fw_ver);
+ dev_warn(adap->pdev_dev, "continuing with, on-adapter "
+ "FLASH copy, version %#x\n", cur_phy_fw_ver);
+ ret = 0;
+ }
+
+ return ret;
+ }
+
+ /* Load PHY Firmware onto adapter.
+ */
+ ret = t4_load_phy_fw(adap, MEMWIN_NIC, &adap->win0_lock,
+ phy_info->phy_fw_version,
+ (u8 *)phyf->data, phyf->size);
+ if (ret < 0)
+ dev_err(adap->pdev_dev, "PHY Firmware transfer error %d\n",
+ -ret);
+ else if (ret > 0) {
+ int new_phy_fw_ver = 0;
+
+ if (phy_info->phy_fw_version)
+ new_phy_fw_ver = phy_info->phy_fw_version(phyf->data,
+ phyf->size);
+ dev_info(adap->pdev_dev, "Successfully transferred PHY "
+ "Firmware /lib/firmware/%s, version %#x\n",
+ phy_info->phy_fw_file, new_phy_fw_ver);
+ }
+
+ release_firmware(phyf);
+
+ return ret;
+}
+
/*
* Attempt to initialize the adapter via a Firmware Configuration File.
*/
@@ -3300,6 +3370,16 @@ static int adap_init0_config(struct adapter *adapter, int reset)
goto bye;
}
+ /* If this is a 10Gb/s-BT adapter make sure the chip-external
+ * 10Gb/s-BT PHYs have up-to-date firmware. Note that this step needs
+ * to be performed after any global adapter RESET above since some
+ * PHYs only have local RAM copies of the PHY firmware.
+ */
+ if (is_10gbt_device(adapter->pdev->device)) {
+ ret = adap_init0_phy(adapter);
+ if (ret < 0)
+ goto bye;
+ }
/*
* If we have a T4 configuration file under /lib/firmware/cxgb4/,
* then use that. Otherwise, use the configuration file stored
@@ -3312,6 +3392,9 @@ static int adap_init0_config(struct adapter *adapter, int reset)
case CHELSIO_T5:
fw_config_file = FW5_CFNAME;
break;
+ case CHELSIO_T6:
+ fw_config_file = FW6_CFNAME;
+ break;
default:
dev_err(adapter->pdev_dev, "Device %d is not supported\n",
adapter->pdev->device);
@@ -3337,7 +3420,7 @@ static int adap_init0_config(struct adapter *adapter, int reset)
params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CF));
ret = t4_query_params(adapter, adapter->mbox,
- adapter->fn, 0, 1, params, val);
+ adapter->pf, 0, 1, params, val);
if (ret == 0) {
/*
* For t4_memory_rw() below addresses and
@@ -3508,7 +3591,24 @@ static struct fw_info fw_info_array[] = {
.intfver_iscsi = FW_INTFVER(T5, ISCSI),
.intfver_fcoe = FW_INTFVER(T5, FCOE),
},
+ }, {
+ .chip = CHELSIO_T6,
+ .fs_name = FW6_CFNAME,
+ .fw_mod_name = FW6_FNAME,
+ .fw_hdr = {
+ .chip = FW_HDR_CHIP_T6,
+ .fw_ver = __cpu_to_be32(FW_VERSION(T6)),
+ .intfver_nic = FW_INTFVER(T6, NIC),
+ .intfver_vnic = FW_INTFVER(T6, VNIC),
+ .intfver_ofld = FW_INTFVER(T6, OFLD),
+ .intfver_ri = FW_INTFVER(T6, RI),
+ .intfver_iscsipdu = FW_INTFVER(T6, ISCSIPDU),
+ .intfver_iscsi = FW_INTFVER(T6, ISCSI),
+ .intfver_fcoepdu = FW_INTFVER(T6, FCOEPDU),
+ .intfver_fcoe = FW_INTFVER(T6, FCOE),
+ },
}
+
};
static struct fw_info *find_fw_info(int chip)
@@ -3614,7 +3714,7 @@ static int adap_init0(struct adapter *adap)
* the firmware. On the other hand, we need these fairly early on
* so we do this right after getting ahold of the firmware.
*/
- ret = get_vpd_params(adap, &adap->params.vpd);
+ ret = t4_get_vpd_params(adap, &adap->params.vpd);
if (ret < 0)
goto bye;
@@ -3626,7 +3726,7 @@ static int adap_init0(struct adapter *adap)
v =
FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PORTVEC);
- ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 1, &v, &port_vec);
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, &v, &port_vec);
if (ret < 0)
goto bye;
@@ -3649,7 +3749,7 @@ static int adap_init0(struct adapter *adap)
*/
params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CF));
- ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 1,
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1,
params, val);
/* If the firmware doesn't support Configuration Files,
@@ -3708,7 +3808,7 @@ static int adap_init0(struct adapter *adap)
params[3] = FW_PARAM_PFVF(FILTER_START);
params[4] = FW_PARAM_PFVF(FILTER_END);
params[5] = FW_PARAM_PFVF(IQFLINT_START);
- ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 6, params, val);
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6, params, val);
if (ret < 0)
goto bye;
adap->sge.egr_start = val[0];
@@ -3726,7 +3826,7 @@ static int adap_init0(struct adapter *adap)
*/
params[0] = FW_PARAM_PFVF(EQ_END);
params[1] = FW_PARAM_PFVF(IQFLINT_END);
- ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val);
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, val);
if (ret < 0)
goto bye;
adap->sge.egr_sz = val[0] - adap->sge.egr_start + 1;
@@ -3747,7 +3847,7 @@ static int adap_init0(struct adapter *adap)
}
/* Allocate the memory for the vaious egress queue bitmaps
- * ie starving_fl and txq_maperr.
+ * ie starving_fl, txq_maperr and blocked_fl.
*/
adap->sge.starving_fl = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz),
sizeof(long), GFP_KERNEL);
@@ -3763,9 +3863,18 @@ static int adap_init0(struct adapter *adap)
goto bye;
}
+#ifdef CONFIG_DEBUG_FS
+ adap->sge.blocked_fl = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz),
+ sizeof(long), GFP_KERNEL);
+ if (!adap->sge.blocked_fl) {
+ ret = -ENOMEM;
+ goto bye;
+ }
+#endif
+
params[0] = FW_PARAM_PFVF(CLIP_START);
params[1] = FW_PARAM_PFVF(CLIP_END);
- ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val);
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, val);
if (ret < 0)
goto bye;
adap->clipt_start = val[0];
@@ -3774,7 +3883,7 @@ static int adap_init0(struct adapter *adap)
/* query params related to active filter region */
params[0] = FW_PARAM_PFVF(ACTIVE_FILTER_START);
params[1] = FW_PARAM_PFVF(ACTIVE_FILTER_END);
- ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val);
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, val);
/* If Active filter size is set we enable establishing
* offload connection through firmware work request
*/
@@ -3791,7 +3900,7 @@ static int adap_init0(struct adapter *adap)
*/
params[0] = FW_PARAM_PFVF(CPLFW4MSG_ENCAP);
val[0] = 1;
- (void) t4_set_params(adap, adap->mbox, adap->fn, 0, 1, params, val);
+ (void)t4_set_params(adap, adap->mbox, adap->pf, 0, 1, params, val);
/*
* Find out whether we're allowed to use the T5+ ULPTX MEMWRITE DSGL
@@ -3803,7 +3912,7 @@ static int adap_init0(struct adapter *adap)
adap->params.ulptx_memwrite_dsgl = false;
} else {
params[0] = FW_PARAM_DEV(ULPTX_MEMWRITE_DSGL);
- ret = t4_query_params(adap, adap->mbox, adap->fn, 0,
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0,
1, params, val);
adap->params.ulptx_memwrite_dsgl = (ret == 0 && val[0] != 0);
}
@@ -3829,7 +3938,7 @@ static int adap_init0(struct adapter *adap)
params[3] = FW_PARAM_PFVF(TDDP_START);
params[4] = FW_PARAM_PFVF(TDDP_END);
params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ);
- ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 6,
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6,
params, val);
if (ret < 0)
goto bye;
@@ -3867,7 +3976,7 @@ static int adap_init0(struct adapter *adap)
params[3] = FW_PARAM_PFVF(RQ_END);
params[4] = FW_PARAM_PFVF(PBL_START);
params[5] = FW_PARAM_PFVF(PBL_END);
- ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 6,
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6,
params, val);
if (ret < 0)
goto bye;
@@ -3884,7 +3993,7 @@ static int adap_init0(struct adapter *adap)
params[3] = FW_PARAM_PFVF(CQ_END);
params[4] = FW_PARAM_PFVF(OCQ_START);
params[5] = FW_PARAM_PFVF(OCQ_END);
- ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 6, params,
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6, params,
val);
if (ret < 0)
goto bye;
@@ -3897,7 +4006,7 @@ static int adap_init0(struct adapter *adap)
params[0] = FW_PARAM_DEV(MAXORDIRD_QP);
params[1] = FW_PARAM_DEV(MAXIRD_ADAPTER);
- ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params,
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params,
val);
if (ret < 0) {
adap->params.max_ordird_qp = 8;
@@ -3915,7 +4024,7 @@ static int adap_init0(struct adapter *adap)
if (caps_cmd.iscsicaps) {
params[0] = FW_PARAM_PFVF(ISCSI_START);
params[1] = FW_PARAM_PFVF(ISCSI_END);
- ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2,
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2,
params, val);
if (ret < 0)
goto bye;
@@ -3961,8 +4070,8 @@ static int adap_init0(struct adapter *adap)
adap->params.b_wnd);
}
t4_init_sge_params(adap);
- t4_init_tp_params(adap);
adap->flags |= FW_OK;
+ t4_init_tp_params(adap);
return 0;
/*
@@ -3975,6 +4084,9 @@ bye:
kfree(adap->sge.ingr_map);
kfree(adap->sge.starving_fl);
kfree(adap->sge.txq_maperr);
+#ifdef CONFIG_DEBUG_FS
+ kfree(adap->sge.blocked_fl);
+#endif
if (ret != -ETIMEDOUT && ret != -EIO)
t4_fw_bye(adap, adap->mbox);
return ret;
@@ -4042,7 +4154,7 @@ static pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev)
if (t4_wait_dev_ready(adap->regs) < 0)
return PCI_ERS_RESULT_DISCONNECT;
- if (t4_fw_hello(adap, adap->fn, adap->fn, MASTER_MUST, NULL) < 0)
+ if (t4_fw_hello(adap, adap->mbox, adap->pf, MASTER_MUST, NULL) < 0)
return PCI_ERS_RESULT_DISCONNECT;
adap->flags |= FW_OK;
if (adap_init1(adap, &c))
@@ -4051,7 +4163,7 @@ static pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev)
for_each_port(adap, i) {
struct port_info *p = adap2pinfo(adap, i);
- ret = t4_alloc_vi(adap, adap->fn, p->tx_chan, adap->fn, 0, 1,
+ ret = t4_alloc_vi(adap, adap->mbox, p->tx_chan, adap->pf, 0, 1,
NULL, NULL);
if (ret < 0)
return PCI_ERS_RESULT_DISCONNECT;
@@ -4342,7 +4454,12 @@ static int enable_msix(struct adapter *adap)
static int init_rss(struct adapter *adap)
{
- unsigned int i, j;
+ unsigned int i;
+ int err;
+
+ err = t4_init_rss_mode(adap, adap->mbox);
+ if (err)
+ return err;
for_each_port(adap, i) {
struct port_info *pi = adap2pinfo(adap, i);
@@ -4350,8 +4467,6 @@ static int init_rss(struct adapter *adap)
pi->rss = kcalloc(pi->rss_size, sizeof(u16), GFP_KERNEL);
if (!pi->rss)
return -ENOMEM;
- for (j = 0; j < pi->rss_size; j++)
- pi->rss[j] = ethtool_rxfh_indir_default(j, pi->nqsets);
}
return 0;
}
@@ -4415,15 +4530,23 @@ static void free_some_resources(struct adapter *adapter)
kfree(adapter->sge.ingr_map);
kfree(adapter->sge.starving_fl);
kfree(adapter->sge.txq_maperr);
+#ifdef CONFIG_DEBUG_FS
+ kfree(adapter->sge.blocked_fl);
+#endif
disable_msi(adapter);
for_each_port(adapter, i)
if (adapter->port[i]) {
+ struct port_info *pi = adap2pinfo(adapter, i);
+
+ if (pi->viid != 0)
+ t4_free_vi(adapter, adapter->mbox, adapter->pf,
+ 0, pi->viid);
kfree(adap2pinfo(adapter, i)->rss);
free_netdev(adapter->port[i]);
}
if (adapter->flags & FW_OK)
- t4_fw_bye(adapter, adapter->fn);
+ t4_fw_bye(adapter, adapter->pf);
}
#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
@@ -4514,7 +4637,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->pdev = pdev;
adapter->pdev_dev = &pdev->dev;
adapter->mbox = func;
- adapter->fn = func;
+ adapter->pf = func;
adapter->msg_enable = dflt_msg_enable;
memset(adapter->chan_map, 0xff, sizeof(adapter->chan_map));
@@ -4534,7 +4657,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!is_t4(adapter->params.chip)) {
s_qpp = (QUEUESPERPAGEPF0_S +
(QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) *
- adapter->fn);
+ adapter->pf);
qpp = 1 << QUEUESPERPAGEPF0_G(t4_read_reg(adapter,
SGE_EGRESS_QUEUES_PER_PAGE_PF_A) >> s_qpp);
num_seg = PAGE_SIZE / SEGMENT_SIZE;
@@ -4557,10 +4680,15 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
err = -ENOMEM;
goto out_free_adapter;
}
+ t4_write_reg(adapter, SGE_STAT_CFG_A,
+ STATSOURCE_T5_V(7) | STATMODE_V(0));
}
setup_memwin(adapter);
err = adap_init0(adapter);
+#ifdef CONFIG_DEBUG_FS
+ bitmap_zero(adapter->sge.blocked_fl, adapter->sge.egr_sz);
+#endif
setup_memwin_rdma(adapter);
if (err)
goto out_unmap_bar;
@@ -4609,10 +4737,25 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
err = t4_port_init(adapter, func, func, 0);
if (err)
goto out_free_dev;
+ } else if (adapter->params.nports == 1) {
+ /* If we don't have a connection to the firmware -- possibly
+ * because of an error -- grab the raw VPD parameters so we
+ * can set the proper MAC Address on the debug network
+ * interface that we've created.
+ */
+ u8 hw_addr[ETH_ALEN];
+ u8 *na = adapter->params.vpd.na;
+
+ err = t4_get_raw_vpd_params(adapter, &adapter->params.vpd);
+ if (!err) {
+ for (i = 0; i < ETH_ALEN; i++)
+ hw_addr[i] = (hex2val(na[2 * i + 0]) * 16 +
+ hex2val(na[2 * i + 1]));
+ t4_set_hw_addr(adapter, 0, hw_addr);
+ }
}
- /*
- * Configure queues and allocate tables now, they can be needed as
+ /* Configure queues and allocate tables now, they can be needed as
* soon as the first register_netdev completes.
*/
cfg_queues(adapter);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
index e33934a6f59e..b27897d4f787 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
@@ -264,6 +264,7 @@ struct cxgb4_lld_info {
unsigned int max_ordird_qp; /* Max ORD/IRD depth per RDMA QP */
unsigned int max_ird_adapter; /* Max IRD memory per adapter */
bool ulptx_memwrite_dsgl; /* use of T5 DSGL allowed */
+ int nodeid; /* device numa node id */
};
struct cxgb4_uld_info {
@@ -297,8 +298,6 @@ struct sk_buff *cxgb4_pktgl_to_skb(const struct pkt_gl *gl,
unsigned int skb_len, unsigned int pull_len);
int cxgb4_sync_txq_pidx(struct net_device *dev, u16 qid, u16 pidx, u16 size);
int cxgb4_flush_eq_cache(struct net_device *dev);
-void cxgb4_disable_db_coalescing(struct net_device *dev);
-void cxgb4_enable_db_coalescing(struct net_device *dev);
int cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte);
u64 cxgb4_read_sge_timestamp(struct net_device *dev);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c
index 1b99aecde736..942db078f33a 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c
@@ -100,16 +100,6 @@
*/
#define TX_QCHECK_PERIOD (HZ / 2)
-/* SGE Hung Ingress DMA Threshold Warning time (in Hz) and Warning Repeat Rate
- * (in RX_QCHECK_PERIOD multiples). If we find one of the SGE Ingress DMA
- * State Machines in the same state for this amount of time (in HZ) then we'll
- * issue a warning about a potential hang. We'll repeat the warning as the
- * SGE Ingress DMA Channel appears to be hung every N RX_QCHECK_PERIODs till
- * the situation clears. If the situation clears, we'll note that as well.
- */
-#define SGE_IDMA_WARN_THRESH (1 * HZ)
-#define SGE_IDMA_WARN_REPEAT (20 * RX_QCHECK_PERIOD)
-
/*
* Max number of Tx descriptors to be reclaimed by the Tx timer.
*/
@@ -532,14 +522,17 @@ static void unmap_rx_buf(struct adapter *adap, struct sge_fl *q)
static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q)
{
- u32 val;
if (q->pend_cred >= 8) {
+ u32 val = adap->params.arch.sge_fl_db;
+
if (is_t4(adap->params.chip))
- val = PIDX_V(q->pend_cred / 8);
+ val |= PIDX_V(q->pend_cred / 8);
else
- val = PIDX_T5_V(q->pend_cred / 8) |
- DBTYPE_F;
- val |= DBPRIO_F;
+ val |= PIDX_T5_V(q->pend_cred / 8);
+
+ /* Make sure all memory writes to the Free List queue are
+ * committed before we tell the hardware about them.
+ */
wmb();
/* If we don't have access to the new User Doorbell (T5+), use
@@ -594,6 +587,11 @@ static unsigned int refill_fl(struct adapter *adap, struct sge_fl *q, int n,
struct rx_sw_desc *sd = &q->sdesc[q->pidx];
int node;
+#ifdef CONFIG_DEBUG_FS
+ if (test_bit(q->cntxt_id - adap->sge.egr_start, adap->sge.blocked_fl))
+ goto out;
+#endif
+
gfp |= __GFP_NOWARN;
node = dev_to_node(adap->pdev_dev);
@@ -930,7 +928,10 @@ static void cxgb_pio_copy(u64 __iomem *dst, u64 *src)
*/
static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
{
- wmb(); /* write descriptors before telling HW */
+ /* Make sure that all writes to the TX Descriptors are committed
+ * before we tell the hardware about them.
+ */
+ wmb();
/* If we don't have access to the new User Doorbell (T5+), use the old
* doorbell mechanism; otherwise use the new BAR2 mechanism.
@@ -1032,7 +1033,7 @@ static void inline_tx_skb(const struct sk_buff *skb, const struct sge_txq *q,
* Figure out what HW csum a packet wants and return the appropriate control
* bits.
*/
-static u64 hwcsum(const struct sk_buff *skb)
+static u64 hwcsum(enum chip_type chip, const struct sk_buff *skb)
{
int csum_type;
const struct iphdr *iph = ip_hdr(skb);
@@ -1047,7 +1048,7 @@ nocsum: /*
* unknown protocol, disable HW csum
* and hope a bad packet is detected
*/
- return TXPKT_L4CSUM_DIS;
+ return TXPKT_L4CSUM_DIS_F;
}
} else {
/*
@@ -1063,15 +1064,21 @@ nocsum: /*
goto nocsum;
}
- if (likely(csum_type >= TX_CSUM_TCPIP))
- return TXPKT_CSUM_TYPE(csum_type) |
- TXPKT_IPHDR_LEN(skb_network_header_len(skb)) |
- TXPKT_ETHHDR_LEN(skb_network_offset(skb) - ETH_HLEN);
- else {
+ if (likely(csum_type >= TX_CSUM_TCPIP)) {
+ u64 hdr_len = TXPKT_IPHDR_LEN_V(skb_network_header_len(skb));
+ int eth_hdr_len = skb_network_offset(skb) - ETH_HLEN;
+
+ if (CHELSIO_CHIP_VERSION(chip) <= CHELSIO_T5)
+ hdr_len |= TXPKT_ETHHDR_LEN_V(eth_hdr_len);
+ else
+ hdr_len |= T6_TXPKT_ETHHDR_LEN_V(eth_hdr_len);
+ return TXPKT_CSUM_TYPE_V(csum_type) | hdr_len;
+ } else {
int start = skb_transport_offset(skb);
- return TXPKT_CSUM_TYPE(csum_type) | TXPKT_CSUM_START(start) |
- TXPKT_CSUM_LOC(start + skb->csum_offset);
+ return TXPKT_CSUM_TYPE_V(csum_type) |
+ TXPKT_CSUM_START_V(start) |
+ TXPKT_CSUM_LOC_V(start + skb->csum_offset);
}
}
@@ -1112,11 +1119,11 @@ cxgb_fcoe_offload(struct sk_buff *skb, struct adapter *adap,
return -ENOTSUPP;
/* FC CRC offload */
- *cntrl = TXPKT_CSUM_TYPE(TX_CSUM_FCOE) |
- TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS |
- TXPKT_CSUM_START(CXGB_FCOE_TXPKT_CSUM_START) |
- TXPKT_CSUM_END(CXGB_FCOE_TXPKT_CSUM_END) |
- TXPKT_CSUM_LOC(CXGB_FCOE_TXPKT_CSUM_END);
+ *cntrl = TXPKT_CSUM_TYPE_V(TX_CSUM_FCOE) |
+ TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F |
+ TXPKT_CSUM_START_V(CXGB_FCOE_TXPKT_CSUM_START) |
+ TXPKT_CSUM_END_V(CXGB_FCOE_TXPKT_CSUM_END) |
+ TXPKT_CSUM_LOC_V(CXGB_FCOE_TXPKT_CSUM_END);
return 0;
}
#endif /* CONFIG_CHELSIO_T4_FCOE */
@@ -1130,7 +1137,6 @@ cxgb_fcoe_offload(struct sk_buff *skb, struct adapter *adap,
*/
netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev)
{
- int len;
u32 wr_mid;
u64 cntrl, *end;
int qidx, credits;
@@ -1143,6 +1149,7 @@ netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev)
const struct skb_shared_info *ssi;
dma_addr_t addr[MAX_SKB_FRAGS + 1];
bool immediate = false;
+ int len, max_pkt_len;
#ifdef CONFIG_CHELSIO_T4_FCOE
int err;
#endif /* CONFIG_CHELSIO_T4_FCOE */
@@ -1156,13 +1163,20 @@ out_free: dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
+ /* Discard the packet if the length is greater than mtu */
+ max_pkt_len = ETH_HLEN + dev->mtu;
+ if (skb_vlan_tag_present(skb))
+ max_pkt_len += VLAN_HLEN;
+ if (!skb_shinfo(skb)->gso_size && (unlikely(skb->len > max_pkt_len)))
+ goto out_free;
+
pi = netdev_priv(dev);
adap = pi->adapter;
qidx = skb_get_queue_mapping(skb);
q = &adap->sge.ethtxq[qidx + pi->first_qset];
reclaim_completed_tx(adap, &q->q, true);
- cntrl = TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS;
+ cntrl = TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F;
#ifdef CONFIG_CHELSIO_T4_FCOE
err = cxgb_fcoe_offload(skb, adap, pi, &cntrl);
@@ -1213,23 +1227,29 @@ out_free: dev_kfree_skb_any(skb);
len += sizeof(*lso);
wr->op_immdlen = htonl(FW_WR_OP_V(FW_ETH_TX_PKT_WR) |
FW_WR_IMMDLEN_V(len));
- lso->c.lso_ctrl = htonl(LSO_OPCODE(CPL_TX_PKT_LSO) |
- LSO_FIRST_SLICE | LSO_LAST_SLICE |
- LSO_IPV6(v6) |
- LSO_ETHHDR_LEN(eth_xtra_len / 4) |
- LSO_IPHDR_LEN(l3hdr_len / 4) |
- LSO_TCPHDR_LEN(tcp_hdr(skb)->doff));
+ lso->c.lso_ctrl = htonl(LSO_OPCODE_V(CPL_TX_PKT_LSO) |
+ LSO_FIRST_SLICE_F | LSO_LAST_SLICE_F |
+ LSO_IPV6_V(v6) |
+ LSO_ETHHDR_LEN_V(eth_xtra_len / 4) |
+ LSO_IPHDR_LEN_V(l3hdr_len / 4) |
+ LSO_TCPHDR_LEN_V(tcp_hdr(skb)->doff));
lso->c.ipid_ofst = htons(0);
lso->c.mss = htons(ssi->gso_size);
lso->c.seqno_offset = htonl(0);
if (is_t4(adap->params.chip))
lso->c.len = htonl(skb->len);
else
- lso->c.len = htonl(LSO_T5_XFER_SIZE(skb->len));
+ lso->c.len = htonl(LSO_T5_XFER_SIZE_V(skb->len));
cpl = (void *)(lso + 1);
- cntrl = TXPKT_CSUM_TYPE(v6 ? TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) |
- TXPKT_IPHDR_LEN(l3hdr_len) |
- TXPKT_ETHHDR_LEN(eth_xtra_len);
+
+ if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5)
+ cntrl = TXPKT_ETHHDR_LEN_V(eth_xtra_len);
+ else
+ cntrl = T6_TXPKT_ETHHDR_LEN_V(eth_xtra_len);
+
+ cntrl |= TXPKT_CSUM_TYPE_V(v6 ?
+ TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) |
+ TXPKT_IPHDR_LEN_V(l3hdr_len);
q->tso++;
q->tx_cso += ssi->gso_segs;
} else {
@@ -1238,23 +1258,25 @@ out_free: dev_kfree_skb_any(skb);
FW_WR_IMMDLEN_V(len));
cpl = (void *)(wr + 1);
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- cntrl = hwcsum(skb) | TXPKT_IPCSUM_DIS;
+ cntrl = hwcsum(adap->params.chip, skb) |
+ TXPKT_IPCSUM_DIS_F;
q->tx_cso++;
}
}
if (skb_vlan_tag_present(skb)) {
q->vlan_ins++;
- cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(skb_vlan_tag_get(skb));
+ cntrl |= TXPKT_VLAN_VLD_F | TXPKT_VLAN_V(skb_vlan_tag_get(skb));
#ifdef CONFIG_CHELSIO_T4_FCOE
if (skb->protocol == htons(ETH_P_FCOE))
- cntrl |= TXPKT_VLAN(
+ cntrl |= TXPKT_VLAN_V(
((skb->priority & 0x7) << VLAN_PRIO_SHIFT));
#endif /* CONFIG_CHELSIO_T4_FCOE */
}
- cpl->ctrl0 = htonl(TXPKT_OPCODE(CPL_TX_PKT_XT) |
- TXPKT_INTF(pi->tx_chan) | TXPKT_PF(adap->fn));
+ cpl->ctrl0 = htonl(TXPKT_OPCODE_V(CPL_TX_PKT_XT) |
+ TXPKT_INTF_V(pi->tx_chan) |
+ TXPKT_PF_V(adap->pf));
cpl->pack = htons(0);
cpl->len = htons(skb->len);
cpl->ctrl1 = cpu_to_be64(cntrl);
@@ -1964,7 +1986,7 @@ static void restore_rx_bufs(const struct pkt_gl *si, struct sge_fl *q,
static inline bool is_new_response(const struct rsp_ctrl *r,
const struct sge_rspq *q)
{
- return RSPD_GEN(r->type_gen) == q->gen;
+ return (r->type_gen >> RSPD_GEN_S) == q->gen;
}
/**
@@ -2011,19 +2033,19 @@ static int process_responses(struct sge_rspq *q, int budget)
break;
dma_rmb();
- rsp_type = RSPD_TYPE(rc->type_gen);
- if (likely(rsp_type == RSP_TYPE_FLBUF)) {
+ rsp_type = RSPD_TYPE_G(rc->type_gen);
+ if (likely(rsp_type == RSPD_TYPE_FLBUF_X)) {
struct page_frag *fp;
struct pkt_gl si;
const struct rx_sw_desc *rsd;
u32 len = ntohl(rc->pldbuflen_qid), bufsz, frags;
- if (len & RSPD_NEWBUF) {
+ if (len & RSPD_NEWBUF_F) {
if (likely(q->offset > 0)) {
free_rx_bufs(q->adap, &rxq->fl, 1);
q->offset = 0;
}
- len = RSPD_LEN(len);
+ len = RSPD_LEN_G(len);
}
si.tot_len = len;
@@ -2058,7 +2080,7 @@ static int process_responses(struct sge_rspq *q, int budget)
q->offset += ALIGN(fp->size, s->fl_align);
else
restore_rx_bufs(&si, &rxq->fl, frags);
- } else if (likely(rsp_type == RSP_TYPE_CPL)) {
+ } else if (likely(rsp_type == RSPD_TYPE_CPL_X)) {
ret = q->handler(q, q->cur_desc, NULL);
} else {
ret = q->handler(q, (const __be64 *)rc, CXGB4_MSG_AN);
@@ -2066,7 +2088,7 @@ static int process_responses(struct sge_rspq *q, int budget)
if (unlikely(ret)) {
/* couldn't process descriptor, back off for recovery */
- q->next_intr_params = QINTR_TIMER_IDX(NOMEM_TMR_IDX);
+ q->next_intr_params = QINTR_TIMER_IDX_V(NOMEM_TMR_IDX);
break;
}
@@ -2090,7 +2112,7 @@ int cxgb_busy_poll(struct napi_struct *napi)
return LL_FLUSH_BUSY;
work_done = process_responses(q, 4);
- params = QINTR_TIMER_IDX(TIMERREG_COUNTER0_X) | QINTR_CNT_EN;
+ params = QINTR_TIMER_IDX_V(TIMERREG_COUNTER0_X) | QINTR_CNT_EN_V(1);
q->next_intr_params = params;
val = CIDXINC_V(work_done) | SEINTARM_V(params);
@@ -2137,7 +2159,7 @@ static int napi_rx_handler(struct napi_struct *napi, int budget)
int timer_index;
napi_complete(napi);
- timer_index = QINTR_TIMER_IDX_GET(q->next_intr_params);
+ timer_index = QINTR_TIMER_IDX_G(q->next_intr_params);
if (q->adaptive_rx) {
if (work_done > max(timer_pkt_quota[timer_index],
@@ -2147,15 +2169,16 @@ static int napi_rx_handler(struct napi_struct *napi, int budget)
timer_index = timer_index - 1;
timer_index = clamp(timer_index, 0, SGE_TIMERREGS - 1);
- q->next_intr_params = QINTR_TIMER_IDX(timer_index) |
- V_QINTR_CNT_EN;
+ q->next_intr_params =
+ QINTR_TIMER_IDX_V(timer_index) |
+ QINTR_CNT_EN_V(0);
params = q->next_intr_params;
} else {
params = q->next_intr_params;
q->next_intr_params = q->intr_params;
}
} else
- params = QINTR_TIMER_IDX(7);
+ params = QINTR_TIMER_IDX_V(7);
val = CIDXINC_V(work_done) | SEINTARM_V(params);
@@ -2203,7 +2226,7 @@ static unsigned int process_intrq(struct adapter *adap)
break;
dma_rmb();
- if (RSPD_TYPE(rc->type_gen) == RSP_TYPE_INTR) {
+ if (RSPD_TYPE_G(rc->type_gen) == RSPD_TYPE_INTR_X) {
unsigned int qid = ntohl(rc->pldbuflen_qid);
qid -= adap->sge.ingr_start;
@@ -2279,7 +2302,7 @@ irq_handler_t t4_intr_handler(struct adapter *adap)
static void sge_rx_timer_cb(unsigned long data)
{
unsigned long m;
- unsigned int i, idma_same_state_cnt[2];
+ unsigned int i;
struct adapter *adap = (struct adapter *)data;
struct sge *s = &adap->sge;
@@ -2300,67 +2323,16 @@ static void sge_rx_timer_cb(unsigned long data)
set_bit(id, s->starving_fl);
}
}
+ /* The remainder of the SGE RX Timer Callback routine is dedicated to
+ * global Master PF activities like checking for chip ingress stalls,
+ * etc.
+ */
+ if (!(adap->flags & MASTER_PF))
+ goto done;
- t4_write_reg(adap, SGE_DEBUG_INDEX_A, 13);
- idma_same_state_cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH_A);
- idma_same_state_cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW_A);
-
- for (i = 0; i < 2; i++) {
- u32 debug0, debug11;
-
- /* If the Ingress DMA Same State Counter ("timer") is less
- * than 1s, then we can reset our synthesized Stall Timer and
- * continue. If we have previously emitted warnings about a
- * potential stalled Ingress Queue, issue a note indicating
- * that the Ingress Queue has resumed forward progress.
- */
- if (idma_same_state_cnt[i] < s->idma_1s_thresh) {
- if (s->idma_stalled[i] >= SGE_IDMA_WARN_THRESH)
- CH_WARN(adap, "SGE idma%d, queue%u,resumed after %d sec\n",
- i, s->idma_qid[i],
- s->idma_stalled[i]/HZ);
- s->idma_stalled[i] = 0;
- continue;
- }
-
- /* Synthesize an SGE Ingress DMA Same State Timer in the Hz
- * domain. The first time we get here it'll be because we
- * passed the 1s Threshold; each additional time it'll be
- * because the RX Timer Callback is being fired on its regular
- * schedule.
- *
- * If the stall is below our Potential Hung Ingress Queue
- * Warning Threshold, continue.
- */
- if (s->idma_stalled[i] == 0)
- s->idma_stalled[i] = HZ;
- else
- s->idma_stalled[i] += RX_QCHECK_PERIOD;
-
- if (s->idma_stalled[i] < SGE_IDMA_WARN_THRESH)
- continue;
-
- /* We'll issue a warning every SGE_IDMA_WARN_REPEAT Hz */
- if (((s->idma_stalled[i] - HZ) % SGE_IDMA_WARN_REPEAT) != 0)
- continue;
-
- /* Read and save the SGE IDMA State and Queue ID information.
- * We do this every time in case it changes across time ...
- */
- t4_write_reg(adap, SGE_DEBUG_INDEX_A, 0);
- debug0 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW_A);
- s->idma_state[i] = (debug0 >> (i * 9)) & 0x3f;
-
- t4_write_reg(adap, SGE_DEBUG_INDEX_A, 11);
- debug11 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW_A);
- s->idma_qid[i] = (debug11 >> (i * 16)) & 0xffff;
-
- CH_WARN(adap, "SGE idma%u, queue%u, maybe stuck state%u %dsecs (debug0=%#x, debug11=%#x)\n",
- i, s->idma_qid[i], s->idma_state[i],
- s->idma_stalled[i]/HZ, debug0, debug11);
- t4_sge_decode_idma_state(adap, s->idma_state[i]);
- }
+ t4_idma_monitor(adap, &s->idma_monitor, HZ, RX_QCHECK_PERIOD);
+done:
mod_timer(&s->rx_timer, jiffies + RX_QCHECK_PERIOD);
}
@@ -2429,17 +2401,20 @@ static void __iomem *bar2_address(struct adapter *adapter,
u64 bar2_qoffset;
int ret;
- ret = cxgb4_t4_bar2_sge_qregs(adapter, qid, qtype, 0,
- &bar2_qoffset, pbar2_qid);
+ ret = t4_bar2_sge_qregs(adapter, qid, qtype, 0,
+ &bar2_qoffset, pbar2_qid);
if (ret)
return NULL;
return adapter->bar2 + bar2_qoffset;
}
+/* @intr_idx: MSI/MSI-X vector if >=0, -(absolute qid + 1) if < 0
+ * @cong: < 0 -> no congestion feedback, >= 0 -> congestion channel map
+ */
int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
struct net_device *dev, int intr_idx,
- struct sge_fl *fl, rspq_handler_t hnd)
+ struct sge_fl *fl, rspq_handler_t hnd, int cong)
{
int ret, flsz = 0;
struct fw_iq_cmd c;
@@ -2457,12 +2432,13 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
memset(&c, 0, sizeof(c));
c.op_to_vfn = htonl(FW_CMD_OP_V(FW_IQ_CMD) | FW_CMD_REQUEST_F |
FW_CMD_WRITE_F | FW_CMD_EXEC_F |
- FW_IQ_CMD_PFN_V(adap->fn) | FW_IQ_CMD_VFN_V(0));
+ FW_IQ_CMD_PFN_V(adap->pf) | FW_IQ_CMD_VFN_V(0));
c.alloc_to_len16 = htonl(FW_IQ_CMD_ALLOC_F | FW_IQ_CMD_IQSTART_F |
FW_LEN16(c));
c.type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE_V(FW_IQ_TYPE_FL_INT_CAP) |
FW_IQ_CMD_IQASYNCH_V(fwevtq) | FW_IQ_CMD_VIID_V(pi->viid) |
- FW_IQ_CMD_IQANDST_V(intr_idx < 0) | FW_IQ_CMD_IQANUD_V(1) |
+ FW_IQ_CMD_IQANDST_V(intr_idx < 0) |
+ FW_IQ_CMD_IQANUD_V(UPDATEDELIVERY_INTERRUPT_X) |
FW_IQ_CMD_IQANDSTINDEX_V(intr_idx >= 0 ? intr_idx :
-intr_idx - 1));
c.iqdroprss_to_iqesize = htons(FW_IQ_CMD_IQPCIECH_V(pi->tx_chan) |
@@ -2471,8 +2447,21 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
FW_IQ_CMD_IQESIZE_V(ilog2(iq->iqe_len) - 4));
c.iqsize = htons(iq->size);
c.iqaddr = cpu_to_be64(iq->phys_addr);
+ if (cong >= 0)
+ c.iqns_to_fl0congen = htonl(FW_IQ_CMD_IQFLINTCONGEN_F);
if (fl) {
+ enum chip_type chip = CHELSIO_CHIP_VERSION(adap->params.chip);
+
+ /* Allocate the ring for the hardware free list (with space
+ * for its status page) along with the associated software
+ * descriptor ring. The free list size needs to be a multiple
+ * of the Egress Queue Unit and at least 2 Egress Units larger
+ * than the SGE's Egress Congrestion Threshold
+ * (fl_starve_thres - 1).
+ */
+ if (fl->size < s->fl_starve_thres - 1 + 2 * 8)
+ fl->size = s->fl_starve_thres - 1 + 2 * 8;
fl->size = roundup(fl->size, 8);
fl->desc = alloc_ring(adap->pdev_dev, fl->size, sizeof(__be64),
sizeof(struct rx_sw_desc), &fl->addr,
@@ -2481,17 +2470,25 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
goto fl_nomem;
flsz = fl->size / 8 + s->stat_len / sizeof(struct tx_desc);
- c.iqns_to_fl0congen = htonl(FW_IQ_CMD_FL0PACKEN_F |
- FW_IQ_CMD_FL0FETCHRO_F |
- FW_IQ_CMD_FL0DATARO_F |
- FW_IQ_CMD_FL0PADEN_F);
- c.fl0dcaen_to_fl0cidxfthresh = htons(FW_IQ_CMD_FL0FBMIN_V(2) |
- FW_IQ_CMD_FL0FBMAX_V(3));
+ c.iqns_to_fl0congen |= htonl(FW_IQ_CMD_FL0PACKEN_F |
+ FW_IQ_CMD_FL0FETCHRO_F |
+ FW_IQ_CMD_FL0DATARO_F |
+ FW_IQ_CMD_FL0PADEN_F);
+ if (cong >= 0)
+ c.iqns_to_fl0congen |=
+ htonl(FW_IQ_CMD_FL0CNGCHMAP_V(cong) |
+ FW_IQ_CMD_FL0CONGCIF_F |
+ FW_IQ_CMD_FL0CONGEN_F);
+ c.fl0dcaen_to_fl0cidxfthresh =
+ htons(FW_IQ_CMD_FL0FBMIN_V(FETCHBURSTMIN_64B_X) |
+ FW_IQ_CMD_FL0FBMAX_V((chip <= CHELSIO_T5) ?
+ FETCHBURSTMAX_512B_X :
+ FETCHBURSTMAX_256B_X));
c.fl0size = htons(flsz);
c.fl0addr = cpu_to_be64(fl->addr);
}
- ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c);
+ ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c);
if (ret)
goto err;
@@ -2532,6 +2529,41 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
&fl->bar2_qid);
refill_fl(adap, fl, fl_cap(fl), GFP_KERNEL);
}
+
+ /* For T5 and later we attempt to set up the Congestion Manager values
+ * of the new RX Ethernet Queue. This should really be handled by
+ * firmware because it's more complex than any host driver wants to
+ * get involved with and it's different per chip and this is almost
+ * certainly wrong. Firmware would be wrong as well, but it would be
+ * a lot easier to fix in one place ... For now we do something very
+ * simple (and hopefully less wrong).
+ */
+ if (!is_t4(adap->params.chip) && cong >= 0) {
+ u32 param, val;
+ int i;
+
+ param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) |
+ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DMAQ_CONM_CTXT) |
+ FW_PARAMS_PARAM_YZ_V(iq->cntxt_id));
+ if (cong == 0) {
+ val = CONMCTXT_CNGTPMODE_V(CONMCTXT_CNGTPMODE_QUEUE_X);
+ } else {
+ val =
+ CONMCTXT_CNGTPMODE_V(CONMCTXT_CNGTPMODE_CHANNEL_X);
+ for (i = 0; i < 4; i++) {
+ if (cong & (1 << i))
+ val |=
+ CONMCTXT_CNGCHMAP_V(1 << (i << 2));
+ }
+ }
+ ret = t4_set_params(adap, adap->mbox, adap->pf, 0, 1,
+ &param, &val);
+ if (ret)
+ dev_warn(adap->pdev_dev, "Failed to set Congestion"
+ " Manager Context for Ingress Queue %d: %d\n",
+ iq->cntxt_id, -ret);
+ }
+
return 0;
fl_nomem:
@@ -2589,23 +2621,24 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
memset(&c, 0, sizeof(c));
c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_ETH_CMD) | FW_CMD_REQUEST_F |
FW_CMD_WRITE_F | FW_CMD_EXEC_F |
- FW_EQ_ETH_CMD_PFN_V(adap->fn) |
+ FW_EQ_ETH_CMD_PFN_V(adap->pf) |
FW_EQ_ETH_CMD_VFN_V(0));
c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_ALLOC_F |
FW_EQ_ETH_CMD_EQSTART_F | FW_LEN16(c));
c.viid_pkd = htonl(FW_EQ_ETH_CMD_AUTOEQUEQE_F |
FW_EQ_ETH_CMD_VIID_V(pi->viid));
- c.fetchszm_to_iqid = htonl(FW_EQ_ETH_CMD_HOSTFCMODE_V(2) |
- FW_EQ_ETH_CMD_PCIECHN_V(pi->tx_chan) |
- FW_EQ_ETH_CMD_FETCHRO_V(1) |
- FW_EQ_ETH_CMD_IQID_V(iqid));
- c.dcaen_to_eqsize = htonl(FW_EQ_ETH_CMD_FBMIN_V(2) |
- FW_EQ_ETH_CMD_FBMAX_V(3) |
- FW_EQ_ETH_CMD_CIDXFTHRESH_V(5) |
- FW_EQ_ETH_CMD_EQSIZE_V(nentries));
+ c.fetchszm_to_iqid =
+ htonl(FW_EQ_ETH_CMD_HOSTFCMODE_V(HOSTFCMODE_STATUS_PAGE_X) |
+ FW_EQ_ETH_CMD_PCIECHN_V(pi->tx_chan) |
+ FW_EQ_ETH_CMD_FETCHRO_F | FW_EQ_ETH_CMD_IQID_V(iqid));
+ c.dcaen_to_eqsize =
+ htonl(FW_EQ_ETH_CMD_FBMIN_V(FETCHBURSTMIN_64B_X) |
+ FW_EQ_ETH_CMD_FBMAX_V(FETCHBURSTMAX_512B_X) |
+ FW_EQ_ETH_CMD_CIDXFTHRESH_V(CIDXFLUSHTHRESH_32_X) |
+ FW_EQ_ETH_CMD_EQSIZE_V(nentries));
c.eqaddr = cpu_to_be64(txq->q.phys_addr);
- ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c);
+ ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c);
if (ret) {
kfree(txq->q.sdesc);
txq->q.sdesc = NULL;
@@ -2637,29 +2670,30 @@ int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq,
txq->q.desc = alloc_ring(adap->pdev_dev, nentries,
sizeof(struct tx_desc), 0, &txq->q.phys_addr,
- NULL, 0, NUMA_NO_NODE);
+ NULL, 0, dev_to_node(adap->pdev_dev));
if (!txq->q.desc)
return -ENOMEM;
c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST_F |
FW_CMD_WRITE_F | FW_CMD_EXEC_F |
- FW_EQ_CTRL_CMD_PFN_V(adap->fn) |
+ FW_EQ_CTRL_CMD_PFN_V(adap->pf) |
FW_EQ_CTRL_CMD_VFN_V(0));
c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_ALLOC_F |
FW_EQ_CTRL_CMD_EQSTART_F | FW_LEN16(c));
c.cmpliqid_eqid = htonl(FW_EQ_CTRL_CMD_CMPLIQID_V(cmplqid));
c.physeqid_pkd = htonl(0);
- c.fetchszm_to_iqid = htonl(FW_EQ_CTRL_CMD_HOSTFCMODE_V(2) |
- FW_EQ_CTRL_CMD_PCIECHN_V(pi->tx_chan) |
- FW_EQ_CTRL_CMD_FETCHRO_F |
- FW_EQ_CTRL_CMD_IQID_V(iqid));
- c.dcaen_to_eqsize = htonl(FW_EQ_CTRL_CMD_FBMIN_V(2) |
- FW_EQ_CTRL_CMD_FBMAX_V(3) |
- FW_EQ_CTRL_CMD_CIDXFTHRESH_V(5) |
- FW_EQ_CTRL_CMD_EQSIZE_V(nentries));
+ c.fetchszm_to_iqid =
+ htonl(FW_EQ_CTRL_CMD_HOSTFCMODE_V(HOSTFCMODE_STATUS_PAGE_X) |
+ FW_EQ_CTRL_CMD_PCIECHN_V(pi->tx_chan) |
+ FW_EQ_CTRL_CMD_FETCHRO_F | FW_EQ_CTRL_CMD_IQID_V(iqid));
+ c.dcaen_to_eqsize =
+ htonl(FW_EQ_CTRL_CMD_FBMIN_V(FETCHBURSTMIN_64B_X) |
+ FW_EQ_CTRL_CMD_FBMAX_V(FETCHBURSTMAX_512B_X) |
+ FW_EQ_CTRL_CMD_CIDXFTHRESH_V(CIDXFLUSHTHRESH_32_X) |
+ FW_EQ_CTRL_CMD_EQSIZE_V(nentries));
c.eqaddr = cpu_to_be64(txq->q.phys_addr);
- ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c);
+ ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c);
if (ret) {
dma_free_coherent(adap->pdev_dev,
nentries * sizeof(struct tx_desc),
@@ -2697,21 +2731,22 @@ int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
memset(&c, 0, sizeof(c));
c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST_F |
FW_CMD_WRITE_F | FW_CMD_EXEC_F |
- FW_EQ_OFLD_CMD_PFN_V(adap->fn) |
+ FW_EQ_OFLD_CMD_PFN_V(adap->pf) |
FW_EQ_OFLD_CMD_VFN_V(0));
c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_ALLOC_F |
FW_EQ_OFLD_CMD_EQSTART_F | FW_LEN16(c));
- c.fetchszm_to_iqid = htonl(FW_EQ_OFLD_CMD_HOSTFCMODE_V(2) |
- FW_EQ_OFLD_CMD_PCIECHN_V(pi->tx_chan) |
- FW_EQ_OFLD_CMD_FETCHRO_F |
- FW_EQ_OFLD_CMD_IQID_V(iqid));
- c.dcaen_to_eqsize = htonl(FW_EQ_OFLD_CMD_FBMIN_V(2) |
- FW_EQ_OFLD_CMD_FBMAX_V(3) |
- FW_EQ_OFLD_CMD_CIDXFTHRESH_V(5) |
- FW_EQ_OFLD_CMD_EQSIZE_V(nentries));
+ c.fetchszm_to_iqid =
+ htonl(FW_EQ_OFLD_CMD_HOSTFCMODE_V(HOSTFCMODE_STATUS_PAGE_X) |
+ FW_EQ_OFLD_CMD_PCIECHN_V(pi->tx_chan) |
+ FW_EQ_OFLD_CMD_FETCHRO_F | FW_EQ_OFLD_CMD_IQID_V(iqid));
+ c.dcaen_to_eqsize =
+ htonl(FW_EQ_OFLD_CMD_FBMIN_V(FETCHBURSTMIN_64B_X) |
+ FW_EQ_OFLD_CMD_FBMAX_V(FETCHBURSTMAX_512B_X) |
+ FW_EQ_OFLD_CMD_CIDXFTHRESH_V(CIDXFLUSHTHRESH_32_X) |
+ FW_EQ_OFLD_CMD_EQSIZE_V(nentries));
c.eqaddr = cpu_to_be64(txq->q.phys_addr);
- ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c);
+ ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c);
if (ret) {
kfree(txq->q.sdesc);
txq->q.sdesc = NULL;
@@ -2750,7 +2785,7 @@ static void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq,
unsigned int fl_id = fl ? fl->cntxt_id : 0xffff;
adap->sge.ingr_map[rq->cntxt_id - adap->sge.ingr_start] = NULL;
- t4_iq_free(adap, adap->fn, adap->fn, 0, FW_IQ_TYPE_FL_INT_CAP,
+ t4_iq_free(adap, adap->mbox, adap->pf, 0, FW_IQ_TYPE_FL_INT_CAP,
rq->cntxt_id, fl_id, 0xffff);
dma_free_coherent(adap->pdev_dev, (rq->size + 1) * rq->iqe_len,
rq->desc, rq->phys_addr);
@@ -2805,7 +2840,7 @@ void t4_free_sge_resources(struct adapter *adap)
free_rspq_fl(adap, &eq->rspq,
eq->fl.size ? &eq->fl : NULL);
if (etq->q.desc) {
- t4_eth_eq_free(adap, adap->fn, adap->fn, 0,
+ t4_eth_eq_free(adap, adap->mbox, adap->pf, 0,
etq->q.cntxt_id);
free_tx_desc(adap, &etq->q, etq->q.in_use, true);
kfree(etq->q.sdesc);
@@ -2824,7 +2859,7 @@ void t4_free_sge_resources(struct adapter *adap)
if (q->q.desc) {
tasklet_kill(&q->qresume_tsk);
- t4_ofld_eq_free(adap, adap->fn, adap->fn, 0,
+ t4_ofld_eq_free(adap, adap->mbox, adap->pf, 0,
q->q.cntxt_id);
free_tx_desc(adap, &q->q, q->q.in_use, false);
kfree(q->q.sdesc);
@@ -2839,7 +2874,7 @@ void t4_free_sge_resources(struct adapter *adap)
if (cq->q.desc) {
tasklet_kill(&cq->qresume_tsk);
- t4_ctrl_eq_free(adap, adap->fn, adap->fn, 0,
+ t4_ctrl_eq_free(adap, adap->mbox, adap->pf, 0,
cq->q.cntxt_id);
__skb_queue_purge(&cq->sendq);
free_txq(adap, &cq->q);
@@ -3023,7 +3058,11 @@ int t4_sge_init(struct adapter *adap)
* Packing Boundary. T5 introduced the ability to specify these
* separately. The actual Ingress Packet Data alignment boundary
* within Packed Buffer Mode is the maximum of these two
- * specifications.
+ * specifications. (Note that it makes no real practical sense to
+ * have the Pading Boudary be larger than the Packing Boundary but you
+ * could set the chip up that way and, in fact, legacy T4 code would
+ * end doing this because it would initialize the Padding Boundary and
+ * leave the Packing Boundary initialized to 0 (16 bytes).)
*/
ingpadboundary = 1 << (INGPADBOUNDARY_G(sge_control) +
INGPADBOUNDARY_SHIFT_X);
@@ -3067,11 +3106,14 @@ int t4_sge_init(struct adapter *adap)
egress_threshold = EGRTHRESHOLDPACKING_G(sge_conm_ctrl);
s->fl_starve_thres = 2*egress_threshold + 1;
+ t4_idma_monitor_init(adap, &s->idma_monitor);
+
+ /* Set up timers used for recuring callbacks to process RX and TX
+ * administrative tasks.
+ */
setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adap);
setup_timer(&s->tx_timer, sge_tx_timer_cb, (unsigned long)adap);
- s->idma_1s_thresh = core_ticks_per_usec(adap) * 1000000; /* 1 s */
- s->idma_stalled[0] = 0;
- s->idma_stalled[1] = 0;
+
spin_lock_init(&s->intrq_lock);
return 0;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index 61d8b3ec959e..2b52aae7ec86 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -150,7 +150,12 @@ void t4_write_indirect(struct adapter *adap, unsigned int addr_reg,
*/
void t4_hw_pci_read_cfg4(struct adapter *adap, int reg, u32 *val)
{
- u32 req = ENABLE_F | FUNCTION_V(adap->fn) | REGISTER_V(reg);
+ u32 req = FUNCTION_V(adap->pf) | REGISTER_V(reg);
+
+ if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5)
+ req |= ENABLE_F;
+ else
+ req |= T6_ENABLE_F;
if (is_t4(adap->params.chip))
req |= LOCALCFG_F;
@@ -214,8 +219,8 @@ static void fw_asrt(struct adapter *adap, u32 mbox_addr)
get_mbox_rpl(adap, (__be64 *)&asrt, sizeof(asrt) / 8, mbox_addr);
dev_alert(adap->pdev_dev,
"FW assertion at %.16s:%u, val0 %#x, val1 %#x\n",
- asrt.u.assert.filename_0_7, ntohl(asrt.u.assert.line),
- ntohl(asrt.u.assert.x), ntohl(asrt.u.assert.y));
+ asrt.u.assert.filename_0_7, be32_to_cpu(asrt.u.assert.line),
+ be32_to_cpu(asrt.u.assert.x), be32_to_cpu(asrt.u.assert.y));
}
static void dump_mbox(struct adapter *adap, int mbox, u32 data_reg)
@@ -233,13 +238,14 @@ static void dump_mbox(struct adapter *adap, int mbox, u32 data_reg)
}
/**
- * t4_wr_mbox_meat - send a command to FW through the given mailbox
+ * t4_wr_mbox_meat_timeout - send a command to FW through the given mailbox
* @adap: the adapter
* @mbox: index of the mailbox to use
* @cmd: the command to write
* @size: command length in bytes
* @rpl: where to optionally store the reply
* @sleep_ok: if true we may sleep while awaiting command completion
+ * @timeout: time to wait for command to finish before timing out
*
* Sends the given command to FW through the selected mailbox and waits
* for the FW to execute the command. If @rpl is not %NULL it is used to
@@ -254,8 +260,8 @@ static void dump_mbox(struct adapter *adap, int mbox, u32 data_reg)
* command or FW executes it but signals an error. In the latter case
* the return value is the error code indicated by FW (negated).
*/
-int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
- void *rpl, bool sleep_ok)
+int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox, const void *cmd,
+ int size, void *rpl, bool sleep_ok, int timeout)
{
static const int delay[] = {
1, 1, 3, 5, 10, 10, 20, 50, 100, 200
@@ -294,7 +300,7 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
delay_idx = 0;
ms = delay[0];
- for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) {
+ for (i = 0; i < timeout; i += ms) {
if (sleep_ok) {
ms = delay[delay_idx]; /* last element may repeat */
if (delay_idx < ARRAY_SIZE(delay) - 1)
@@ -332,114 +338,11 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
return -ETIMEDOUT;
}
-/**
- * t4_mc_read - read from MC through backdoor accesses
- * @adap: the adapter
- * @addr: address of first byte requested
- * @idx: which MC to access
- * @data: 64 bytes of data containing the requested address
- * @ecc: where to store the corresponding 64-bit ECC word
- *
- * Read 64 bytes of data from MC starting at a 64-byte-aligned address
- * that covers the requested address @addr. If @parity is not %NULL it
- * is assigned the 64-bit ECC word for the read data.
- */
-int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
-{
- int i;
- u32 mc_bist_cmd, mc_bist_cmd_addr, mc_bist_cmd_len;
- u32 mc_bist_status_rdata, mc_bist_data_pattern;
-
- if (is_t4(adap->params.chip)) {
- mc_bist_cmd = MC_BIST_CMD_A;
- mc_bist_cmd_addr = MC_BIST_CMD_ADDR_A;
- mc_bist_cmd_len = MC_BIST_CMD_LEN_A;
- mc_bist_status_rdata = MC_BIST_STATUS_RDATA_A;
- mc_bist_data_pattern = MC_BIST_DATA_PATTERN_A;
- } else {
- mc_bist_cmd = MC_REG(MC_P_BIST_CMD_A, idx);
- mc_bist_cmd_addr = MC_REG(MC_P_BIST_CMD_ADDR_A, idx);
- mc_bist_cmd_len = MC_REG(MC_P_BIST_CMD_LEN_A, idx);
- mc_bist_status_rdata = MC_REG(MC_P_BIST_STATUS_RDATA_A, idx);
- mc_bist_data_pattern = MC_REG(MC_P_BIST_DATA_PATTERN_A, idx);
- }
-
- if (t4_read_reg(adap, mc_bist_cmd) & START_BIST_F)
- return -EBUSY;
- t4_write_reg(adap, mc_bist_cmd_addr, addr & ~0x3fU);
- t4_write_reg(adap, mc_bist_cmd_len, 64);
- t4_write_reg(adap, mc_bist_data_pattern, 0xc);
- t4_write_reg(adap, mc_bist_cmd, BIST_OPCODE_V(1) | START_BIST_F |
- BIST_CMD_GAP_V(1));
- i = t4_wait_op_done(adap, mc_bist_cmd, START_BIST_F, 0, 10, 1);
- if (i)
- return i;
-
-#define MC_DATA(i) MC_BIST_STATUS_REG(mc_bist_status_rdata, i)
-
- for (i = 15; i >= 0; i--)
- *data++ = htonl(t4_read_reg(adap, MC_DATA(i)));
- if (ecc)
- *ecc = t4_read_reg64(adap, MC_DATA(16));
-#undef MC_DATA
- return 0;
-}
-
-/**
- * t4_edc_read - read from EDC through backdoor accesses
- * @adap: the adapter
- * @idx: which EDC to access
- * @addr: address of first byte requested
- * @data: 64 bytes of data containing the requested address
- * @ecc: where to store the corresponding 64-bit ECC word
- *
- * Read 64 bytes of data from EDC starting at a 64-byte-aligned address
- * that covers the requested address @addr. If @parity is not %NULL it
- * is assigned the 64-bit ECC word for the read data.
- */
-int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
+int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
+ void *rpl, bool sleep_ok)
{
- int i;
- u32 edc_bist_cmd, edc_bist_cmd_addr, edc_bist_cmd_len;
- u32 edc_bist_cmd_data_pattern, edc_bist_status_rdata;
-
- if (is_t4(adap->params.chip)) {
- edc_bist_cmd = EDC_REG(EDC_BIST_CMD_A, idx);
- edc_bist_cmd_addr = EDC_REG(EDC_BIST_CMD_ADDR_A, idx);
- edc_bist_cmd_len = EDC_REG(EDC_BIST_CMD_LEN_A, idx);
- edc_bist_cmd_data_pattern = EDC_REG(EDC_BIST_DATA_PATTERN_A,
- idx);
- edc_bist_status_rdata = EDC_REG(EDC_BIST_STATUS_RDATA_A,
- idx);
- } else {
- edc_bist_cmd = EDC_REG_T5(EDC_H_BIST_CMD_A, idx);
- edc_bist_cmd_addr = EDC_REG_T5(EDC_H_BIST_CMD_ADDR_A, idx);
- edc_bist_cmd_len = EDC_REG_T5(EDC_H_BIST_CMD_LEN_A, idx);
- edc_bist_cmd_data_pattern =
- EDC_REG_T5(EDC_H_BIST_DATA_PATTERN_A, idx);
- edc_bist_status_rdata =
- EDC_REG_T5(EDC_H_BIST_STATUS_RDATA_A, idx);
- }
-
- if (t4_read_reg(adap, edc_bist_cmd) & START_BIST_F)
- return -EBUSY;
- t4_write_reg(adap, edc_bist_cmd_addr, addr & ~0x3fU);
- t4_write_reg(adap, edc_bist_cmd_len, 64);
- t4_write_reg(adap, edc_bist_cmd_data_pattern, 0xc);
- t4_write_reg(adap, edc_bist_cmd,
- BIST_OPCODE_V(1) | BIST_CMD_GAP_V(1) | START_BIST_F);
- i = t4_wait_op_done(adap, edc_bist_cmd, START_BIST_F, 0, 10, 1);
- if (i)
- return i;
-
-#define EDC_DATA(i) (EDC_BIST_STATUS_REG(edc_bist_status_rdata, i))
-
- for (i = 15; i >= 0; i--)
- *data++ = htonl(t4_read_reg(adap, EDC_DATA(i)));
- if (ecc)
- *ecc = t4_read_reg64(adap, EDC_DATA(16));
-#undef EDC_DATA
- return 0;
+ return t4_wr_mbox_meat_timeout(adap, mbox, cmd, size, rpl, sleep_ok,
+ FW_CMD_MAX_TIMEOUT);
}
/**
@@ -483,9 +386,8 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
/* Offset into the region of memory which is being accessed
* MEM_EDC0 = 0
* MEM_EDC1 = 1
- * MEM_MC = 2 -- T4
- * MEM_MC0 = 2 -- For T5
- * MEM_MC1 = 3 -- For T5
+ * MEM_MC = 2 -- MEM_MC for chips with only 1 memory controller
+ * MEM_MC1 = 3 -- for chips with 2 memory controllers (e.g. T5)
*/
edc_size = EDRAM0_SIZE_G(t4_read_reg(adap, MA_EDRAM0_BAR_A));
if (mtype != MEM_MC1)
@@ -514,7 +416,7 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
mem_base = PCIEOFST_G(mem_reg) << PCIEOFST_SHIFT_X;
if (is_t4(adap->params.chip))
mem_base -= adap->t4_bar0;
- win_pf = is_t4(adap->params.chip) ? 0 : PFNUM_V(adap->fn);
+ win_pf = is_t4(adap->params.chip) ? 0 : PFNUM_V(adap->pf);
/* Calculate our initial PCI-E Memory Window Position and Offset into
* that Window.
@@ -625,6 +527,102 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
return 0;
}
+/* Return the specified PCI-E Configuration Space register from our Physical
+ * Function. We try first via a Firmware LDST Command since we prefer to let
+ * the firmware own all of these registers, but if that fails we go for it
+ * directly ourselves.
+ */
+u32 t4_read_pcie_cfg4(struct adapter *adap, int reg)
+{
+ u32 val, ldst_addrspace;
+
+ /* If fw_attach != 0, construct and send the Firmware LDST Command to
+ * retrieve the specified PCI-E Configuration Space register.
+ */
+ struct fw_ldst_cmd ldst_cmd;
+ int ret;
+
+ memset(&ldst_cmd, 0, sizeof(ldst_cmd));
+ ldst_addrspace = FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_FUNC_PCIE);
+ ldst_cmd.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F |
+ ldst_addrspace);
+ ldst_cmd.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst_cmd));
+ ldst_cmd.u.pcie.select_naccess = FW_LDST_CMD_NACCESS_V(1);
+ ldst_cmd.u.pcie.ctrl_to_fn =
+ (FW_LDST_CMD_LC_F | FW_LDST_CMD_FN_V(adap->pf));
+ ldst_cmd.u.pcie.r = reg;
+
+ /* If the LDST Command succeeds, return the result, otherwise
+ * fall through to reading it directly ourselves ...
+ */
+ ret = t4_wr_mbox(adap, adap->mbox, &ldst_cmd, sizeof(ldst_cmd),
+ &ldst_cmd);
+ if (ret == 0)
+ val = be32_to_cpu(ldst_cmd.u.pcie.data[0]);
+ else
+ /* Read the desired Configuration Space register via the PCI-E
+ * Backdoor mechanism.
+ */
+ t4_hw_pci_read_cfg4(adap, reg, &val);
+ return val;
+}
+
+/* Get the window based on base passed to it.
+ * Window aperture is currently unhandled, but there is no use case for it
+ * right now
+ */
+static u32 t4_get_window(struct adapter *adap, u32 pci_base, u64 pci_mask,
+ u32 memwin_base)
+{
+ u32 ret;
+
+ if (is_t4(adap->params.chip)) {
+ u32 bar0;
+
+ /* Truncation intentional: we only read the bottom 32-bits of
+ * the 64-bit BAR0/BAR1 ... We use the hardware backdoor
+ * mechanism to read BAR0 instead of using
+ * pci_resource_start() because we could be operating from
+ * within a Virtual Machine which is trapping our accesses to
+ * our Configuration Space and we need to set up the PCI-E
+ * Memory Window decoders with the actual addresses which will
+ * be coming across the PCI-E link.
+ */
+ bar0 = t4_read_pcie_cfg4(adap, pci_base);
+ bar0 &= pci_mask;
+ adap->t4_bar0 = bar0;
+
+ ret = bar0 + memwin_base;
+ } else {
+ /* For T5, only relative offset inside the PCIe BAR is passed */
+ ret = memwin_base;
+ }
+ return ret;
+}
+
+/* Get the default utility window (win0) used by everyone */
+u32 t4_get_util_window(struct adapter *adap)
+{
+ return t4_get_window(adap, PCI_BASE_ADDRESS_0,
+ PCI_BASE_ADDRESS_MEM_MASK, MEMWIN0_BASE);
+}
+
+/* Set up memory window for accessing adapter memory ranges. (Read
+ * back MA register to ensure that changes propagate before we attempt
+ * to use the new values.)
+ */
+void t4_setup_memwin(struct adapter *adap, u32 memwin_base, u32 window)
+{
+ t4_write_reg(adap,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, window),
+ memwin_base | BIR_V(0) |
+ WINDOW_V(ilog2(MEMWIN0_APERTURE) - WINDOW_SHIFT_X));
+ t4_read_reg(adap,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, window));
+}
+
/**
* t4_get_regs_len - return the size of the chips register set
* @adapter: the adapter
@@ -640,6 +638,7 @@ unsigned int t4_get_regs_len(struct adapter *adapter)
return T4_REGMAP_SIZE;
case CHELSIO_T5:
+ case CHELSIO_T6:
return T5_REGMAP_SIZE;
}
@@ -666,7 +665,8 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x11fc, 0x123c,
0x1300, 0x173c,
0x1800, 0x18fc,
- 0x3000, 0x30d8,
+ 0x3000, 0x305c,
+ 0x3068, 0x30d8,
0x30e0, 0x5924,
0x5960, 0x59d4,
0x5a00, 0x5af8,
@@ -729,7 +729,7 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x19238, 0x1924c,
0x193f8, 0x19474,
0x19490, 0x194f8,
- 0x19800, 0x19f30,
+ 0x19800, 0x19f4c,
0x1a000, 0x1a06c,
0x1a0b0, 0x1a120,
0x1a128, 0x1a138,
@@ -878,7 +878,7 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x27780, 0x2778c,
0x27800, 0x27c38,
0x27c80, 0x27d7c,
- 0x27e00, 0x27e04
+ 0x27e00, 0x27e04,
};
static const unsigned int t5_reg_ranges[] = {
@@ -888,7 +888,7 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x1280, 0x173c,
0x1800, 0x18fc,
0x3000, 0x3028,
- 0x3060, 0x30d8,
+ 0x3068, 0x30d8,
0x30e0, 0x30fc,
0x3140, 0x357c,
0x35a8, 0x35cc,
@@ -900,7 +900,7 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x5940, 0x59dc,
0x59fc, 0x5a18,
0x5a60, 0x5a9c,
- 0x5b9c, 0x5bfc,
+ 0x5b94, 0x5bfc,
0x6000, 0x6040,
0x6058, 0x614c,
0x7700, 0x7798,
@@ -1014,27 +1014,30 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x30800, 0x30834,
0x308c0, 0x30908,
0x30910, 0x309ac,
- 0x30a00, 0x30a04,
- 0x30a0c, 0x30a2c,
+ 0x30a00, 0x30a2c,
0x30a44, 0x30a50,
0x30a74, 0x30c24,
+ 0x30d00, 0x30d00,
0x30d08, 0x30d14,
0x30d1c, 0x30d20,
0x30d3c, 0x30d50,
0x31200, 0x3120c,
0x31220, 0x31220,
0x31240, 0x31240,
- 0x31600, 0x31600,
- 0x31608, 0x3160c,
+ 0x31600, 0x3160c,
0x31a00, 0x31a1c,
- 0x31e04, 0x31e20,
+ 0x31e00, 0x31e20,
0x31e38, 0x31e3c,
0x31e80, 0x31e80,
0x31e88, 0x31ea8,
0x31eb0, 0x31eb4,
0x31ec8, 0x31ed4,
0x31fb8, 0x32004,
- 0x32208, 0x3223c,
+ 0x32200, 0x32200,
+ 0x32208, 0x32240,
+ 0x32248, 0x32280,
+ 0x32288, 0x322c0,
+ 0x322c8, 0x322fc,
0x32600, 0x32630,
0x32a00, 0x32abc,
0x32b00, 0x32b70,
@@ -1074,27 +1077,30 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x34800, 0x34834,
0x348c0, 0x34908,
0x34910, 0x349ac,
- 0x34a00, 0x34a04,
- 0x34a0c, 0x34a2c,
+ 0x34a00, 0x34a2c,
0x34a44, 0x34a50,
0x34a74, 0x34c24,
+ 0x34d00, 0x34d00,
0x34d08, 0x34d14,
0x34d1c, 0x34d20,
0x34d3c, 0x34d50,
0x35200, 0x3520c,
0x35220, 0x35220,
0x35240, 0x35240,
- 0x35600, 0x35600,
- 0x35608, 0x3560c,
+ 0x35600, 0x3560c,
0x35a00, 0x35a1c,
- 0x35e04, 0x35e20,
+ 0x35e00, 0x35e20,
0x35e38, 0x35e3c,
0x35e80, 0x35e80,
0x35e88, 0x35ea8,
0x35eb0, 0x35eb4,
0x35ec8, 0x35ed4,
0x35fb8, 0x36004,
- 0x36208, 0x3623c,
+ 0x36200, 0x36200,
+ 0x36208, 0x36240,
+ 0x36248, 0x36280,
+ 0x36288, 0x362c0,
+ 0x362c8, 0x362fc,
0x36600, 0x36630,
0x36a00, 0x36abc,
0x36b00, 0x36b70,
@@ -1134,27 +1140,30 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x38800, 0x38834,
0x388c0, 0x38908,
0x38910, 0x389ac,
- 0x38a00, 0x38a04,
- 0x38a0c, 0x38a2c,
+ 0x38a00, 0x38a2c,
0x38a44, 0x38a50,
0x38a74, 0x38c24,
+ 0x38d00, 0x38d00,
0x38d08, 0x38d14,
0x38d1c, 0x38d20,
0x38d3c, 0x38d50,
0x39200, 0x3920c,
0x39220, 0x39220,
0x39240, 0x39240,
- 0x39600, 0x39600,
- 0x39608, 0x3960c,
+ 0x39600, 0x3960c,
0x39a00, 0x39a1c,
- 0x39e04, 0x39e20,
+ 0x39e00, 0x39e20,
0x39e38, 0x39e3c,
0x39e80, 0x39e80,
0x39e88, 0x39ea8,
0x39eb0, 0x39eb4,
0x39ec8, 0x39ed4,
0x39fb8, 0x3a004,
- 0x3a208, 0x3a23c,
+ 0x3a200, 0x3a200,
+ 0x3a208, 0x3a240,
+ 0x3a248, 0x3a280,
+ 0x3a288, 0x3a2c0,
+ 0x3a2c8, 0x3a2fc,
0x3a600, 0x3a630,
0x3aa00, 0x3aabc,
0x3ab00, 0x3ab70,
@@ -1194,27 +1203,30 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x3c800, 0x3c834,
0x3c8c0, 0x3c908,
0x3c910, 0x3c9ac,
- 0x3ca00, 0x3ca04,
- 0x3ca0c, 0x3ca2c,
+ 0x3ca00, 0x3ca2c,
0x3ca44, 0x3ca50,
0x3ca74, 0x3cc24,
+ 0x3cd00, 0x3cd00,
0x3cd08, 0x3cd14,
0x3cd1c, 0x3cd20,
0x3cd3c, 0x3cd50,
0x3d200, 0x3d20c,
0x3d220, 0x3d220,
0x3d240, 0x3d240,
- 0x3d600, 0x3d600,
- 0x3d608, 0x3d60c,
+ 0x3d600, 0x3d60c,
0x3da00, 0x3da1c,
- 0x3de04, 0x3de20,
+ 0x3de00, 0x3de20,
0x3de38, 0x3de3c,
0x3de80, 0x3de80,
0x3de88, 0x3dea8,
0x3deb0, 0x3deb4,
0x3dec8, 0x3ded4,
0x3dfb8, 0x3e004,
- 0x3e208, 0x3e23c,
+ 0x3e200, 0x3e200,
+ 0x3e208, 0x3e240,
+ 0x3e248, 0x3e280,
+ 0x3e288, 0x3e2c0,
+ 0x3e2c8, 0x3e2fc,
0x3e600, 0x3e630,
0x3ea00, 0x3eabc,
0x3eb00, 0x3eb70,
@@ -1247,7 +1259,7 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x3fcf0, 0x3fcfc,
0x40000, 0x4000c,
0x40040, 0x40068,
- 0x40080, 0x40144,
+ 0x4007c, 0x40144,
0x40180, 0x4018c,
0x40200, 0x40298,
0x402ac, 0x4033c,
@@ -1275,7 +1287,7 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x47800, 0x47814,
0x48000, 0x4800c,
0x48040, 0x48068,
- 0x48080, 0x48144,
+ 0x4807c, 0x48144,
0x48180, 0x4818c,
0x48200, 0x48298,
0x482ac, 0x4833c,
@@ -1309,6 +1321,344 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
0x51300, 0x51308,
};
+ static const unsigned int t6_reg_ranges[] = {
+ 0x1008, 0x114c,
+ 0x1180, 0x11b4,
+ 0x11fc, 0x1250,
+ 0x1280, 0x133c,
+ 0x1800, 0x18fc,
+ 0x3000, 0x302c,
+ 0x3060, 0x30d8,
+ 0x30e0, 0x30fc,
+ 0x3140, 0x357c,
+ 0x35a8, 0x35cc,
+ 0x35ec, 0x35ec,
+ 0x3600, 0x5624,
+ 0x56cc, 0x575c,
+ 0x580c, 0x5814,
+ 0x5890, 0x58bc,
+ 0x5940, 0x595c,
+ 0x5980, 0x598c,
+ 0x59b0, 0x59dc,
+ 0x59fc, 0x5a18,
+ 0x5a60, 0x5a6c,
+ 0x5a80, 0x5a9c,
+ 0x5b94, 0x5bfc,
+ 0x5c10, 0x5ec0,
+ 0x5ec8, 0x5ec8,
+ 0x6000, 0x6040,
+ 0x6058, 0x6154,
+ 0x7700, 0x7798,
+ 0x77c0, 0x7880,
+ 0x78cc, 0x78fc,
+ 0x7b00, 0x7c54,
+ 0x7d00, 0x7efc,
+ 0x8dc0, 0x8de0,
+ 0x8df8, 0x8e84,
+ 0x8ea0, 0x8f88,
+ 0x8fb8, 0x911c,
+ 0x9400, 0x9470,
+ 0x9600, 0x971c,
+ 0x9800, 0x9808,
+ 0x9820, 0x983c,
+ 0x9850, 0x9864,
+ 0x9c00, 0x9c6c,
+ 0x9c80, 0x9cec,
+ 0x9d00, 0x9d6c,
+ 0x9d80, 0x9dec,
+ 0x9e00, 0x9e6c,
+ 0x9e80, 0x9eec,
+ 0x9f00, 0x9f6c,
+ 0x9f80, 0xa020,
+ 0xd004, 0xd03c,
+ 0xdfc0, 0xdfe0,
+ 0xe000, 0xf008,
+ 0x11000, 0x11014,
+ 0x11048, 0x11110,
+ 0x11118, 0x1117c,
+ 0x11190, 0x11260,
+ 0x11300, 0x1130c,
+ 0x12000, 0x1205c,
+ 0x19040, 0x1906c,
+ 0x19078, 0x19080,
+ 0x1908c, 0x19124,
+ 0x19150, 0x191b0,
+ 0x191d0, 0x191e8,
+ 0x19238, 0x192b8,
+ 0x193f8, 0x19474,
+ 0x19490, 0x194cc,
+ 0x194f0, 0x194f8,
+ 0x19c00, 0x19c80,
+ 0x19c94, 0x19cbc,
+ 0x19ce4, 0x19d28,
+ 0x19d50, 0x19d78,
+ 0x19d94, 0x19dc8,
+ 0x19df0, 0x19e10,
+ 0x19e50, 0x19e6c,
+ 0x19ea0, 0x19f34,
+ 0x19f40, 0x19f50,
+ 0x19f90, 0x19fac,
+ 0x19fc4, 0x19fe4,
+ 0x1a000, 0x1a06c,
+ 0x1a0b0, 0x1a120,
+ 0x1a128, 0x1a138,
+ 0x1a190, 0x1a1c4,
+ 0x1a1fc, 0x1a1fc,
+ 0x1e008, 0x1e00c,
+ 0x1e040, 0x1e04c,
+ 0x1e284, 0x1e290,
+ 0x1e2c0, 0x1e2c0,
+ 0x1e2e0, 0x1e2e0,
+ 0x1e300, 0x1e384,
+ 0x1e3c0, 0x1e3c8,
+ 0x1e408, 0x1e40c,
+ 0x1e440, 0x1e44c,
+ 0x1e684, 0x1e690,
+ 0x1e6c0, 0x1e6c0,
+ 0x1e6e0, 0x1e6e0,
+ 0x1e700, 0x1e784,
+ 0x1e7c0, 0x1e7c8,
+ 0x1e808, 0x1e80c,
+ 0x1e840, 0x1e84c,
+ 0x1ea84, 0x1ea90,
+ 0x1eac0, 0x1eac0,
+ 0x1eae0, 0x1eae0,
+ 0x1eb00, 0x1eb84,
+ 0x1ebc0, 0x1ebc8,
+ 0x1ec08, 0x1ec0c,
+ 0x1ec40, 0x1ec4c,
+ 0x1ee84, 0x1ee90,
+ 0x1eec0, 0x1eec0,
+ 0x1eee0, 0x1eee0,
+ 0x1ef00, 0x1ef84,
+ 0x1efc0, 0x1efc8,
+ 0x1f008, 0x1f00c,
+ 0x1f040, 0x1f04c,
+ 0x1f284, 0x1f290,
+ 0x1f2c0, 0x1f2c0,
+ 0x1f2e0, 0x1f2e0,
+ 0x1f300, 0x1f384,
+ 0x1f3c0, 0x1f3c8,
+ 0x1f408, 0x1f40c,
+ 0x1f440, 0x1f44c,
+ 0x1f684, 0x1f690,
+ 0x1f6c0, 0x1f6c0,
+ 0x1f6e0, 0x1f6e0,
+ 0x1f700, 0x1f784,
+ 0x1f7c0, 0x1f7c8,
+ 0x1f808, 0x1f80c,
+ 0x1f840, 0x1f84c,
+ 0x1fa84, 0x1fa90,
+ 0x1fac0, 0x1fac0,
+ 0x1fae0, 0x1fae0,
+ 0x1fb00, 0x1fb84,
+ 0x1fbc0, 0x1fbc8,
+ 0x1fc08, 0x1fc0c,
+ 0x1fc40, 0x1fc4c,
+ 0x1fe84, 0x1fe90,
+ 0x1fec0, 0x1fec0,
+ 0x1fee0, 0x1fee0,
+ 0x1ff00, 0x1ff84,
+ 0x1ffc0, 0x1ffc8,
+ 0x30000, 0x30070,
+ 0x30100, 0x3015c,
+ 0x30190, 0x301d0,
+ 0x30200, 0x30318,
+ 0x30400, 0x3052c,
+ 0x30540, 0x3061c,
+ 0x30800, 0x3088c,
+ 0x308c0, 0x30908,
+ 0x30910, 0x309b8,
+ 0x30a00, 0x30a04,
+ 0x30a0c, 0x30a2c,
+ 0x30a44, 0x30a50,
+ 0x30a74, 0x30c24,
+ 0x30d00, 0x30d3c,
+ 0x30d44, 0x30d7c,
+ 0x30de0, 0x30de0,
+ 0x30e00, 0x30ed4,
+ 0x30f00, 0x30fa4,
+ 0x30fc0, 0x30fc4,
+ 0x31000, 0x31004,
+ 0x31080, 0x310fc,
+ 0x31208, 0x31220,
+ 0x3123c, 0x31254,
+ 0x31300, 0x31300,
+ 0x31308, 0x3131c,
+ 0x31338, 0x3133c,
+ 0x31380, 0x31380,
+ 0x31388, 0x313a8,
+ 0x313b4, 0x313b4,
+ 0x31400, 0x31420,
+ 0x31438, 0x3143c,
+ 0x31480, 0x31480,
+ 0x314a8, 0x314a8,
+ 0x314b0, 0x314b4,
+ 0x314c8, 0x314d4,
+ 0x31a40, 0x31a4c,
+ 0x31af0, 0x31b20,
+ 0x31b38, 0x31b3c,
+ 0x31b80, 0x31b80,
+ 0x31ba8, 0x31ba8,
+ 0x31bb0, 0x31bb4,
+ 0x31bc8, 0x31bd4,
+ 0x32140, 0x3218c,
+ 0x321f0, 0x32200,
+ 0x32218, 0x32218,
+ 0x32400, 0x32400,
+ 0x32408, 0x3241c,
+ 0x32618, 0x32620,
+ 0x32664, 0x32664,
+ 0x326a8, 0x326a8,
+ 0x326ec, 0x326ec,
+ 0x32a00, 0x32abc,
+ 0x32b00, 0x32b78,
+ 0x32c00, 0x32c00,
+ 0x32c08, 0x32c3c,
+ 0x32e00, 0x32e2c,
+ 0x32f00, 0x32f2c,
+ 0x33000, 0x330ac,
+ 0x330c0, 0x331ac,
+ 0x331c0, 0x332c4,
+ 0x332e4, 0x333c4,
+ 0x333e4, 0x334ac,
+ 0x334c0, 0x335ac,
+ 0x335c0, 0x336c4,
+ 0x336e4, 0x337c4,
+ 0x337e4, 0x337fc,
+ 0x33814, 0x33814,
+ 0x33854, 0x33868,
+ 0x33880, 0x3388c,
+ 0x338c0, 0x338d0,
+ 0x338e8, 0x338ec,
+ 0x33900, 0x339ac,
+ 0x339c0, 0x33ac4,
+ 0x33ae4, 0x33b10,
+ 0x33b24, 0x33b50,
+ 0x33bf0, 0x33c10,
+ 0x33c24, 0x33c50,
+ 0x33cf0, 0x33cfc,
+ 0x34000, 0x34070,
+ 0x34100, 0x3415c,
+ 0x34190, 0x341d0,
+ 0x34200, 0x34318,
+ 0x34400, 0x3452c,
+ 0x34540, 0x3461c,
+ 0x34800, 0x3488c,
+ 0x348c0, 0x34908,
+ 0x34910, 0x349b8,
+ 0x34a00, 0x34a04,
+ 0x34a0c, 0x34a2c,
+ 0x34a44, 0x34a50,
+ 0x34a74, 0x34c24,
+ 0x34d00, 0x34d3c,
+ 0x34d44, 0x34d7c,
+ 0x34de0, 0x34de0,
+ 0x34e00, 0x34ed4,
+ 0x34f00, 0x34fa4,
+ 0x34fc0, 0x34fc4,
+ 0x35000, 0x35004,
+ 0x35080, 0x350fc,
+ 0x35208, 0x35220,
+ 0x3523c, 0x35254,
+ 0x35300, 0x35300,
+ 0x35308, 0x3531c,
+ 0x35338, 0x3533c,
+ 0x35380, 0x35380,
+ 0x35388, 0x353a8,
+ 0x353b4, 0x353b4,
+ 0x35400, 0x35420,
+ 0x35438, 0x3543c,
+ 0x35480, 0x35480,
+ 0x354a8, 0x354a8,
+ 0x354b0, 0x354b4,
+ 0x354c8, 0x354d4,
+ 0x35a40, 0x35a4c,
+ 0x35af0, 0x35b20,
+ 0x35b38, 0x35b3c,
+ 0x35b80, 0x35b80,
+ 0x35ba8, 0x35ba8,
+ 0x35bb0, 0x35bb4,
+ 0x35bc8, 0x35bd4,
+ 0x36140, 0x3618c,
+ 0x361f0, 0x36200,
+ 0x36218, 0x36218,
+ 0x36400, 0x36400,
+ 0x36408, 0x3641c,
+ 0x36618, 0x36620,
+ 0x36664, 0x36664,
+ 0x366a8, 0x366a8,
+ 0x366ec, 0x366ec,
+ 0x36a00, 0x36abc,
+ 0x36b00, 0x36b78,
+ 0x36c00, 0x36c00,
+ 0x36c08, 0x36c3c,
+ 0x36e00, 0x36e2c,
+ 0x36f00, 0x36f2c,
+ 0x37000, 0x370ac,
+ 0x370c0, 0x371ac,
+ 0x371c0, 0x372c4,
+ 0x372e4, 0x373c4,
+ 0x373e4, 0x374ac,
+ 0x374c0, 0x375ac,
+ 0x375c0, 0x376c4,
+ 0x376e4, 0x377c4,
+ 0x377e4, 0x377fc,
+ 0x37814, 0x37814,
+ 0x37854, 0x37868,
+ 0x37880, 0x3788c,
+ 0x378c0, 0x378d0,
+ 0x378e8, 0x378ec,
+ 0x37900, 0x379ac,
+ 0x379c0, 0x37ac4,
+ 0x37ae4, 0x37b10,
+ 0x37b24, 0x37b50,
+ 0x37bf0, 0x37c10,
+ 0x37c24, 0x37c50,
+ 0x37cf0, 0x37cfc,
+ 0x40040, 0x40040,
+ 0x40080, 0x40084,
+ 0x40100, 0x40100,
+ 0x40140, 0x401bc,
+ 0x40200, 0x40214,
+ 0x40228, 0x40228,
+ 0x40240, 0x40258,
+ 0x40280, 0x40280,
+ 0x40304, 0x40304,
+ 0x40330, 0x4033c,
+ 0x41304, 0x413dc,
+ 0x41400, 0x4141c,
+ 0x41480, 0x414d0,
+ 0x44000, 0x4407c,
+ 0x440c0, 0x4427c,
+ 0x442c0, 0x4447c,
+ 0x444c0, 0x4467c,
+ 0x446c0, 0x4487c,
+ 0x448c0, 0x44a7c,
+ 0x44ac0, 0x44c7c,
+ 0x44cc0, 0x44e7c,
+ 0x44ec0, 0x4507c,
+ 0x450c0, 0x451fc,
+ 0x45800, 0x45868,
+ 0x45880, 0x45884,
+ 0x458a0, 0x458b0,
+ 0x45a00, 0x45a68,
+ 0x45a80, 0x45a84,
+ 0x45aa0, 0x45ab0,
+ 0x460c0, 0x460e4,
+ 0x47000, 0x4708c,
+ 0x47200, 0x47250,
+ 0x47400, 0x47420,
+ 0x47600, 0x47618,
+ 0x47800, 0x4782c,
+ 0x50000, 0x500cc,
+ 0x50400, 0x50400,
+ 0x50800, 0x508cc,
+ 0x50c00, 0x50c00,
+ 0x51000, 0x510b0,
+ 0x51300, 0x51324,
+ };
+
u32 *buf_end = (u32 *)((char *)buf + buf_size);
const unsigned int *reg_ranges;
int reg_ranges_size, range;
@@ -1328,6 +1678,11 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
reg_ranges_size = ARRAY_SIZE(t5_reg_ranges);
break;
+ case CHELSIO_T6:
+ reg_ranges = t6_reg_ranges;
+ reg_ranges_size = ARRAY_SIZE(t6_reg_ranges);
+ break;
+
default:
dev_err(adap->pdev_dev,
"Unsupported chip version %d\n", chip_version);
@@ -1374,17 +1729,16 @@ int t4_seeprom_wp(struct adapter *adapter, bool enable)
}
/**
- * get_vpd_params - read VPD parameters from VPD EEPROM
+ * t4_get_raw_vpd_params - read VPD parameters from VPD EEPROM
* @adapter: adapter to read
* @p: where to store the parameters
*
* Reads card parameters stored in VPD EEPROM.
*/
-int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
+int t4_get_raw_vpd_params(struct adapter *adapter, struct vpd_params *p)
{
- u32 cclk_param, cclk_val;
- int i, ret, addr;
- int ec, sn, pn;
+ int i, ret = 0, addr;
+ int ec, sn, pn, na;
u8 *vpd, csum;
unsigned int vpdr_len, kw_offset, id_len;
@@ -1392,6 +1746,9 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
if (!vpd)
return -ENOMEM;
+ /* Card information normally starts at VPD_BASE but early cards had
+ * it at 0.
+ */
ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(u32), vpd);
if (ret < 0)
goto out;
@@ -1457,6 +1814,7 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
FIND_VPD_KW(ec, "EC");
FIND_VPD_KW(sn, "SN");
FIND_VPD_KW(pn, "PN");
+ FIND_VPD_KW(na, "NA");
#undef FIND_VPD_KW
memcpy(p->id, vpd + PCI_VPD_LRDT_TAG_SIZE, id_len);
@@ -1469,18 +1827,42 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
i = pci_vpd_info_field_size(vpd + pn - PCI_VPD_INFO_FLD_HDR_SIZE);
memcpy(p->pn, vpd + pn, min(i, PN_LEN));
strim(p->pn);
+ memcpy(p->na, vpd + na, min(i, MACADDR_LEN));
+ strim((char *)p->na);
- /*
- * Ask firmware for the Core Clock since it knows how to translate the
+out:
+ vfree(vpd);
+ return ret;
+}
+
+/**
+ * t4_get_vpd_params - read VPD parameters & retrieve Core Clock
+ * @adapter: adapter to read
+ * @p: where to store the parameters
+ *
+ * Reads card parameters stored in VPD EEPROM and retrieves the Core
+ * Clock. This can only be called after a connection to the firmware
+ * is established.
+ */
+int t4_get_vpd_params(struct adapter *adapter, struct vpd_params *p)
+{
+ u32 cclk_param, cclk_val;
+ int ret;
+
+ /* Grab the raw VPD parameters.
+ */
+ ret = t4_get_raw_vpd_params(adapter, p);
+ if (ret)
+ return ret;
+
+ /* Ask firmware for the Core Clock since it knows how to translate the
* Reference Clock ('V2') VPD field into a Core Clock value ...
*/
cclk_param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CCLK));
- ret = t4_query_params(adapter, adapter->mbox, 0, 0,
+ ret = t4_query_params(adapter, adapter->mbox, adapter->pf, 0,
1, &cclk_param, &cclk_val);
-out:
- vfree(vpd);
if (ret)
return ret;
p->cclk = cclk_val;
@@ -1618,7 +2000,7 @@ int t4_read_flash(struct adapter *adapter, unsigned int addr,
if (ret)
return ret;
if (byte_oriented)
- *data = (__force __u32) (htonl(*data));
+ *data = (__force __u32)(cpu_to_be32(*data));
}
return 0;
}
@@ -1941,7 +2323,8 @@ static bool t4_fw_matches_chip(const struct adapter *adap,
* which will keep us "honest" in the future ...
*/
if ((is_t4(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T4) ||
- (is_t5(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T5))
+ (is_t5(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T5) ||
+ (is_t6(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T6))
return true;
dev_err(adap->pdev_dev,
@@ -1979,7 +2362,7 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
"FW image size not multiple of 512 bytes\n");
return -EINVAL;
}
- if (ntohs(hdr->len512) * 512 != size) {
+ if ((unsigned int)be16_to_cpu(hdr->len512) * 512 != size) {
dev_err(adap->pdev_dev,
"FW image size differs from size in FW header\n");
return -EINVAL;
@@ -1993,7 +2376,7 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
return -EINVAL;
for (csum = 0, i = 0; i < size / sizeof(csum); i++)
- csum += ntohl(p[i]);
+ csum += be32_to_cpu(p[i]);
if (csum != 0xffffffff) {
dev_err(adap->pdev_dev,
@@ -2012,7 +2395,7 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
* first page with a bad version.
*/
memcpy(first_page, fw_data, SF_PAGE_SIZE);
- ((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff);
+ ((struct fw_hdr *)first_page)->fw_ver = cpu_to_be32(0xffffffff);
ret = t4_write_flash(adap, fw_img_start, SF_PAGE_SIZE, first_page);
if (ret)
goto out;
@@ -2039,6 +2422,147 @@ out:
}
/**
+ * t4_phy_fw_ver - return current PHY firmware version
+ * @adap: the adapter
+ * @phy_fw_ver: return value buffer for PHY firmware version
+ *
+ * Returns the current version of external PHY firmware on the
+ * adapter.
+ */
+int t4_phy_fw_ver(struct adapter *adap, int *phy_fw_ver)
+{
+ u32 param, val;
+ int ret;
+
+ param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PHYFW) |
+ FW_PARAMS_PARAM_Y_V(adap->params.portvec) |
+ FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_VERSION));
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1,
+ &param, &val);
+ if (ret < 0)
+ return ret;
+ *phy_fw_ver = val;
+ return 0;
+}
+
+/**
+ * t4_load_phy_fw - download port PHY firmware
+ * @adap: the adapter
+ * @win: the PCI-E Memory Window index to use for t4_memory_rw()
+ * @win_lock: the lock to use to guard the memory copy
+ * @phy_fw_version: function to check PHY firmware versions
+ * @phy_fw_data: the PHY firmware image to write
+ * @phy_fw_size: image size
+ *
+ * Transfer the specified PHY firmware to the adapter. If a non-NULL
+ * @phy_fw_version is supplied, then it will be used to determine if
+ * it's necessary to perform the transfer by comparing the version
+ * of any existing adapter PHY firmware with that of the passed in
+ * PHY firmware image. If @win_lock is non-NULL then it will be used
+ * around the call to t4_memory_rw() which transfers the PHY firmware
+ * to the adapter.
+ *
+ * A negative error number will be returned if an error occurs. If
+ * version number support is available and there's no need to upgrade
+ * the firmware, 0 will be returned. If firmware is successfully
+ * transferred to the adapter, 1 will be retured.
+ *
+ * NOTE: some adapters only have local RAM to store the PHY firmware. As
+ * a result, a RESET of the adapter would cause that RAM to lose its
+ * contents. Thus, loading PHY firmware on such adapters must happen
+ * after any FW_RESET_CMDs ...
+ */
+int t4_load_phy_fw(struct adapter *adap,
+ int win, spinlock_t *win_lock,
+ int (*phy_fw_version)(const u8 *, size_t),
+ const u8 *phy_fw_data, size_t phy_fw_size)
+{
+ unsigned long mtype = 0, maddr = 0;
+ u32 param, val;
+ int cur_phy_fw_ver = 0, new_phy_fw_vers = 0;
+ int ret;
+
+ /* If we have version number support, then check to see if the adapter
+ * already has up-to-date PHY firmware loaded.
+ */
+ if (phy_fw_version) {
+ new_phy_fw_vers = phy_fw_version(phy_fw_data, phy_fw_size);
+ ret = t4_phy_fw_ver(adap, &cur_phy_fw_ver);
+ if (ret < 0)
+ return ret;
+
+ if (cur_phy_fw_ver >= new_phy_fw_vers) {
+ CH_WARN(adap, "PHY Firmware already up-to-date, "
+ "version %#x\n", cur_phy_fw_ver);
+ return 0;
+ }
+ }
+
+ /* Ask the firmware where it wants us to copy the PHY firmware image.
+ * The size of the file requires a special version of the READ coommand
+ * which will pass the file size via the values field in PARAMS_CMD and
+ * retrieve the return value from firmware and place it in the same
+ * buffer values
+ */
+ param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PHYFW) |
+ FW_PARAMS_PARAM_Y_V(adap->params.portvec) |
+ FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_DOWNLOAD));
+ val = phy_fw_size;
+ ret = t4_query_params_rw(adap, adap->mbox, adap->pf, 0, 1,
+ &param, &val, 1);
+ if (ret < 0)
+ return ret;
+ mtype = val >> 8;
+ maddr = (val & 0xff) << 16;
+
+ /* Copy the supplied PHY Firmware image to the adapter memory location
+ * allocated by the adapter firmware.
+ */
+ if (win_lock)
+ spin_lock_bh(win_lock);
+ ret = t4_memory_rw(adap, win, mtype, maddr,
+ phy_fw_size, (__be32 *)phy_fw_data,
+ T4_MEMORY_WRITE);
+ if (win_lock)
+ spin_unlock_bh(win_lock);
+ if (ret)
+ return ret;
+
+ /* Tell the firmware that the PHY firmware image has been written to
+ * RAM and it can now start copying it over to the PHYs. The chip
+ * firmware will RESET the affected PHYs as part of this operation
+ * leaving them running the new PHY firmware image.
+ */
+ param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PHYFW) |
+ FW_PARAMS_PARAM_Y_V(adap->params.portvec) |
+ FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_DOWNLOAD));
+ ret = t4_set_params_timeout(adap, adap->mbox, adap->pf, 0, 1,
+ &param, &val, 30000);
+
+ /* If we have version number support, then check to see that the new
+ * firmware got loaded properly.
+ */
+ if (phy_fw_version) {
+ ret = t4_phy_fw_ver(adap, &cur_phy_fw_ver);
+ if (ret < 0)
+ return ret;
+
+ if (cur_phy_fw_ver != new_phy_fw_vers) {
+ CH_WARN(adap, "PHY Firmware did not update: "
+ "version on adapter %#x, "
+ "version flashed %#x\n",
+ cur_phy_fw_ver, new_phy_fw_vers);
+ return -ENXIO;
+ }
+ }
+
+ return 1;
+}
+
+/**
* t4_fwcache - firmware cache operation
* @adap: the adapter
* @op : the operation (flush or flush and invalidate)
@@ -2051,7 +2575,7 @@ int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op)
c.op_to_vfn =
cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) |
FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
- FW_PARAMS_CMD_PFN_V(adap->fn) |
+ FW_PARAMS_CMD_PFN_V(adap->pf) |
FW_PARAMS_CMD_VFN_V(0));
c.retval_len16 = cpu_to_be32(FW_LEN16(c));
c.param[0].mnem =
@@ -2062,6 +2586,61 @@ int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op)
return t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), NULL);
}
+void t4_cim_read_pif_la(struct adapter *adap, u32 *pif_req, u32 *pif_rsp,
+ unsigned int *pif_req_wrptr,
+ unsigned int *pif_rsp_wrptr)
+{
+ int i, j;
+ u32 cfg, val, req, rsp;
+
+ cfg = t4_read_reg(adap, CIM_DEBUGCFG_A);
+ if (cfg & LADBGEN_F)
+ t4_write_reg(adap, CIM_DEBUGCFG_A, cfg ^ LADBGEN_F);
+
+ val = t4_read_reg(adap, CIM_DEBUGSTS_A);
+ req = POLADBGWRPTR_G(val);
+ rsp = PILADBGWRPTR_G(val);
+ if (pif_req_wrptr)
+ *pif_req_wrptr = req;
+ if (pif_rsp_wrptr)
+ *pif_rsp_wrptr = rsp;
+
+ for (i = 0; i < CIM_PIFLA_SIZE; i++) {
+ for (j = 0; j < 6; j++) {
+ t4_write_reg(adap, CIM_DEBUGCFG_A, POLADBGRDPTR_V(req) |
+ PILADBGRDPTR_V(rsp));
+ *pif_req++ = t4_read_reg(adap, CIM_PO_LA_DEBUGDATA_A);
+ *pif_rsp++ = t4_read_reg(adap, CIM_PI_LA_DEBUGDATA_A);
+ req++;
+ rsp++;
+ }
+ req = (req + 2) & POLADBGRDPTR_M;
+ rsp = (rsp + 2) & PILADBGRDPTR_M;
+ }
+ t4_write_reg(adap, CIM_DEBUGCFG_A, cfg);
+}
+
+void t4_cim_read_ma_la(struct adapter *adap, u32 *ma_req, u32 *ma_rsp)
+{
+ u32 cfg;
+ int i, j, idx;
+
+ cfg = t4_read_reg(adap, CIM_DEBUGCFG_A);
+ if (cfg & LADBGEN_F)
+ t4_write_reg(adap, CIM_DEBUGCFG_A, cfg ^ LADBGEN_F);
+
+ for (i = 0; i < CIM_MALA_SIZE; i++) {
+ for (j = 0; j < 5; j++) {
+ idx = 8 * i + j;
+ t4_write_reg(adap, CIM_DEBUGCFG_A, POLADBGRDPTR_V(idx) |
+ PILADBGRDPTR_V(idx));
+ *ma_req++ = t4_read_reg(adap, CIM_PO_LA_MADEBUGDATA_A);
+ *ma_rsp++ = t4_read_reg(adap, CIM_PI_LA_MADEBUGDATA_A);
+ }
+ }
+ t4_write_reg(adap, CIM_DEBUGCFG_A, cfg);
+}
+
void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf)
{
unsigned int i, j;
@@ -2082,7 +2661,7 @@ void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf)
FW_PORT_CAP_ANEG)
/**
- * t4_link_start - apply link configuration to MAC/PHY
+ * t4_link_l1cfg - apply link configuration to MAC/PHY
* @phy: the PHY to setup
* @mac: the MAC to setup
* @lc: the requested link configuration
@@ -2094,7 +2673,7 @@ void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf)
* - If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
* otherwise do it later based on the outcome of auto-negotiation.
*/
-int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port,
+int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port,
struct link_config *lc)
{
struct fw_port_cmd c;
@@ -2107,19 +2686,22 @@ int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port,
fc |= FW_PORT_CAP_FC_TX;
memset(&c, 0, sizeof(c));
- c.op_to_portid = htonl(FW_CMD_OP_V(FW_PORT_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_EXEC_F | FW_PORT_CMD_PORTID_V(port));
- c.action_to_len16 = htonl(FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_L1_CFG) |
- FW_LEN16(c));
+ c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
+ FW_PORT_CMD_PORTID_V(port));
+ c.action_to_len16 =
+ cpu_to_be32(FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_L1_CFG) |
+ FW_LEN16(c));
if (!(lc->supported & FW_PORT_CAP_ANEG)) {
- c.u.l1cfg.rcap = htonl((lc->supported & ADVERT_MASK) | fc);
+ c.u.l1cfg.rcap = cpu_to_be32((lc->supported & ADVERT_MASK) |
+ fc);
lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
} else if (lc->autoneg == AUTONEG_DISABLE) {
- c.u.l1cfg.rcap = htonl(lc->requested_speed | fc | mdi);
+ c.u.l1cfg.rcap = cpu_to_be32(lc->requested_speed | fc | mdi);
lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
} else
- c.u.l1cfg.rcap = htonl(lc->advertising | fc | mdi);
+ c.u.l1cfg.rcap = cpu_to_be32(lc->advertising | fc | mdi);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
@@ -2137,11 +2719,13 @@ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port)
struct fw_port_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_portid = htonl(FW_CMD_OP_V(FW_PORT_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_EXEC_F | FW_PORT_CMD_PORTID_V(port));
- c.action_to_len16 = htonl(FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_L1_CFG) |
- FW_LEN16(c));
- c.u.l1cfg.rcap = htonl(FW_PORT_CAP_ANEG);
+ c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
+ FW_PORT_CMD_PORTID_V(port));
+ c.action_to_len16 =
+ cpu_to_be32(FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_L1_CFG) |
+ FW_LEN16(c));
+ c.u.l1cfg.rcap = cpu_to_be32(FW_PORT_CAP_ANEG);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
@@ -2335,6 +2919,7 @@ static void tp_intr_handler(struct adapter *adapter)
static void sge_intr_handler(struct adapter *adapter)
{
u64 v;
+ u32 err;
static const struct intr_info sge_intr_info[] = {
{ ERR_CPL_EXCEED_IQE_SIZE_F,
@@ -2343,8 +2928,6 @@ static void sge_intr_handler(struct adapter *adapter)
"SGE GTS CIDX increment too large", -1, 0 },
{ ERR_CPL_OPCODE_0_F, "SGE received 0-length CPL", -1, 0 },
{ DBFIFO_LP_INT_F, NULL, -1, 0, t4_db_full },
- { DBFIFO_HP_INT_F, NULL, -1, 0, t4_db_full },
- { ERR_DROPPED_DB_F, NULL, -1, 0, t4_db_dropped },
{ ERR_DATA_CPL_ON_HIGH_QID1_F | ERR_DATA_CPL_ON_HIGH_QID0_F,
"SGE IQID > 1023 received CPL for FL", -1, 0 },
{ ERR_BAD_DB_PIDX3_F, "SGE DBP 3 pidx increment too large", -1,
@@ -2357,13 +2940,19 @@ static void sge_intr_handler(struct adapter *adapter)
0 },
{ ERR_ING_CTXT_PRIO_F,
"SGE too many priority ingress contexts", -1, 0 },
- { ERR_EGR_CTXT_PRIO_F,
- "SGE too many priority egress contexts", -1, 0 },
{ INGRESS_SIZE_ERR_F, "SGE illegal ingress QID", -1, 0 },
{ EGRESS_SIZE_ERR_F, "SGE illegal egress QID", -1, 0 },
{ 0 }
};
+ static struct intr_info t4t5_sge_intr_info[] = {
+ { ERR_DROPPED_DB_F, NULL, -1, 0, t4_db_dropped },
+ { DBFIFO_HP_INT_F, NULL, -1, 0, t4_db_full },
+ { ERR_EGR_CTXT_PRIO_F,
+ "SGE too many priority egress contexts", -1, 0 },
+ { 0 }
+ };
+
v = (u64)t4_read_reg(adapter, SGE_INT_CAUSE1_A) |
((u64)t4_read_reg(adapter, SGE_INT_CAUSE2_A) << 32);
if (v) {
@@ -2373,8 +2962,23 @@ static void sge_intr_handler(struct adapter *adapter)
t4_write_reg(adapter, SGE_INT_CAUSE2_A, v >> 32);
}
- if (t4_handle_intr_status(adapter, SGE_INT_CAUSE3_A, sge_intr_info) ||
- v != 0)
+ v |= t4_handle_intr_status(adapter, SGE_INT_CAUSE3_A, sge_intr_info);
+ if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5)
+ v |= t4_handle_intr_status(adapter, SGE_INT_CAUSE3_A,
+ t4t5_sge_intr_info);
+
+ err = t4_read_reg(adapter, SGE_ERROR_STATS_A);
+ if (err & ERROR_QID_VALID_F) {
+ dev_err(adapter->pdev_dev, "SGE error for queue %u\n",
+ ERROR_QID_G(err));
+ if (err & UNCAPTURED_ERROR_F)
+ dev_err(adapter->pdev_dev,
+ "SGE UNCAPTURED_ERROR set (clearing)\n");
+ t4_write_reg(adapter, SGE_ERROR_STATS_A, ERROR_QID_VALID_F |
+ UNCAPTURED_ERROR_F);
+ }
+
+ if (v != 0)
t4_fatal_err(adapter);
}
@@ -2547,6 +3151,7 @@ static void cplsw_intr_handler(struct adapter *adapter)
*/
static void le_intr_handler(struct adapter *adap)
{
+ enum chip_type chip = CHELSIO_CHIP_VERSION(adap->params.chip);
static const struct intr_info le_intr_info[] = {
{ LIPMISS_F, "LE LIP miss", -1, 0 },
{ LIP0_F, "LE 0 LIP error", -1, 0 },
@@ -2556,7 +3161,18 @@ static void le_intr_handler(struct adapter *adap)
{ 0 }
};
- if (t4_handle_intr_status(adap, LE_DB_INT_CAUSE_A, le_intr_info))
+ static struct intr_info t6_le_intr_info[] = {
+ { T6_LIPMISS_F, "LE LIP miss", -1, 0 },
+ { T6_LIP0_F, "LE 0 LIP error", -1, 0 },
+ { TCAMINTPERR_F, "LE parity error", -1, 1 },
+ { T6_UNKNOWNCMD_F, "LE unknown command", -1, 1 },
+ { SSRAMINTPERR_F, "LE request queue parity error", -1, 1 },
+ { 0 }
+ };
+
+ if (t4_handle_intr_status(adap, LE_DB_INT_CAUSE_A,
+ (chip <= CHELSIO_T5) ?
+ le_intr_info : t6_le_intr_info))
t4_fatal_err(adap);
}
@@ -2825,7 +3441,7 @@ int t4_slow_intr_handler(struct adapter *adapter)
pcie_intr_handler(adapter);
if (cause & MC_F)
mem_intr_handler(adapter, MEM_MC);
- if (!is_t4(adapter->params.chip) && (cause & MC1_S))
+ if (is_t5(adapter->params.chip) && (cause & MC1_F))
mem_intr_handler(adapter, MEM_MC1);
if (cause & EDC0_F)
mem_intr_handler(adapter, MEM_EDC0);
@@ -2871,17 +3487,18 @@ int t4_slow_intr_handler(struct adapter *adapter)
*/
void t4_intr_enable(struct adapter *adapter)
{
+ u32 val = 0;
u32 pf = SOURCEPF_G(t4_read_reg(adapter, PL_WHOAMI_A));
+ if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5)
+ val = ERR_DROPPED_DB_F | ERR_EGR_CTXT_PRIO_F | DBFIFO_HP_INT_F;
t4_write_reg(adapter, SGE_INT_ENABLE3_A, ERR_CPL_EXCEED_IQE_SIZE_F |
ERR_INVALID_CIDX_INC_F | ERR_CPL_OPCODE_0_F |
- ERR_DROPPED_DB_F | ERR_DATA_CPL_ON_HIGH_QID1_F |
+ ERR_DATA_CPL_ON_HIGH_QID1_F | INGRESS_SIZE_ERR_F |
ERR_DATA_CPL_ON_HIGH_QID0_F | ERR_BAD_DB_PIDX3_F |
ERR_BAD_DB_PIDX2_F | ERR_BAD_DB_PIDX1_F |
ERR_BAD_DB_PIDX0_F | ERR_ING_CTXT_PRIO_F |
- ERR_EGR_CTXT_PRIO_F | INGRESS_SIZE_ERR_F |
- DBFIFO_HP_INT_F | DBFIFO_LP_INT_F |
- EGRESS_SIZE_ERR_F);
+ DBFIFO_LP_INT_F | EGRESS_SIZE_ERR_F | val);
t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE_A), PF_INTR_MASK);
t4_set_reg_field(adapter, PL_INT_MAP0_A, 0, 1 << pf);
}
@@ -2945,18 +3562,18 @@ int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid,
struct fw_rss_ind_tbl_cmd cmd;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_viid = htonl(FW_CMD_OP_V(FW_RSS_IND_TBL_CMD) |
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_RSS_IND_TBL_CMD) |
FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
FW_RSS_IND_TBL_CMD_VIID_V(viid));
- cmd.retval_len16 = htonl(FW_LEN16(cmd));
+ cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
/* each fw_rss_ind_tbl_cmd takes up to 32 entries */
while (n > 0) {
int nq = min(n, 32);
__be32 *qp = &cmd.iq0_to_iq2;
- cmd.niqid = htons(nq);
- cmd.startidx = htons(start);
+ cmd.niqid = cpu_to_be16(nq);
+ cmd.startidx = cpu_to_be16(start);
start += nq;
n -= nq;
@@ -2974,7 +3591,7 @@ int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid,
if (++rsp >= rsp_end)
rsp = rspq;
- *qp++ = htonl(v);
+ *qp++ = cpu_to_be32(v);
nq -= 3;
}
@@ -3000,20 +3617,46 @@ int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode,
struct fw_rss_glb_config_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_write = htonl(FW_CMD_OP_V(FW_RSS_GLB_CONFIG_CMD) |
- FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
- c.retval_len16 = htonl(FW_LEN16(c));
+ c.op_to_write = cpu_to_be32(FW_CMD_OP_V(FW_RSS_GLB_CONFIG_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
+ c.retval_len16 = cpu_to_be32(FW_LEN16(c));
if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL) {
- c.u.manual.mode_pkd = htonl(FW_RSS_GLB_CONFIG_CMD_MODE_V(mode));
+ c.u.manual.mode_pkd =
+ cpu_to_be32(FW_RSS_GLB_CONFIG_CMD_MODE_V(mode));
} else if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) {
c.u.basicvirtual.mode_pkd =
- htonl(FW_RSS_GLB_CONFIG_CMD_MODE_V(mode));
- c.u.basicvirtual.synmapen_to_hashtoeplitz = htonl(flags);
+ cpu_to_be32(FW_RSS_GLB_CONFIG_CMD_MODE_V(mode));
+ c.u.basicvirtual.synmapen_to_hashtoeplitz = cpu_to_be32(flags);
} else
return -EINVAL;
return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL);
}
+/**
+ * t4_config_vi_rss - configure per VI RSS settings
+ * @adapter: the adapter
+ * @mbox: mbox to use for the FW command
+ * @viid: the VI id
+ * @flags: RSS flags
+ * @defq: id of the default RSS queue for the VI.
+ *
+ * Configures VI-specific RSS properties.
+ */
+int t4_config_vi_rss(struct adapter *adapter, int mbox, unsigned int viid,
+ unsigned int flags, unsigned int defq)
+{
+ struct fw_rss_vi_config_cmd c;
+
+ memset(&c, 0, sizeof(c));
+ c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_RSS_VI_CONFIG_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
+ FW_RSS_VI_CONFIG_CMD_VIID_V(viid));
+ c.retval_len16 = cpu_to_be32(FW_LEN16(c));
+ c.u.basicvirtual.defaultq_to_udpen = cpu_to_be32(flags |
+ FW_RSS_VI_CONFIG_CMD_DEFAULTQ_V(defq));
+ return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL);
+}
+
/* Read an RSS table row */
static int rd_rss_row(struct adapter *adap, int row, u32 *val)
{
@@ -3045,6 +3688,40 @@ int t4_read_rss(struct adapter *adapter, u16 *map)
}
/**
+ * t4_fw_tp_pio_rw - Access TP PIO through LDST
+ * @adap: the adapter
+ * @vals: where the indirect register values are stored/written
+ * @nregs: how many indirect registers to read/write
+ * @start_idx: index of first indirect register to read/write
+ * @rw: Read (1) or Write (0)
+ *
+ * Access TP PIO registers through LDST
+ */
+static void t4_fw_tp_pio_rw(struct adapter *adap, u32 *vals, unsigned int nregs,
+ unsigned int start_index, unsigned int rw)
+{
+ int ret, i;
+ int cmd = FW_LDST_ADDRSPC_TP_PIO;
+ struct fw_ldst_cmd c;
+
+ for (i = 0 ; i < nregs; i++) {
+ memset(&c, 0, sizeof(c));
+ c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) |
+ FW_CMD_REQUEST_F |
+ (rw ? FW_CMD_READ_F :
+ FW_CMD_WRITE_F) |
+ FW_LDST_CMD_ADDRSPACE_V(cmd));
+ c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c));
+
+ c.u.addrval.addr = cpu_to_be32(start_index + i);
+ c.u.addrval.val = rw ? 0 : cpu_to_be32(vals[i]);
+ ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c);
+ if (!ret && rw)
+ vals[i] = be32_to_cpu(c.u.addrval.val);
+ }
+}
+
+/**
* t4_read_rss_key - read the global RSS key
* @adap: the adapter
* @key: 10-entry array holding the 320-bit RSS key
@@ -3053,8 +3730,11 @@ int t4_read_rss(struct adapter *adapter, u16 *map)
*/
void t4_read_rss_key(struct adapter *adap, u32 *key)
{
- t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10,
- TP_RSS_SECRET_KEY0_A);
+ if (adap->flags & FW_OK)
+ t4_fw_tp_pio_rw(adap, key, 10, TP_RSS_SECRET_KEY0_A, 1);
+ else
+ t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10,
+ TP_RSS_SECRET_KEY0_A);
}
/**
@@ -3069,11 +3749,32 @@ void t4_read_rss_key(struct adapter *adap, u32 *key)
*/
void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx)
{
- t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10,
- TP_RSS_SECRET_KEY0_A);
- if (idx >= 0 && idx < 16)
- t4_write_reg(adap, TP_RSS_CONFIG_VRT_A,
- KEYWRADDR_V(idx) | KEYWREN_F);
+ u8 rss_key_addr_cnt = 16;
+ u32 vrt = t4_read_reg(adap, TP_RSS_CONFIG_VRT_A);
+
+ /* T6 and later: for KeyMode 3 (per-vf and per-vf scramble),
+ * allows access to key addresses 16-63 by using KeyWrAddrX
+ * as index[5:4](upper 2) into key table
+ */
+ if ((CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) &&
+ (vrt & KEYEXTEND_F) && (KEYMODE_G(vrt) == 3))
+ rss_key_addr_cnt = 32;
+
+ if (adap->flags & FW_OK)
+ t4_fw_tp_pio_rw(adap, (void *)key, 10, TP_RSS_SECRET_KEY0_A, 0);
+ else
+ t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10,
+ TP_RSS_SECRET_KEY0_A);
+
+ if (idx >= 0 && idx < rss_key_addr_cnt) {
+ if (rss_key_addr_cnt > 16)
+ t4_write_reg(adap, TP_RSS_CONFIG_VRT_A,
+ KEYWRADDRX_V(idx >> 4) |
+ T6_VFWRADDR_V(idx) | KEYWREN_F);
+ else
+ t4_write_reg(adap, TP_RSS_CONFIG_VRT_A,
+ KEYWRADDR_V(idx) | KEYWREN_F);
+ }
}
/**
@@ -3088,8 +3789,12 @@ void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx)
void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index,
u32 *valp)
{
- t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
- valp, 1, TP_RSS_PF0_CONFIG_A + index);
+ if (adapter->flags & FW_OK)
+ t4_fw_tp_pio_rw(adapter, valp, 1,
+ TP_RSS_PF0_CONFIG_A + index, 1);
+ else
+ t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+ valp, 1, TP_RSS_PF0_CONFIG_A + index);
}
/**
@@ -3107,8 +3812,13 @@ void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index,
{
u32 vrt, mask, data;
- mask = VFWRADDR_V(VFWRADDR_M);
- data = VFWRADDR_V(index);
+ if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) {
+ mask = VFWRADDR_V(VFWRADDR_M);
+ data = VFWRADDR_V(index);
+ } else {
+ mask = T6_VFWRADDR_V(T6_VFWRADDR_M);
+ data = T6_VFWRADDR_V(index);
+ }
/* Request that the index'th VF Table values be read into VFL/VFH.
*/
@@ -3119,10 +3829,15 @@ void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index,
/* Grab the VFL/VFH values ...
*/
- t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
- vfl, 1, TP_RSS_VFL_CONFIG_A);
- t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
- vfh, 1, TP_RSS_VFH_CONFIG_A);
+ if (adapter->flags & FW_OK) {
+ t4_fw_tp_pio_rw(adapter, vfl, 1, TP_RSS_VFL_CONFIG_A, 1);
+ t4_fw_tp_pio_rw(adapter, vfh, 1, TP_RSS_VFH_CONFIG_A, 1);
+ } else {
+ t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+ vfl, 1, TP_RSS_VFL_CONFIG_A);
+ t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+ vfh, 1, TP_RSS_VFH_CONFIG_A);
+ }
}
/**
@@ -3135,8 +3850,11 @@ u32 t4_read_rss_pf_map(struct adapter *adapter)
{
u32 pfmap;
- t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
- &pfmap, 1, TP_RSS_PF_MAP_A);
+ if (adapter->flags & FW_OK)
+ t4_fw_tp_pio_rw(adapter, &pfmap, 1, TP_RSS_PF_MAP_A, 1);
+ else
+ t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+ &pfmap, 1, TP_RSS_PF_MAP_A);
return pfmap;
}
@@ -3150,8 +3868,11 @@ u32 t4_read_rss_pf_mask(struct adapter *adapter)
{
u32 pfmask;
- t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
- &pfmask, 1, TP_RSS_PF_MSK_A);
+ if (adapter->flags & FW_OK)
+ t4_fw_tp_pio_rw(adapter, &pfmask, 1, TP_RSS_PF_MSK_A, 1);
+ else
+ t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+ &pfmask, 1, TP_RSS_PF_MSK_A);
return pfmask;
}
@@ -3176,18 +3897,18 @@ void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
if (v4) {
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val,
ARRAY_SIZE(val), TP_MIB_TCP_OUT_RST_A);
- v4->tcpOutRsts = STAT(OUT_RST);
- v4->tcpInSegs = STAT64(IN_SEG);
- v4->tcpOutSegs = STAT64(OUT_SEG);
- v4->tcpRetransSegs = STAT64(RXT_SEG);
+ v4->tcp_out_rsts = STAT(OUT_RST);
+ v4->tcp_in_segs = STAT64(IN_SEG);
+ v4->tcp_out_segs = STAT64(OUT_SEG);
+ v4->tcp_retrans_segs = STAT64(RXT_SEG);
}
if (v6) {
t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val,
ARRAY_SIZE(val), TP_MIB_TCP_V6OUT_RST_A);
- v6->tcpOutRsts = STAT(OUT_RST);
- v6->tcpInSegs = STAT64(IN_SEG);
- v6->tcpOutSegs = STAT64(OUT_SEG);
- v6->tcpRetransSegs = STAT64(RXT_SEG);
+ v6->tcp_out_rsts = STAT(OUT_RST);
+ v6->tcp_in_segs = STAT64(IN_SEG);
+ v6->tcp_out_segs = STAT64(OUT_SEG);
+ v6->tcp_retrans_segs = STAT64(RXT_SEG);
}
#undef STAT64
#undef STAT
@@ -3195,6 +3916,130 @@ void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
}
/**
+ * t4_tp_get_err_stats - read TP's error MIB counters
+ * @adap: the adapter
+ * @st: holds the counter values
+ *
+ * Returns the values of TP's error counters.
+ */
+void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st)
+{
+ /* T6 and later has 2 channels */
+ if (adap->params.arch.nchan == NCHAN) {
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+ st->mac_in_errs, 12, TP_MIB_MAC_IN_ERR_0_A);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+ st->tnl_cong_drops, 8,
+ TP_MIB_TNL_CNG_DROP_0_A);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+ st->tnl_tx_drops, 4,
+ TP_MIB_TNL_DROP_0_A);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+ st->ofld_vlan_drops, 4,
+ TP_MIB_OFD_VLN_DROP_0_A);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+ st->tcp6_in_errs, 4,
+ TP_MIB_TCP_V6IN_ERR_0_A);
+ } else {
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+ st->mac_in_errs, 2, TP_MIB_MAC_IN_ERR_0_A);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+ st->hdr_in_errs, 2, TP_MIB_HDR_IN_ERR_0_A);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+ st->tcp_in_errs, 2, TP_MIB_TCP_IN_ERR_0_A);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+ st->tnl_cong_drops, 2,
+ TP_MIB_TNL_CNG_DROP_0_A);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+ st->ofld_chan_drops, 2,
+ TP_MIB_OFD_CHN_DROP_0_A);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+ st->tnl_tx_drops, 2, TP_MIB_TNL_DROP_0_A);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+ st->ofld_vlan_drops, 2,
+ TP_MIB_OFD_VLN_DROP_0_A);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+ st->tcp6_in_errs, 2, TP_MIB_TCP_V6IN_ERR_0_A);
+ }
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+ &st->ofld_no_neigh, 2, TP_MIB_OFD_ARP_DROP_A);
+}
+
+/**
+ * t4_tp_get_cpl_stats - read TP's CPL MIB counters
+ * @adap: the adapter
+ * @st: holds the counter values
+ *
+ * Returns the values of TP's CPL counters.
+ */
+void t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st)
+{
+ /* T6 and later has 2 channels */
+ if (adap->params.arch.nchan == NCHAN) {
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->req,
+ 8, TP_MIB_CPL_IN_REQ_0_A);
+ } else {
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->req,
+ 2, TP_MIB_CPL_IN_REQ_0_A);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->rsp,
+ 2, TP_MIB_CPL_OUT_RSP_0_A);
+ }
+}
+
+/**
+ * t4_tp_get_rdma_stats - read TP's RDMA MIB counters
+ * @adap: the adapter
+ * @st: holds the counter values
+ *
+ * Returns the values of TP's RDMA counters.
+ */
+void t4_tp_get_rdma_stats(struct adapter *adap, struct tp_rdma_stats *st)
+{
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, &st->rqe_dfr_pkt,
+ 2, TP_MIB_RQE_DFR_PKT_A);
+}
+
+/**
+ * t4_get_fcoe_stats - read TP's FCoE MIB counters for a port
+ * @adap: the adapter
+ * @idx: the port index
+ * @st: holds the counter values
+ *
+ * Returns the values of TP's FCoE counters for the selected port.
+ */
+void t4_get_fcoe_stats(struct adapter *adap, unsigned int idx,
+ struct tp_fcoe_stats *st)
+{
+ u32 val[2];
+
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, &st->frames_ddp,
+ 1, TP_MIB_FCOE_DDP_0_A + idx);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, &st->frames_drop,
+ 1, TP_MIB_FCOE_DROP_0_A + idx);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val,
+ 2, TP_MIB_FCOE_BYTE_0_HI_A + 2 * idx);
+ st->octets_ddp = ((u64)val[0] << 32) | val[1];
+}
+
+/**
+ * t4_get_usm_stats - read TP's non-TCP DDP MIB counters
+ * @adap: the adapter
+ * @st: holds the counter values
+ *
+ * Returns the values of TP's counters for non-TCP directly-placed packets.
+ */
+void t4_get_usm_stats(struct adapter *adap, struct tp_usm_stats *st)
+{
+ u32 val[4];
+
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val, 4,
+ TP_MIB_USM_PKTS_A);
+ st->frames = val[0];
+ st->drops = val[1];
+ st->octets = ((u64)val[2] << 32) | val[3];
+}
+
+/**
* t4_read_mtu_tbl - returns the values in the HW path MTU table
* @adap: the adapter
* @mtus: where to store the MTU values
@@ -3346,6 +4191,52 @@ void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
}
}
+/* Calculates a rate in bytes/s given the number of 256-byte units per 4K core
+ * clocks. The formula is
+ *
+ * bytes/s = bytes256 * 256 * ClkFreq / 4096
+ *
+ * which is equivalent to
+ *
+ * bytes/s = 62.5 * bytes256 * ClkFreq_ms
+ */
+static u64 chan_rate(struct adapter *adap, unsigned int bytes256)
+{
+ u64 v = bytes256 * adap->params.vpd.cclk;
+
+ return v * 62 + v / 2;
+}
+
+/**
+ * t4_get_chan_txrate - get the current per channel Tx rates
+ * @adap: the adapter
+ * @nic_rate: rates for NIC traffic
+ * @ofld_rate: rates for offloaded traffic
+ *
+ * Return the current Tx rates in bytes/s for NIC and offloaded traffic
+ * for each channel.
+ */
+void t4_get_chan_txrate(struct adapter *adap, u64 *nic_rate, u64 *ofld_rate)
+{
+ u32 v;
+
+ v = t4_read_reg(adap, TP_TX_TRATE_A);
+ nic_rate[0] = chan_rate(adap, TNLRATE0_G(v));
+ nic_rate[1] = chan_rate(adap, TNLRATE1_G(v));
+ if (adap->params.arch.nchan == NCHAN) {
+ nic_rate[2] = chan_rate(adap, TNLRATE2_G(v));
+ nic_rate[3] = chan_rate(adap, TNLRATE3_G(v));
+ }
+
+ v = t4_read_reg(adap, TP_TX_ORATE_A);
+ ofld_rate[0] = chan_rate(adap, OFDRATE0_G(v));
+ ofld_rate[1] = chan_rate(adap, OFDRATE1_G(v));
+ if (adap->params.arch.nchan == NCHAN) {
+ ofld_rate[2] = chan_rate(adap, OFDRATE2_G(v));
+ ofld_rate[3] = chan_rate(adap, OFDRATE3_G(v));
+ }
+}
+
/**
* t4_pmtx_get_stats - returns the HW stats from PMTX
* @adap: the adapter
@@ -3401,7 +4292,7 @@ void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[])
}
/**
- * get_mps_bg_map - return the buffer groups associated with a port
+ * t4_get_mps_bg_map - return the buffer groups associated with a port
* @adap: the adapter
* @idx: the port index
*
@@ -3409,7 +4300,7 @@ void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[])
* with the given port. Bit i is set if buffer group i is used by the
* port.
*/
-static unsigned int get_mps_bg_map(struct adapter *adap, int idx)
+unsigned int t4_get_mps_bg_map(struct adapter *adap, int idx)
{
u32 n = NUMPORTS_G(t4_read_reg(adap, MPS_CMN_CTL_A));
@@ -3451,6 +4342,28 @@ const char *t4_get_port_type_description(enum fw_port_type port_type)
}
/**
+ * t4_get_port_stats_offset - collect port stats relative to a previous
+ * snapshot
+ * @adap: The adapter
+ * @idx: The port
+ * @stats: Current stats to fill
+ * @offset: Previous stats snapshot
+ */
+void t4_get_port_stats_offset(struct adapter *adap, int idx,
+ struct port_stats *stats,
+ struct port_stats *offset)
+{
+ u64 *s, *o;
+ int i;
+
+ t4_get_port_stats(adap, idx, stats);
+ for (i = 0, s = (u64 *)stats, o = (u64 *)offset;
+ i < (sizeof(struct port_stats) / sizeof(u64));
+ i++, s++, o++)
+ *s -= *o;
+}
+
+/**
* t4_get_port_stats - collect port statistics
* @adap: the adapter
* @idx: the port index
@@ -3460,7 +4373,7 @@ const char *t4_get_port_type_description(enum fw_port_type port_type)
*/
void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
{
- u32 bgmap = get_mps_bg_map(adap, idx);
+ u32 bgmap = t4_get_mps_bg_map(adap, idx);
#define GET_STAT(name) \
t4_read_reg64(adap, \
@@ -3534,103 +4447,51 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
}
/**
- * t4_wol_magic_enable - enable/disable magic packet WoL
- * @adap: the adapter
- * @port: the physical port index
- * @addr: MAC address expected in magic packets, %NULL to disable
- *
- * Enables/disables magic packet wake-on-LAN for the selected port.
- */
-void t4_wol_magic_enable(struct adapter *adap, unsigned int port,
- const u8 *addr)
-{
- u32 mag_id_reg_l, mag_id_reg_h, port_cfg_reg;
-
- if (is_t4(adap->params.chip)) {
- mag_id_reg_l = PORT_REG(port, XGMAC_PORT_MAGIC_MACID_LO);
- mag_id_reg_h = PORT_REG(port, XGMAC_PORT_MAGIC_MACID_HI);
- port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2_A);
- } else {
- mag_id_reg_l = T5_PORT_REG(port, MAC_PORT_MAGIC_MACID_LO);
- mag_id_reg_h = T5_PORT_REG(port, MAC_PORT_MAGIC_MACID_HI);
- port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2_A);
- }
-
- if (addr) {
- t4_write_reg(adap, mag_id_reg_l,
- (addr[2] << 24) | (addr[3] << 16) |
- (addr[4] << 8) | addr[5]);
- t4_write_reg(adap, mag_id_reg_h,
- (addr[0] << 8) | addr[1]);
- }
- t4_set_reg_field(adap, port_cfg_reg, MAGICEN_F,
- addr ? MAGICEN_F : 0);
-}
-
-/**
- * t4_wol_pat_enable - enable/disable pattern-based WoL
+ * t4_get_lb_stats - collect loopback port statistics
* @adap: the adapter
- * @port: the physical port index
- * @map: bitmap of which HW pattern filters to set
- * @mask0: byte mask for bytes 0-63 of a packet
- * @mask1: byte mask for bytes 64-127 of a packet
- * @crc: Ethernet CRC for selected bytes
- * @enable: enable/disable switch
+ * @idx: the loopback port index
+ * @p: the stats structure to fill
*
- * Sets the pattern filters indicated in @map to mask out the bytes
- * specified in @mask0/@mask1 in received packets and compare the CRC of
- * the resulting packet against @crc. If @enable is %true pattern-based
- * WoL is enabled, otherwise disabled.
+ * Return HW statistics for the given loopback port.
*/
-int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
- u64 mask0, u64 mask1, unsigned int crc, bool enable)
+void t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p)
{
- int i;
- u32 port_cfg_reg;
-
- if (is_t4(adap->params.chip))
- port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2_A);
- else
- port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2_A);
+ u32 bgmap = t4_get_mps_bg_map(adap, idx);
- if (!enable) {
- t4_set_reg_field(adap, port_cfg_reg, PATEN_F, 0);
- return 0;
- }
- if (map > 0xff)
- return -EINVAL;
-
-#define EPIO_REG(name) \
+#define GET_STAT(name) \
+ t4_read_reg64(adap, \
(is_t4(adap->params.chip) ? \
- PORT_REG(port, XGMAC_PORT_EPIO_##name##_A) : \
- T5_PORT_REG(port, MAC_PORT_EPIO_##name##_A))
+ PORT_REG(idx, MPS_PORT_STAT_LB_PORT_##name##_L) : \
+ T5_PORT_REG(idx, MPS_PORT_STAT_LB_PORT_##name##_L)))
+#define GET_STAT_COM(name) t4_read_reg64(adap, MPS_STAT_##name##_L)
- t4_write_reg(adap, EPIO_REG(DATA1), mask0 >> 32);
- t4_write_reg(adap, EPIO_REG(DATA2), mask1);
- t4_write_reg(adap, EPIO_REG(DATA3), mask1 >> 32);
+ p->octets = GET_STAT(BYTES);
+ p->frames = GET_STAT(FRAMES);
+ p->bcast_frames = GET_STAT(BCAST);
+ p->mcast_frames = GET_STAT(MCAST);
+ p->ucast_frames = GET_STAT(UCAST);
+ p->error_frames = GET_STAT(ERROR);
+
+ p->frames_64 = GET_STAT(64B);
+ p->frames_65_127 = GET_STAT(65B_127B);
+ p->frames_128_255 = GET_STAT(128B_255B);
+ p->frames_256_511 = GET_STAT(256B_511B);
+ p->frames_512_1023 = GET_STAT(512B_1023B);
+ p->frames_1024_1518 = GET_STAT(1024B_1518B);
+ p->frames_1519_max = GET_STAT(1519B_MAX);
+ p->drop = GET_STAT(DROP_FRAMES);
+
+ p->ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_DROP_FRAME) : 0;
+ p->ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_DROP_FRAME) : 0;
+ p->ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_DROP_FRAME) : 0;
+ p->ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_DROP_FRAME) : 0;
+ p->trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_TRUNC_FRAME) : 0;
+ p->trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_TRUNC_FRAME) : 0;
+ p->trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_TRUNC_FRAME) : 0;
+ p->trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_TRUNC_FRAME) : 0;
- for (i = 0; i < NWOL_PAT; i++, map >>= 1) {
- if (!(map & 1))
- continue;
-
- /* write byte masks */
- t4_write_reg(adap, EPIO_REG(DATA0), mask0);
- t4_write_reg(adap, EPIO_REG(OP), ADDRESS_V(i) | EPIOWR_F);
- t4_read_reg(adap, EPIO_REG(OP)); /* flush */
- if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY_F)
- return -ETIMEDOUT;
-
- /* write CRC */
- t4_write_reg(adap, EPIO_REG(DATA0), crc);
- t4_write_reg(adap, EPIO_REG(OP), ADDRESS_V(i + 32) | EPIOWR_F);
- t4_read_reg(adap, EPIO_REG(OP)); /* flush */
- if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY_F)
- return -ETIMEDOUT;
- }
-#undef EPIO_REG
-
- t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2_A), 0, PATEN_F);
- return 0;
+#undef GET_STAT
+#undef GET_STAT_COM
}
/* t4_mk_filtdelwr - create a delete filter WR
@@ -3644,33 +4505,38 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
void t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid)
{
memset(wr, 0, sizeof(*wr));
- wr->op_pkd = htonl(FW_WR_OP_V(FW_FILTER_WR));
- wr->len16_pkd = htonl(FW_WR_LEN16_V(sizeof(*wr) / 16));
- wr->tid_to_iq = htonl(FW_FILTER_WR_TID_V(ftid) |
- FW_FILTER_WR_NOREPLY_V(qid < 0));
- wr->del_filter_to_l2tix = htonl(FW_FILTER_WR_DEL_FILTER_F);
+ wr->op_pkd = cpu_to_be32(FW_WR_OP_V(FW_FILTER_WR));
+ wr->len16_pkd = cpu_to_be32(FW_WR_LEN16_V(sizeof(*wr) / 16));
+ wr->tid_to_iq = cpu_to_be32(FW_FILTER_WR_TID_V(ftid) |
+ FW_FILTER_WR_NOREPLY_V(qid < 0));
+ wr->del_filter_to_l2tix = cpu_to_be32(FW_FILTER_WR_DEL_FILTER_F);
if (qid >= 0)
- wr->rx_chan_rx_rpl_iq = htons(FW_FILTER_WR_RX_RPL_IQ_V(qid));
+ wr->rx_chan_rx_rpl_iq =
+ cpu_to_be16(FW_FILTER_WR_RX_RPL_IQ_V(qid));
}
#define INIT_CMD(var, cmd, rd_wr) do { \
- (var).op_to_write = htonl(FW_CMD_OP_V(FW_##cmd##_CMD) | \
- FW_CMD_REQUEST_F | FW_CMD_##rd_wr##_F); \
- (var).retval_len16 = htonl(FW_LEN16(var)); \
+ (var).op_to_write = cpu_to_be32(FW_CMD_OP_V(FW_##cmd##_CMD) | \
+ FW_CMD_REQUEST_F | \
+ FW_CMD_##rd_wr##_F); \
+ (var).retval_len16 = cpu_to_be32(FW_LEN16(var)); \
} while (0)
int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
u32 addr, u32 val)
{
+ u32 ldst_addrspace;
struct fw_ldst_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_addrspace = htonl(FW_CMD_OP_V(FW_LDST_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_WRITE_F |
- FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_FIRMWARE));
- c.cycles_to_len16 = htonl(FW_LEN16(c));
- c.u.addrval.addr = htonl(addr);
- c.u.addrval.val = htonl(val);
+ ldst_addrspace = FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_FIRMWARE);
+ c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F |
+ ldst_addrspace);
+ c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c));
+ c.u.addrval.addr = cpu_to_be32(addr);
+ c.u.addrval.val = cpu_to_be32(val);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
@@ -3690,19 +4556,22 @@ int t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
unsigned int mmd, unsigned int reg, u16 *valp)
{
int ret;
+ u32 ldst_addrspace;
struct fw_ldst_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_addrspace = htonl(FW_CMD_OP_V(FW_LDST_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_READ_F | FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_MDIO));
- c.cycles_to_len16 = htonl(FW_LEN16(c));
- c.u.mdio.paddr_mmd = htons(FW_LDST_CMD_PADDR_V(phy_addr) |
- FW_LDST_CMD_MMD_V(mmd));
- c.u.mdio.raddr = htons(reg);
+ ldst_addrspace = FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_MDIO);
+ c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F |
+ ldst_addrspace);
+ c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c));
+ c.u.mdio.paddr_mmd = cpu_to_be16(FW_LDST_CMD_PADDR_V(phy_addr) |
+ FW_LDST_CMD_MMD_V(mmd));
+ c.u.mdio.raddr = cpu_to_be16(reg);
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
if (ret == 0)
- *valp = ntohs(c.u.mdio.rval);
+ *valp = be16_to_cpu(c.u.mdio.rval);
return ret;
}
@@ -3720,16 +4589,19 @@ int t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
unsigned int mmd, unsigned int reg, u16 val)
{
+ u32 ldst_addrspace;
struct fw_ldst_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_addrspace = htonl(FW_CMD_OP_V(FW_LDST_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_WRITE_F | FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_MDIO));
- c.cycles_to_len16 = htonl(FW_LEN16(c));
- c.u.mdio.paddr_mmd = htons(FW_LDST_CMD_PADDR_V(phy_addr) |
- FW_LDST_CMD_MMD_V(mmd));
- c.u.mdio.raddr = htons(reg);
- c.u.mdio.rval = htons(val);
+ ldst_addrspace = FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_MDIO);
+ c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
+ ldst_addrspace);
+ c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c));
+ c.u.mdio.paddr_mmd = cpu_to_be16(FW_LDST_CMD_PADDR_V(phy_addr) |
+ FW_LDST_CMD_MMD_V(mmd));
+ c.u.mdio.raddr = cpu_to_be16(reg);
+ c.u.mdio.rval = cpu_to_be16(val);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
@@ -3841,6 +4713,32 @@ void t4_sge_decode_idma_state(struct adapter *adapter, int state)
}
/**
+ * t4_sge_ctxt_flush - flush the SGE context cache
+ * @adap: the adapter
+ * @mbox: mailbox to use for the FW command
+ *
+ * Issues a FW command through the given mailbox to flush the
+ * SGE context cache.
+ */
+int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox)
+{
+ int ret;
+ u32 ldst_addrspace;
+ struct fw_ldst_cmd c;
+
+ memset(&c, 0, sizeof(c));
+ ldst_addrspace = FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_SGE_EGRC);
+ c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F |
+ ldst_addrspace);
+ c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c));
+ c.u.idctxt.msg_ctxtflush = cpu_to_be32(FW_LDST_CMD_CTXTFLUSH_F);
+
+ ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
+ return ret;
+}
+
+/**
* t4_fw_hello - establish communication with FW
* @adap: the adapter
* @mbox: mailbox to use for the FW command
@@ -3863,11 +4761,11 @@ int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox,
retry:
memset(&c, 0, sizeof(c));
INIT_CMD(c, HELLO, WRITE);
- c.err_to_clearinit = htonl(
+ c.err_to_clearinit = cpu_to_be32(
FW_HELLO_CMD_MASTERDIS_V(master == MASTER_CANT) |
FW_HELLO_CMD_MASTERFORCE_V(master == MASTER_MUST) |
- FW_HELLO_CMD_MBMASTER_V(master == MASTER_MUST ? mbox :
- FW_HELLO_CMD_MBMASTER_M) |
+ FW_HELLO_CMD_MBMASTER_V(master == MASTER_MUST ?
+ mbox : FW_HELLO_CMD_MBMASTER_M) |
FW_HELLO_CMD_MBASYNCNOT_V(evt_mbox) |
FW_HELLO_CMD_STAGE_V(fw_hello_cmd_stage_os) |
FW_HELLO_CMD_CLEARINIT_F);
@@ -3888,7 +4786,7 @@ retry:
return ret;
}
- v = ntohl(c.err_to_clearinit);
+ v = be32_to_cpu(c.err_to_clearinit);
master_mbox = FW_HELLO_CMD_MBMASTER_G(v);
if (state) {
if (v & FW_HELLO_CMD_ERR_F)
@@ -4017,7 +4915,7 @@ int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset)
memset(&c, 0, sizeof(c));
INIT_CMD(c, RESET, WRITE);
- c.val = htonl(reset);
+ c.val = cpu_to_be32(reset);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
@@ -4050,8 +4948,8 @@ static int t4_fw_halt(struct adapter *adap, unsigned int mbox, int force)
memset(&c, 0, sizeof(c));
INIT_CMD(c, RESET, WRITE);
- c.val = htonl(PIORST_F | PIORSTMODE_F);
- c.halt_pkd = htonl(FW_RESET_CMD_HALT_F);
+ c.val = cpu_to_be32(PIORST_F | PIORSTMODE_F);
+ c.halt_pkd = cpu_to_be32(FW_RESET_CMD_HALT_F);
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
@@ -4190,7 +5088,7 @@ int t4_fw_upgrade(struct adapter *adap, unsigned int mbox,
* the newly loaded firmware will handle this right by checking
* its header flags to see if it advertises the capability.
*/
- reset = ((ntohl(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0);
+ reset = ((be32_to_cpu(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0);
return t4_fw_restart(adap, mbox, reset);
}
@@ -4321,7 +5219,7 @@ int t4_fw_initialize(struct adapter *adap, unsigned int mbox)
}
/**
- * t4_query_params - query FW or device parameters
+ * t4_query_params_rw - query FW or device parameters
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @pf: the PF
@@ -4329,13 +5227,14 @@ int t4_fw_initialize(struct adapter *adap, unsigned int mbox)
* @nparams: the number of parameters
* @params: the parameter names
* @val: the parameter values
+ * @rw: Write and read flag
*
* Reads the value of FW or device parameters. Up to 7 parameters can be
* queried at once.
*/
-int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
- unsigned int vf, unsigned int nparams, const u32 *params,
- u32 *val)
+int t4_query_params_rw(struct adapter *adap, unsigned int mbox, unsigned int pf,
+ unsigned int vf, unsigned int nparams, const u32 *params,
+ u32 *val, int rw)
{
int i, ret;
struct fw_params_cmd c;
@@ -4345,22 +5244,35 @@ int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
return -EINVAL;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP_V(FW_PARAMS_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_READ_F | FW_PARAMS_CMD_PFN_V(pf) |
- FW_PARAMS_CMD_VFN_V(vf));
- c.retval_len16 = htonl(FW_LEN16(c));
- for (i = 0; i < nparams; i++, p += 2)
- *p = htonl(*params++);
+ c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F |
+ FW_PARAMS_CMD_PFN_V(pf) |
+ FW_PARAMS_CMD_VFN_V(vf));
+ c.retval_len16 = cpu_to_be32(FW_LEN16(c));
+
+ for (i = 0; i < nparams; i++) {
+ *p++ = cpu_to_be32(*params++);
+ if (rw)
+ *p = cpu_to_be32(*(val + i));
+ p++;
+ }
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
if (ret == 0)
for (i = 0, p = &c.param[0].val; i < nparams; i++, p += 2)
- *val++ = ntohl(*p);
+ *val++ = be32_to_cpu(*p);
return ret;
}
+int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
+ unsigned int vf, unsigned int nparams, const u32 *params,
+ u32 *val)
+{
+ return t4_query_params_rw(adap, mbox, pf, vf, nparams, params, val, 0);
+}
+
/**
- * t4_set_params_nosleep - sets FW or device parameters
+ * t4_set_params_timeout - sets FW or device parameters
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @pf: the PF
@@ -4368,15 +5280,15 @@ int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
* @nparams: the number of parameters
* @params: the parameter names
* @val: the parameter values
+ * @timeout: the timeout time
*
- * Does not ever sleep
* Sets the value of FW or device parameters. Up to 7 parameters can be
* specified at once.
*/
-int t4_set_params_nosleep(struct adapter *adap, unsigned int mbox,
+int t4_set_params_timeout(struct adapter *adap, unsigned int mbox,
unsigned int pf, unsigned int vf,
unsigned int nparams, const u32 *params,
- const u32 *val)
+ const u32 *val, int timeout)
{
struct fw_params_cmd c;
__be32 *p = &c.param[0].mnem;
@@ -4386,9 +5298,9 @@ int t4_set_params_nosleep(struct adapter *adap, unsigned int mbox,
memset(&c, 0, sizeof(c));
c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) |
- FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
- FW_PARAMS_CMD_PFN_V(pf) |
- FW_PARAMS_CMD_VFN_V(vf));
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
+ FW_PARAMS_CMD_PFN_V(pf) |
+ FW_PARAMS_CMD_VFN_V(vf));
c.retval_len16 = cpu_to_be32(FW_LEN16(c));
while (nparams--) {
@@ -4396,7 +5308,7 @@ int t4_set_params_nosleep(struct adapter *adap, unsigned int mbox,
*p++ = cpu_to_be32(*val++);
}
- return t4_wr_mbox_ns(adap, mbox, &c, sizeof(c), NULL);
+ return t4_wr_mbox_timeout(adap, mbox, &c, sizeof(c), NULL, timeout);
}
/**
@@ -4416,23 +5328,8 @@ int t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int nparams, const u32 *params,
const u32 *val)
{
- struct fw_params_cmd c;
- __be32 *p = &c.param[0].mnem;
-
- if (nparams > 7)
- return -EINVAL;
-
- memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP_V(FW_PARAMS_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_WRITE_F | FW_PARAMS_CMD_PFN_V(pf) |
- FW_PARAMS_CMD_VFN_V(vf));
- c.retval_len16 = htonl(FW_LEN16(c));
- while (nparams--) {
- *p++ = htonl(*params++);
- *p++ = htonl(*val++);
- }
-
- return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
+ return t4_set_params_timeout(adap, mbox, pf, vf, nparams, params, val,
+ FW_CMD_MAX_TIMEOUT);
}
/**
@@ -4465,20 +5362,21 @@ int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf,
struct fw_pfvf_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP_V(FW_PFVF_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_WRITE_F | FW_PFVF_CMD_PFN_V(pf) |
- FW_PFVF_CMD_VFN_V(vf));
- c.retval_len16 = htonl(FW_LEN16(c));
- c.niqflint_niq = htonl(FW_PFVF_CMD_NIQFLINT_V(rxqi) |
- FW_PFVF_CMD_NIQ_V(rxq));
- c.type_to_neq = htonl(FW_PFVF_CMD_CMASK_V(cmask) |
- FW_PFVF_CMD_PMASK_V(pmask) |
- FW_PFVF_CMD_NEQ_V(txq));
- c.tc_to_nexactf = htonl(FW_PFVF_CMD_TC_V(tc) | FW_PFVF_CMD_NVI_V(vi) |
- FW_PFVF_CMD_NEXACTF_V(nexact));
- c.r_caps_to_nethctrl = htonl(FW_PFVF_CMD_R_CAPS_V(rcaps) |
- FW_PFVF_CMD_WX_CAPS_V(wxcaps) |
- FW_PFVF_CMD_NETHCTRL_V(txq_eth_ctrl));
+ c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PFVF_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F | FW_PFVF_CMD_PFN_V(pf) |
+ FW_PFVF_CMD_VFN_V(vf));
+ c.retval_len16 = cpu_to_be32(FW_LEN16(c));
+ c.niqflint_niq = cpu_to_be32(FW_PFVF_CMD_NIQFLINT_V(rxqi) |
+ FW_PFVF_CMD_NIQ_V(rxq));
+ c.type_to_neq = cpu_to_be32(FW_PFVF_CMD_CMASK_V(cmask) |
+ FW_PFVF_CMD_PMASK_V(pmask) |
+ FW_PFVF_CMD_NEQ_V(txq));
+ c.tc_to_nexactf = cpu_to_be32(FW_PFVF_CMD_TC_V(tc) |
+ FW_PFVF_CMD_NVI_V(vi) |
+ FW_PFVF_CMD_NEXACTF_V(nexact));
+ c.r_caps_to_nethctrl = cpu_to_be32(FW_PFVF_CMD_R_CAPS_V(rcaps) |
+ FW_PFVF_CMD_WX_CAPS_V(wxcaps) |
+ FW_PFVF_CMD_NETHCTRL_V(txq_eth_ctrl));
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
@@ -4507,10 +5405,10 @@ int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port,
struct fw_vi_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP_V(FW_VI_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_WRITE_F | FW_CMD_EXEC_F |
- FW_VI_CMD_PFN_V(pf) | FW_VI_CMD_VFN_V(vf));
- c.alloc_to_len16 = htonl(FW_VI_CMD_ALLOC_F | FW_LEN16(c));
+ c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_VI_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F | FW_CMD_EXEC_F |
+ FW_VI_CMD_PFN_V(pf) | FW_VI_CMD_VFN_V(vf));
+ c.alloc_to_len16 = cpu_to_be32(FW_VI_CMD_ALLOC_F | FW_LEN16(c));
c.portid_pkd = FW_VI_CMD_PORTID_V(port);
c.nmac = nmac - 1;
@@ -4532,8 +5430,35 @@ int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port,
}
}
if (rss_size)
- *rss_size = FW_VI_CMD_RSSSIZE_G(ntohs(c.rsssize_pkd));
- return FW_VI_CMD_VIID_G(ntohs(c.type_viid));
+ *rss_size = FW_VI_CMD_RSSSIZE_G(be16_to_cpu(c.rsssize_pkd));
+ return FW_VI_CMD_VIID_G(be16_to_cpu(c.type_viid));
+}
+
+/**
+ * t4_free_vi - free a virtual interface
+ * @adap: the adapter
+ * @mbox: mailbox to use for the FW command
+ * @pf: the PF owning the VI
+ * @vf: the VF owning the VI
+ * @viid: virtual interface identifiler
+ *
+ * Free a previously allocated virtual interface.
+ */
+int t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf,
+ unsigned int vf, unsigned int viid)
+{
+ struct fw_vi_cmd c;
+
+ memset(&c, 0, sizeof(c));
+ c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_VI_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F |
+ FW_VI_CMD_PFN_V(pf) |
+ FW_VI_CMD_VFN_V(vf));
+ c.alloc_to_len16 = cpu_to_be32(FW_VI_CMD_FREE_F | FW_LEN16(c));
+ c.type_viid = cpu_to_be16(FW_VI_CMD_VIID_V(viid));
+
+ return t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
}
/**
@@ -4569,14 +5494,16 @@ int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
vlanex = FW_VI_RXMODE_CMD_VLANEXEN_M;
memset(&c, 0, sizeof(c));
- c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_RXMODE_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_WRITE_F | FW_VI_RXMODE_CMD_VIID_V(viid));
- c.retval_len16 = htonl(FW_LEN16(c));
- c.mtu_to_vlanexen = htonl(FW_VI_RXMODE_CMD_MTU_V(mtu) |
- FW_VI_RXMODE_CMD_PROMISCEN_V(promisc) |
- FW_VI_RXMODE_CMD_ALLMULTIEN_V(all_multi) |
- FW_VI_RXMODE_CMD_BROADCASTEN_V(bcast) |
- FW_VI_RXMODE_CMD_VLANEXEN_V(vlanex));
+ c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_RXMODE_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
+ FW_VI_RXMODE_CMD_VIID_V(viid));
+ c.retval_len16 = cpu_to_be32(FW_LEN16(c));
+ c.mtu_to_vlanexen =
+ cpu_to_be32(FW_VI_RXMODE_CMD_MTU_V(mtu) |
+ FW_VI_RXMODE_CMD_PROMISCEN_V(promisc) |
+ FW_VI_RXMODE_CMD_ALLMULTIEN_V(all_multi) |
+ FW_VI_RXMODE_CMD_BROADCASTEN_V(bcast) |
+ FW_VI_RXMODE_CMD_VLANEXEN_V(vlanex));
return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok);
}
@@ -4606,43 +5533,71 @@ int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
unsigned int viid, bool free, unsigned int naddr,
const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok)
{
- int i, ret;
+ int offset, ret = 0;
struct fw_vi_mac_cmd c;
- struct fw_vi_mac_exact *p;
- unsigned int max_naddr = is_t4(adap->params.chip) ?
- NUM_MPS_CLS_SRAM_L_INSTANCES :
- NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
+ unsigned int nfilters = 0;
+ unsigned int max_naddr = adap->params.arch.mps_tcam_size;
+ unsigned int rem = naddr;
- if (naddr > 7)
+ if (naddr > max_naddr)
return -EINVAL;
- memset(&c, 0, sizeof(c));
- c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_MAC_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_WRITE_F | (free ? FW_CMD_EXEC_F : 0) |
- FW_VI_MAC_CMD_VIID_V(viid));
- c.freemacs_to_len16 = htonl(FW_VI_MAC_CMD_FREEMACS_V(free) |
- FW_CMD_LEN16_V((naddr + 2) / 2));
-
- for (i = 0, p = c.u.exact; i < naddr; i++, p++) {
- p->valid_to_idx = htons(FW_VI_MAC_CMD_VALID_F |
- FW_VI_MAC_CMD_IDX_V(FW_VI_MAC_ADD_MAC));
- memcpy(p->macaddr, addr[i], sizeof(p->macaddr));
- }
+ for (offset = 0; offset < naddr ; /**/) {
+ unsigned int fw_naddr = (rem < ARRAY_SIZE(c.u.exact) ?
+ rem : ARRAY_SIZE(c.u.exact));
+ size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
+ u.exact[fw_naddr]), 16);
+ struct fw_vi_mac_exact *p;
+ int i;
- ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok);
- if (ret)
- return ret;
+ memset(&c, 0, sizeof(c));
+ c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F |
+ FW_CMD_EXEC_V(free) |
+ FW_VI_MAC_CMD_VIID_V(viid));
+ c.freemacs_to_len16 =
+ cpu_to_be32(FW_VI_MAC_CMD_FREEMACS_V(free) |
+ FW_CMD_LEN16_V(len16));
+
+ for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
+ p->valid_to_idx =
+ cpu_to_be16(FW_VI_MAC_CMD_VALID_F |
+ FW_VI_MAC_CMD_IDX_V(
+ FW_VI_MAC_ADD_MAC));
+ memcpy(p->macaddr, addr[offset + i],
+ sizeof(p->macaddr));
+ }
- for (i = 0, p = c.u.exact; i < naddr; i++, p++) {
- u16 index = FW_VI_MAC_CMD_IDX_G(ntohs(p->valid_to_idx));
+ /* It's okay if we run out of space in our MAC address arena.
+ * Some of the addresses we submit may get stored so we need
+ * to run through the reply to see what the results were ...
+ */
+ ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok);
+ if (ret && ret != -FW_ENOMEM)
+ break;
- if (idx)
- idx[i] = index >= max_naddr ? 0xffff : index;
- if (index < max_naddr)
- ret++;
- else if (hash)
- *hash |= (1ULL << hash_mac_addr(addr[i]));
+ for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
+ u16 index = FW_VI_MAC_CMD_IDX_G(
+ be16_to_cpu(p->valid_to_idx));
+
+ if (idx)
+ idx[offset + i] = (index >= max_naddr ?
+ 0xffff : index);
+ if (index < max_naddr)
+ nfilters++;
+ else if (hash)
+ *hash |= (1ULL <<
+ hash_mac_addr(addr[offset + i]));
+ }
+
+ free = false;
+ offset += fw_naddr;
+ rem -= fw_naddr;
}
+
+ if (ret == 0 || ret == -FW_ENOMEM)
+ ret = nfilters;
return ret;
}
@@ -4671,26 +5626,25 @@ int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid,
int ret, mode;
struct fw_vi_mac_cmd c;
struct fw_vi_mac_exact *p = c.u.exact;
- unsigned int max_mac_addr = is_t4(adap->params.chip) ?
- NUM_MPS_CLS_SRAM_L_INSTANCES :
- NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
+ unsigned int max_mac_addr = adap->params.arch.mps_tcam_size;
if (idx < 0) /* new allocation */
idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC;
mode = add_smt ? FW_VI_MAC_SMT_AND_MPSTCAM : FW_VI_MAC_MPS_TCAM_ENTRY;
memset(&c, 0, sizeof(c));
- c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_MAC_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_WRITE_F | FW_VI_MAC_CMD_VIID_V(viid));
- c.freemacs_to_len16 = htonl(FW_CMD_LEN16_V(1));
- p->valid_to_idx = htons(FW_VI_MAC_CMD_VALID_F |
- FW_VI_MAC_CMD_SMAC_RESULT_V(mode) |
- FW_VI_MAC_CMD_IDX_V(idx));
+ c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
+ FW_VI_MAC_CMD_VIID_V(viid));
+ c.freemacs_to_len16 = cpu_to_be32(FW_CMD_LEN16_V(1));
+ p->valid_to_idx = cpu_to_be16(FW_VI_MAC_CMD_VALID_F |
+ FW_VI_MAC_CMD_SMAC_RESULT_V(mode) |
+ FW_VI_MAC_CMD_IDX_V(idx));
memcpy(p->macaddr, addr, sizeof(p->macaddr));
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
if (ret == 0) {
- ret = FW_VI_MAC_CMD_IDX_G(ntohs(p->valid_to_idx));
+ ret = FW_VI_MAC_CMD_IDX_G(be16_to_cpu(p->valid_to_idx));
if (ret >= max_mac_addr)
ret = -ENOMEM;
}
@@ -4714,11 +5668,12 @@ int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid,
struct fw_vi_mac_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_MAC_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_WRITE_F | FW_VI_ENABLE_CMD_VIID_V(viid));
- c.freemacs_to_len16 = htonl(FW_VI_MAC_CMD_HASHVECEN_F |
- FW_VI_MAC_CMD_HASHUNIEN_V(ucast) |
- FW_CMD_LEN16_V(1));
+ c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
+ FW_VI_ENABLE_CMD_VIID_V(viid));
+ c.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_HASHVECEN_F |
+ FW_VI_MAC_CMD_HASHUNIEN_V(ucast) |
+ FW_CMD_LEN16_V(1));
c.u.hash.hashvec = cpu_to_be64(vec);
return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok);
}
@@ -4741,12 +5696,13 @@ int t4_enable_vi_params(struct adapter *adap, unsigned int mbox,
struct fw_vi_enable_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_EXEC_F | FW_VI_ENABLE_CMD_VIID_V(viid));
-
- c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_IEN_V(rx_en) |
- FW_VI_ENABLE_CMD_EEN_V(tx_en) | FW_LEN16(c) |
- FW_VI_ENABLE_CMD_DCB_INFO_V(dcb_en));
+ c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_ENABLE_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
+ FW_VI_ENABLE_CMD_VIID_V(viid));
+ c.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_IEN_V(rx_en) |
+ FW_VI_ENABLE_CMD_EEN_V(tx_en) |
+ FW_VI_ENABLE_CMD_DCB_INFO_V(dcb_en) |
+ FW_LEN16(c));
return t4_wr_mbox_ns(adap, mbox, &c, sizeof(c), NULL);
}
@@ -4781,10 +5737,11 @@ int t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid,
struct fw_vi_enable_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_EXEC_F | FW_VI_ENABLE_CMD_VIID_V(viid));
- c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_LED_F | FW_LEN16(c));
- c.blinkdur = htons(nblinks);
+ c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_ENABLE_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
+ FW_VI_ENABLE_CMD_VIID_V(viid));
+ c.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_LED_F | FW_LEN16(c));
+ c.blinkdur = cpu_to_be16(nblinks);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
@@ -4808,14 +5765,14 @@ int t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
struct fw_iq_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP_V(FW_IQ_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_EXEC_F | FW_IQ_CMD_PFN_V(pf) |
- FW_IQ_CMD_VFN_V(vf));
- c.alloc_to_len16 = htonl(FW_IQ_CMD_FREE_F | FW_LEN16(c));
- c.type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE_V(iqtype));
- c.iqid = htons(iqid);
- c.fl0id = htons(fl0id);
- c.fl1id = htons(fl1id);
+ c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_IQ_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F | FW_IQ_CMD_PFN_V(pf) |
+ FW_IQ_CMD_VFN_V(vf));
+ c.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_FREE_F | FW_LEN16(c));
+ c.type_to_iqandstindex = cpu_to_be32(FW_IQ_CMD_TYPE_V(iqtype));
+ c.iqid = cpu_to_be16(iqid);
+ c.fl0id = cpu_to_be16(fl0id);
+ c.fl1id = cpu_to_be16(fl1id);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
@@ -4835,11 +5792,12 @@ int t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
struct fw_eq_eth_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_ETH_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_EXEC_F | FW_EQ_ETH_CMD_PFN_V(pf) |
- FW_EQ_ETH_CMD_VFN_V(vf));
- c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_FREE_F | FW_LEN16(c));
- c.eqid_pkd = htonl(FW_EQ_ETH_CMD_EQID_V(eqid));
+ c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_EQ_ETH_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
+ FW_EQ_ETH_CMD_PFN_V(pf) |
+ FW_EQ_ETH_CMD_VFN_V(vf));
+ c.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_FREE_F | FW_LEN16(c));
+ c.eqid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_EQID_V(eqid));
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
@@ -4859,11 +5817,12 @@ int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
struct fw_eq_ctrl_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_EXEC_F | FW_EQ_CTRL_CMD_PFN_V(pf) |
- FW_EQ_CTRL_CMD_VFN_V(vf));
- c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_FREE_F | FW_LEN16(c));
- c.cmpliqid_eqid = htonl(FW_EQ_CTRL_CMD_EQID_V(eqid));
+ c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_EQ_CTRL_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
+ FW_EQ_CTRL_CMD_PFN_V(pf) |
+ FW_EQ_CTRL_CMD_VFN_V(vf));
+ c.alloc_to_len16 = cpu_to_be32(FW_EQ_CTRL_CMD_FREE_F | FW_LEN16(c));
+ c.cmpliqid_eqid = cpu_to_be32(FW_EQ_CTRL_CMD_EQID_V(eqid));
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
@@ -4883,11 +5842,12 @@ int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
struct fw_eq_ofld_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST_F |
- FW_CMD_EXEC_F | FW_EQ_OFLD_CMD_PFN_V(pf) |
- FW_EQ_OFLD_CMD_VFN_V(vf));
- c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_FREE_F | FW_LEN16(c));
- c.eqid_pkd = htonl(FW_EQ_OFLD_CMD_EQID_V(eqid));
+ c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_EQ_OFLD_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
+ FW_EQ_OFLD_CMD_PFN_V(pf) |
+ FW_EQ_OFLD_CMD_VFN_V(vf));
+ c.alloc_to_len16 = cpu_to_be32(FW_EQ_OFLD_CMD_FREE_F | FW_LEN16(c));
+ c.eqid_pkd = cpu_to_be32(FW_EQ_OFLD_CMD_EQID_V(eqid));
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
@@ -4905,11 +5865,11 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl)
if (opcode == FW_PORT_CMD) { /* link/module state change message */
int speed = 0, fc = 0;
const struct fw_port_cmd *p = (void *)rpl;
- int chan = FW_PORT_CMD_PORTID_G(ntohl(p->op_to_portid));
+ int chan = FW_PORT_CMD_PORTID_G(be32_to_cpu(p->op_to_portid));
int port = adap->chan_map[chan];
struct port_info *pi = adap2pinfo(adap, port);
struct link_config *lc = &pi->link_cfg;
- u32 stat = ntohl(p->u.info.lstatus_to_modtype);
+ u32 stat = be32_to_cpu(p->u.info.lstatus_to_modtype);
int link_ok = (stat & FW_PORT_CMD_LSTATUS_F) != 0;
u32 mod = FW_PORT_CMD_MODTYPE_G(stat);
@@ -5043,6 +6003,22 @@ static int get_flash_params(struct adapter *adap)
return 0;
}
+static void set_pcie_completion_timeout(struct adapter *adapter, u8 range)
+{
+ u16 val;
+ u32 pcie_cap;
+
+ pcie_cap = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+ if (pcie_cap) {
+ pci_read_config_word(adapter->pdev,
+ pcie_cap + PCI_EXP_DEVCTL2, &val);
+ val &= ~PCI_EXP_DEVCTL2_COMP_TIMEOUT;
+ val |= range;
+ pci_write_config_word(adapter->pdev,
+ pcie_cap + PCI_EXP_DEVCTL2, val);
+ }
+}
+
/**
* t4_prep_adapter - prepare SW and HW for operation
* @adapter: the adapter
@@ -5075,9 +6051,30 @@ int t4_prep_adapter(struct adapter *adapter)
switch (ver) {
case CHELSIO_T4:
adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T4, pl_rev);
+ adapter->params.arch.sge_fl_db = DBPRIO_F;
+ adapter->params.arch.mps_tcam_size =
+ NUM_MPS_CLS_SRAM_L_INSTANCES;
+ adapter->params.arch.mps_rplc_size = 128;
+ adapter->params.arch.nchan = NCHAN;
+ adapter->params.arch.vfcount = 128;
break;
case CHELSIO_T5:
adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T5, pl_rev);
+ adapter->params.arch.sge_fl_db = DBPRIO_F | DBTYPE_F;
+ adapter->params.arch.mps_tcam_size =
+ NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
+ adapter->params.arch.mps_rplc_size = 128;
+ adapter->params.arch.nchan = NCHAN;
+ adapter->params.arch.vfcount = 128;
+ break;
+ case CHELSIO_T6:
+ adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T6, pl_rev);
+ adapter->params.arch.sge_fl_db = 0;
+ adapter->params.arch.mps_tcam_size =
+ NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
+ adapter->params.arch.mps_rplc_size = 256;
+ adapter->params.arch.nchan = 2;
+ adapter->params.arch.vfcount = 256;
break;
default:
dev_err(adapter->pdev_dev, "Device %d is not supported\n",
@@ -5094,11 +6091,14 @@ int t4_prep_adapter(struct adapter *adapter)
adapter->params.nports = 1;
adapter->params.portvec = 1;
adapter->params.vpd.cclk = 50000;
+
+ /* Set pci completion timeout value to 4 seconds. */
+ set_pcie_completion_timeout(adapter, 0xd);
return 0;
}
/**
- * cxgb4_t4_bar2_sge_qregs - return BAR2 SGE Queue register information
+ * t4_bar2_sge_qregs - return BAR2 SGE Queue register information
* @adapter: the adapter
* @qid: the Queue ID
* @qtype: the Ingress or Egress type for @qid
@@ -5123,7 +6123,7 @@ int t4_prep_adapter(struct adapter *adapter)
* Write Combining Doorbell Buffer. If the BAR2 Queue ID is not 0,
* then these "Inferred Queue ID" register may not be used.
*/
-int cxgb4_t4_bar2_sge_qregs(struct adapter *adapter,
+int t4_bar2_sge_qregs(struct adapter *adapter,
unsigned int qid,
enum t4_bar2_qtype qtype,
int user,
@@ -5155,7 +6155,7 @@ int cxgb4_t4_bar2_sge_qregs(struct adapter *adapter,
* o The BAR2 Queue ID.
* o The BAR2 Queue ID Offset into the BAR2 page.
*/
- bar2_page_offset = ((qid >> qpp_shift) << page_shift);
+ bar2_page_offset = ((u64)(qid >> qpp_shift) << page_shift);
bar2_qid = qid & qpp_mask;
bar2_qid_offset = bar2_qid * SGE_UDB_SIZE;
@@ -5224,18 +6224,19 @@ int t4_init_devlog_params(struct adapter *adap)
/* Otherwise, ask the firmware for it's Device Log Parameters.
*/
memset(&devlog_cmd, 0, sizeof(devlog_cmd));
- devlog_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_DEVLOG_CMD) |
- FW_CMD_REQUEST_F | FW_CMD_READ_F);
- devlog_cmd.retval_len16 = htonl(FW_LEN16(devlog_cmd));
+ devlog_cmd.op_to_write = cpu_to_be32(FW_CMD_OP_V(FW_DEVLOG_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F);
+ devlog_cmd.retval_len16 = cpu_to_be32(FW_LEN16(devlog_cmd));
ret = t4_wr_mbox(adap, adap->mbox, &devlog_cmd, sizeof(devlog_cmd),
&devlog_cmd);
if (ret)
return ret;
- devlog_meminfo = ntohl(devlog_cmd.memtype_devlog_memaddr16_devlog);
+ devlog_meminfo =
+ be32_to_cpu(devlog_cmd.memtype_devlog_memaddr16_devlog);
dparams->memtype = FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(devlog_meminfo);
dparams->start = FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(devlog_meminfo) << 4;
- dparams->size = ntohl(devlog_cmd.memsize_devlog);
+ dparams->size = be32_to_cpu(devlog_cmd.memsize_devlog);
return 0;
}
@@ -5256,13 +6257,13 @@ int t4_init_sge_params(struct adapter *adapter)
*/
hps = t4_read_reg(adapter, SGE_HOST_PAGE_SIZE_A);
s_hps = (HOSTPAGESIZEPF0_S +
- (HOSTPAGESIZEPF1_S - HOSTPAGESIZEPF0_S) * adapter->fn);
+ (HOSTPAGESIZEPF1_S - HOSTPAGESIZEPF0_S) * adapter->pf);
sge_params->hps = ((hps >> s_hps) & HOSTPAGESIZEPF0_M);
/* Extract the SGE Egress and Ingess Queues Per Page for our PF.
*/
s_qpp = (QUEUESPERPAGEPF0_S +
- (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * adapter->fn);
+ (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * adapter->pf);
qpp = t4_read_reg(adapter, SGE_EGRESS_QUEUES_PER_PAGE_PF_A);
sge_params->eq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_M);
qpp = t4_read_reg(adapter, SGE_INGRESS_QUEUES_PER_PAGE_PF_A);
@@ -5293,12 +6294,19 @@ int t4_init_tp_params(struct adapter *adap)
/* Cache the adapter's Compressed Filter Mode and global Incress
* Configuration.
*/
- t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A,
- &adap->params.tp.vlan_pri_map, 1,
- TP_VLAN_PRI_MAP_A);
- t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A,
- &adap->params.tp.ingress_config, 1,
- TP_INGRESS_CONFIG_A);
+ if (adap->flags & FW_OK) {
+ t4_fw_tp_pio_rw(adap, &adap->params.tp.vlan_pri_map, 1,
+ TP_VLAN_PRI_MAP_A, 1);
+ t4_fw_tp_pio_rw(adap, &adap->params.tp.ingress_config, 1,
+ TP_INGRESS_CONFIG_A, 1);
+ } else {
+ t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+ &adap->params.tp.vlan_pri_map, 1,
+ TP_VLAN_PRI_MAP_A);
+ t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+ &adap->params.tp.ingress_config, 1,
+ TP_INGRESS_CONFIG_A);
+ }
/* Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field
* shift positions of several elements of the Compressed Filter Tuple
@@ -5374,6 +6382,29 @@ int t4_filter_field_shift(const struct adapter *adap, int filter_sel)
return field_shift;
}
+int t4_init_rss_mode(struct adapter *adap, int mbox)
+{
+ int i, ret;
+ struct fw_rss_vi_config_cmd rvc;
+
+ memset(&rvc, 0, sizeof(rvc));
+
+ for_each_port(adap, i) {
+ struct port_info *p = adap2pinfo(adap, i);
+
+ rvc.op_to_viid =
+ cpu_to_be32(FW_CMD_OP_V(FW_RSS_VI_CONFIG_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F |
+ FW_RSS_VI_CONFIG_CMD_VIID_V(p->viid));
+ rvc.retval_len16 = cpu_to_be32(FW_LEN16(rvc));
+ ret = t4_wr_mbox(adap, mbox, &rvc, sizeof(rvc), &rvc);
+ if (ret)
+ return ret;
+ p->rss_mode = be32_to_cpu(rvc.u.basicvirtual.defaultq_to_udpen);
+ }
+ return 0;
+}
+
int t4_port_init(struct adapter *adap, int mbox, int pf, int vf)
{
u8 addr[6];
@@ -5391,10 +6422,10 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf)
while ((adap->params.portvec & (1 << j)) == 0)
j++;
- c.op_to_portid = htonl(FW_CMD_OP_V(FW_PORT_CMD) |
- FW_CMD_REQUEST_F | FW_CMD_READ_F |
- FW_PORT_CMD_PORTID_V(j));
- c.action_to_len16 = htonl(
+ c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F |
+ FW_PORT_CMD_PORTID_V(j));
+ c.action_to_len16 = cpu_to_be32(
FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_GET_PORT_INFO) |
FW_LEN16(c));
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
@@ -5412,22 +6443,23 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf)
memcpy(adap->port[i]->dev_addr, addr, ETH_ALEN);
adap->port[i]->dev_port = j;
- ret = ntohl(c.u.info.lstatus_to_modtype);
+ ret = be32_to_cpu(c.u.info.lstatus_to_modtype);
p->mdio_addr = (ret & FW_PORT_CMD_MDIOCAP_F) ?
FW_PORT_CMD_MDIOADDR_G(ret) : -1;
p->port_type = FW_PORT_CMD_PTYPE_G(ret);
p->mod_type = FW_PORT_MOD_TYPE_NA;
- rvc.op_to_viid = htonl(FW_CMD_OP_V(FW_RSS_VI_CONFIG_CMD) |
- FW_CMD_REQUEST_F | FW_CMD_READ_F |
- FW_RSS_VI_CONFIG_CMD_VIID(p->viid));
- rvc.retval_len16 = htonl(FW_LEN16(rvc));
+ rvc.op_to_viid =
+ cpu_to_be32(FW_CMD_OP_V(FW_RSS_VI_CONFIG_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F |
+ FW_RSS_VI_CONFIG_CMD_VIID(p->viid));
+ rvc.retval_len16 = cpu_to_be32(FW_LEN16(rvc));
ret = t4_wr_mbox(adap, mbox, &rvc, sizeof(rvc), &rvc);
if (ret)
return ret;
- p->rss_mode = ntohl(rvc.u.basicvirtual.defaultq_to_udpen);
+ p->rss_mode = be32_to_cpu(rvc.u.basicvirtual.defaultq_to_udpen);
- init_link_config(&p->link_cfg, ntohs(c.u.info.pcap));
+ init_link_config(&p->link_cfg, be16_to_cpu(c.u.info.pcap));
j++;
}
return 0;
@@ -5718,3 +6750,130 @@ void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr)
t4_write_reg(adap, TP_DBG_LA_CONFIG_A,
cfg | adap->params.tp.la_mask);
}
+
+/* SGE Hung Ingress DMA Warning Threshold time and Warning Repeat Rate (in
+ * seconds). If we find one of the SGE Ingress DMA State Machines in the same
+ * state for more than the Warning Threshold then we'll issue a warning about
+ * a potential hang. We'll repeat the warning as the SGE Ingress DMA Channel
+ * appears to be hung every Warning Repeat second till the situation clears.
+ * If the situation clears, we'll note that as well.
+ */
+#define SGE_IDMA_WARN_THRESH 1
+#define SGE_IDMA_WARN_REPEAT 300
+
+/**
+ * t4_idma_monitor_init - initialize SGE Ingress DMA Monitor
+ * @adapter: the adapter
+ * @idma: the adapter IDMA Monitor state
+ *
+ * Initialize the state of an SGE Ingress DMA Monitor.
+ */
+void t4_idma_monitor_init(struct adapter *adapter,
+ struct sge_idma_monitor_state *idma)
+{
+ /* Initialize the state variables for detecting an SGE Ingress DMA
+ * hang. The SGE has internal counters which count up on each clock
+ * tick whenever the SGE finds its Ingress DMA State Engines in the
+ * same state they were on the previous clock tick. The clock used is
+ * the Core Clock so we have a limit on the maximum "time" they can
+ * record; typically a very small number of seconds. For instance,
+ * with a 600MHz Core Clock, we can only count up to a bit more than
+ * 7s. So we'll synthesize a larger counter in order to not run the
+ * risk of having the "timers" overflow and give us the flexibility to
+ * maintain a Hung SGE State Machine of our own which operates across
+ * a longer time frame.
+ */
+ idma->idma_1s_thresh = core_ticks_per_usec(adapter) * 1000000; /* 1s */
+ idma->idma_stalled[0] = 0;
+ idma->idma_stalled[1] = 0;
+}
+
+/**
+ * t4_idma_monitor - monitor SGE Ingress DMA state
+ * @adapter: the adapter
+ * @idma: the adapter IDMA Monitor state
+ * @hz: number of ticks/second
+ * @ticks: number of ticks since the last IDMA Monitor call
+ */
+void t4_idma_monitor(struct adapter *adapter,
+ struct sge_idma_monitor_state *idma,
+ int hz, int ticks)
+{
+ int i, idma_same_state_cnt[2];
+
+ /* Read the SGE Debug Ingress DMA Same State Count registers. These
+ * are counters inside the SGE which count up on each clock when the
+ * SGE finds its Ingress DMA State Engines in the same states they
+ * were in the previous clock. The counters will peg out at
+ * 0xffffffff without wrapping around so once they pass the 1s
+ * threshold they'll stay above that till the IDMA state changes.
+ */
+ t4_write_reg(adapter, SGE_DEBUG_INDEX_A, 13);
+ idma_same_state_cnt[0] = t4_read_reg(adapter, SGE_DEBUG_DATA_HIGH_A);
+ idma_same_state_cnt[1] = t4_read_reg(adapter, SGE_DEBUG_DATA_LOW_A);
+
+ for (i = 0; i < 2; i++) {
+ u32 debug0, debug11;
+
+ /* If the Ingress DMA Same State Counter ("timer") is less
+ * than 1s, then we can reset our synthesized Stall Timer and
+ * continue. If we have previously emitted warnings about a
+ * potential stalled Ingress Queue, issue a note indicating
+ * that the Ingress Queue has resumed forward progress.
+ */
+ if (idma_same_state_cnt[i] < idma->idma_1s_thresh) {
+ if (idma->idma_stalled[i] >= SGE_IDMA_WARN_THRESH * hz)
+ dev_warn(adapter->pdev_dev, "SGE idma%d, queue %u, "
+ "resumed after %d seconds\n",
+ i, idma->idma_qid[i],
+ idma->idma_stalled[i] / hz);
+ idma->idma_stalled[i] = 0;
+ continue;
+ }
+
+ /* Synthesize an SGE Ingress DMA Same State Timer in the Hz
+ * domain. The first time we get here it'll be because we
+ * passed the 1s Threshold; each additional time it'll be
+ * because the RX Timer Callback is being fired on its regular
+ * schedule.
+ *
+ * If the stall is below our Potential Hung Ingress Queue
+ * Warning Threshold, continue.
+ */
+ if (idma->idma_stalled[i] == 0) {
+ idma->idma_stalled[i] = hz;
+ idma->idma_warn[i] = 0;
+ } else {
+ idma->idma_stalled[i] += ticks;
+ idma->idma_warn[i] -= ticks;
+ }
+
+ if (idma->idma_stalled[i] < SGE_IDMA_WARN_THRESH * hz)
+ continue;
+
+ /* We'll issue a warning every SGE_IDMA_WARN_REPEAT seconds.
+ */
+ if (idma->idma_warn[i] > 0)
+ continue;
+ idma->idma_warn[i] = SGE_IDMA_WARN_REPEAT * hz;
+
+ /* Read and save the SGE IDMA State and Queue ID information.
+ * We do this every time in case it changes across time ...
+ * can't be too careful ...
+ */
+ t4_write_reg(adapter, SGE_DEBUG_INDEX_A, 0);
+ debug0 = t4_read_reg(adapter, SGE_DEBUG_DATA_LOW_A);
+ idma->idma_state[i] = (debug0 >> (i * 9)) & 0x3f;
+
+ t4_write_reg(adapter, SGE_DEBUG_INDEX_A, 11);
+ debug11 = t4_read_reg(adapter, SGE_DEBUG_DATA_LOW_A);
+ idma->idma_qid[i] = (debug11 >> (i * 16)) & 0xffff;
+
+ dev_warn(adapter->pdev_dev, "SGE idma%u, queue %u, potentially stuck in "
+ "state %u for %d seconds (debug0=%#x, debug11=%#x)\n",
+ i, idma->idma_qid[i], idma->idma_state[i],
+ idma->idma_stalled[i] / hz,
+ debug0, debug11);
+ t4_sge_decode_idma_state(adapter, idma->idma_state[i]);
+ }
+}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
index 380b15c0417a..c8488f430d19 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
@@ -52,8 +52,6 @@ enum {
MBOX_LEN = 64, /* mailbox size in bytes */
TRACE_LEN = 112, /* length of trace data and mask */
FILTER_OPT_LEN = 36, /* filter tuple width for optional components */
- NWOL_PAT = 8, /* # of WoL patterns */
- WOL_PAT_LEN = 128, /* length of WoL patterns */
};
enum {
@@ -61,6 +59,8 @@ enum {
CIM_NUM_OBQ = 6, /* # of CIM OBQs */
CIM_NUM_OBQ_T5 = 8, /* # of CIM OBQs for T5 adapter */
CIMLA_SIZE = 2048, /* # of 32-bit words in CIM LA */
+ CIM_PIFLA_SIZE = 64, /* # of 192-bit words in CIM PIF LA */
+ CIM_MALA_SIZE = 64, /* # of 160-bit words in CIM MA LA */
CIM_IBQ_SIZE = 128, /* # of 128-bit words in a CIM IBQ */
CIM_OBQ_SIZE = 128, /* # of 128-bit words in a CIM OBQ */
TPLA_SIZE = 128, /* # of 64-bit words in TP LA */
@@ -152,17 +152,33 @@ struct rsp_ctrl {
};
};
-#define RSPD_NEWBUF 0x80000000U
-#define RSPD_LEN(x) (((x) >> 0) & 0x7fffffffU)
-#define RSPD_QID(x) RSPD_LEN(x)
+#define RSPD_NEWBUF_S 31
+#define RSPD_NEWBUF_V(x) ((x) << RSPD_NEWBUF_S)
+#define RSPD_NEWBUF_F RSPD_NEWBUF_V(1U)
-#define RSPD_GEN(x) ((x) >> 7)
-#define RSPD_TYPE(x) (((x) >> 4) & 3)
+#define RSPD_LEN_S 0
+#define RSPD_LEN_M 0x7fffffff
+#define RSPD_LEN_G(x) (((x) >> RSPD_LEN_S) & RSPD_LEN_M)
-#define V_QINTR_CNT_EN 0x0
-#define QINTR_CNT_EN 0x1
-#define QINTR_TIMER_IDX(x) ((x) << 1)
-#define QINTR_TIMER_IDX_GET(x) (((x) >> 1) & 0x7)
+#define RSPD_QID_S RSPD_LEN_S
+#define RSPD_QID_M RSPD_LEN_M
+#define RSPD_QID_G(x) RSPD_LEN_G(x)
+
+#define RSPD_GEN_S 7
+
+#define RSPD_TYPE_S 4
+#define RSPD_TYPE_M 0x3
+#define RSPD_TYPE_G(x) (((x) >> RSPD_TYPE_S) & RSPD_TYPE_M)
+
+/* Rx queue interrupt deferral fields: counter enable and timer index */
+#define QINTR_CNT_EN_S 0
+#define QINTR_CNT_EN_V(x) ((x) << QINTR_CNT_EN_S)
+#define QINTR_CNT_EN_F QINTR_CNT_EN_V(1U)
+
+#define QINTR_TIMER_IDX_S 1
+#define QINTR_TIMER_IDX_M 0x7
+#define QINTR_TIMER_IDX_V(x) ((x) << QINTR_TIMER_IDX_S)
+#define QINTR_TIMER_IDX_G(x) (((x) >> QINTR_TIMER_IDX_S) & QINTR_TIMER_IDX_M)
/*
* Flash layout.
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
index 30a2f56e99c2..132cb8fc0bf7 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
@@ -634,26 +634,9 @@ struct cpl_tid_release {
struct cpl_tx_pkt_core {
__be32 ctrl0;
-#define TXPKT_VF(x) ((x) << 0)
-#define TXPKT_PF(x) ((x) << 8)
-#define TXPKT_VF_VLD (1 << 11)
-#define TXPKT_OVLAN_IDX(x) ((x) << 12)
-#define TXPKT_INTF(x) ((x) << 16)
-#define TXPKT_INS_OVLAN (1 << 21)
-#define TXPKT_OPCODE(x) ((x) << 24)
__be16 pack;
__be16 len;
__be64 ctrl1;
-#define TXPKT_CSUM_END(x) ((x) << 12)
-#define TXPKT_CSUM_START(x) ((x) << 20)
-#define TXPKT_IPHDR_LEN(x) ((u64)(x) << 20)
-#define TXPKT_CSUM_LOC(x) ((u64)(x) << 30)
-#define TXPKT_ETHHDR_LEN(x) ((u64)(x) << 34)
-#define TXPKT_CSUM_TYPE(x) ((u64)(x) << 40)
-#define TXPKT_VLAN(x) ((u64)(x) << 44)
-#define TXPKT_VLAN_VLD (1ULL << 60)
-#define TXPKT_IPCSUM_DIS (1ULL << 62)
-#define TXPKT_L4CSUM_DIS (1ULL << 63)
};
struct cpl_tx_pkt {
@@ -663,16 +646,69 @@ struct cpl_tx_pkt {
#define cpl_tx_pkt_xt cpl_tx_pkt
+/* cpl_tx_pkt_core.ctrl0 fields */
+#define TXPKT_VF_S 0
+#define TXPKT_VF_V(x) ((x) << TXPKT_VF_S)
+
+#define TXPKT_PF_S 8
+#define TXPKT_PF_V(x) ((x) << TXPKT_PF_S)
+
+#define TXPKT_VF_VLD_S 11
+#define TXPKT_VF_VLD_V(x) ((x) << TXPKT_VF_VLD_S)
+#define TXPKT_VF_VLD_F TXPKT_VF_VLD_V(1U)
+
+#define TXPKT_OVLAN_IDX_S 12
+#define TXPKT_OVLAN_IDX_V(x) ((x) << TXPKT_OVLAN_IDX_S)
+
+#define TXPKT_INTF_S 16
+#define TXPKT_INTF_V(x) ((x) << TXPKT_INTF_S)
+
+#define TXPKT_INS_OVLAN_S 21
+#define TXPKT_INS_OVLAN_V(x) ((x) << TXPKT_INS_OVLAN_S)
+#define TXPKT_INS_OVLAN_F TXPKT_INS_OVLAN_V(1U)
+
+#define TXPKT_OPCODE_S 24
+#define TXPKT_OPCODE_V(x) ((x) << TXPKT_OPCODE_S)
+
+/* cpl_tx_pkt_core.ctrl1 fields */
+#define TXPKT_CSUM_END_S 12
+#define TXPKT_CSUM_END_V(x) ((x) << TXPKT_CSUM_END_S)
+
+#define TXPKT_CSUM_START_S 20
+#define TXPKT_CSUM_START_V(x) ((x) << TXPKT_CSUM_START_S)
+
+#define TXPKT_IPHDR_LEN_S 20
+#define TXPKT_IPHDR_LEN_V(x) ((__u64)(x) << TXPKT_IPHDR_LEN_S)
+
+#define TXPKT_CSUM_LOC_S 30
+#define TXPKT_CSUM_LOC_V(x) ((__u64)(x) << TXPKT_CSUM_LOC_S)
+
+#define TXPKT_ETHHDR_LEN_S 34
+#define TXPKT_ETHHDR_LEN_V(x) ((__u64)(x) << TXPKT_ETHHDR_LEN_S)
+
+#define T6_TXPKT_ETHHDR_LEN_S 32
+#define T6_TXPKT_ETHHDR_LEN_V(x) ((__u64)(x) << T6_TXPKT_ETHHDR_LEN_S)
+
+#define TXPKT_CSUM_TYPE_S 40
+#define TXPKT_CSUM_TYPE_V(x) ((__u64)(x) << TXPKT_CSUM_TYPE_S)
+
+#define TXPKT_VLAN_S 44
+#define TXPKT_VLAN_V(x) ((__u64)(x) << TXPKT_VLAN_S)
+
+#define TXPKT_VLAN_VLD_S 60
+#define TXPKT_VLAN_VLD_V(x) ((__u64)(x) << TXPKT_VLAN_VLD_S)
+#define TXPKT_VLAN_VLD_F TXPKT_VLAN_VLD_V(1ULL)
+
+#define TXPKT_IPCSUM_DIS_S 62
+#define TXPKT_IPCSUM_DIS_V(x) ((__u64)(x) << TXPKT_IPCSUM_DIS_S)
+#define TXPKT_IPCSUM_DIS_F TXPKT_IPCSUM_DIS_V(1ULL)
+
+#define TXPKT_L4CSUM_DIS_S 63
+#define TXPKT_L4CSUM_DIS_V(x) ((__u64)(x) << TXPKT_L4CSUM_DIS_S)
+#define TXPKT_L4CSUM_DIS_F TXPKT_L4CSUM_DIS_V(1ULL)
+
struct cpl_tx_pkt_lso_core {
__be32 lso_ctrl;
-#define LSO_TCPHDR_LEN(x) ((x) << 0)
-#define LSO_IPHDR_LEN(x) ((x) << 4)
-#define LSO_ETHHDR_LEN(x) ((x) << 16)
-#define LSO_IPV6(x) ((x) << 20)
-#define LSO_LAST_SLICE (1 << 22)
-#define LSO_FIRST_SLICE (1 << 23)
-#define LSO_OPCODE(x) ((x) << 24)
-#define LSO_T5_XFER_SIZE(x) ((x) << 0)
__be16 ipid_ofst;
__be16 mss;
__be32 seqno_offset;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h
index 1a9a6f334d2d..d7ca106927b0 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h
@@ -153,6 +153,8 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN
CH_PCI_ID_TABLE_FENTRY(0x5088), /* Custom T570-CR */
CH_PCI_ID_TABLE_FENTRY(0x5089), /* Custom T520-CR */
CH_PCI_ID_TABLE_FENTRY(0x5090), /* Custom T540-CR */
+ CH_PCI_ID_TABLE_FENTRY(0x5091), /* Custom T522-CR */
+ CH_PCI_ID_TABLE_FENTRY(0x5092), /* Custom T520-CR */
CH_PCI_DEVICE_ID_TABLE_DEFINE_END;
#endif /* __T4_PCI_ID_TBL_H__ */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
index 326674b19983..375a825573b0 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
@@ -418,6 +418,20 @@
#define SGE_INGRESS_QUEUES_PER_PAGE_PF_A 0x10f4
#define SGE_INGRESS_QUEUES_PER_PAGE_VF_A 0x10f8
+#define SGE_ERROR_STATS_A 0x1100
+
+#define UNCAPTURED_ERROR_S 18
+#define UNCAPTURED_ERROR_V(x) ((x) << UNCAPTURED_ERROR_S)
+#define UNCAPTURED_ERROR_F UNCAPTURED_ERROR_V(1U)
+
+#define ERROR_QID_VALID_S 17
+#define ERROR_QID_VALID_V(x) ((x) << ERROR_QID_VALID_S)
+#define ERROR_QID_VALID_F ERROR_QID_VALID_V(1U)
+
+#define ERROR_QID_S 0
+#define ERROR_QID_M 0x1ffffU
+#define ERROR_QID_G(x) (((x) >> ERROR_QID_S) & ERROR_QID_M)
+
#define HP_INT_THRESH_S 28
#define HP_INT_THRESH_M 0xfU
#define HP_INT_THRESH_V(x) ((x) << HP_INT_THRESH_S)
@@ -448,8 +462,13 @@
#define SGE_STAT_MATCH_A 0x10e8
#define SGE_STAT_CFG_A 0x10ec
+#define STATMODE_S 2
+#define STATMODE_V(x) ((x) << STATMODE_S)
+
#define STATSOURCE_T5_S 9
+#define STATSOURCE_T5_M 0xfU
#define STATSOURCE_T5_V(x) ((x) << STATSOURCE_T5_S)
+#define STATSOURCE_T5_G(x) (((x) >> STATSOURCE_T5_S) & STATSOURCE_T5_M)
#define SGE_DBFIFO_STATUS2_A 0x1118
@@ -705,6 +724,10 @@
#define REGISTER_S 0
#define REGISTER_V(x) ((x) << REGISTER_S)
+#define T6_ENABLE_S 31
+#define T6_ENABLE_V(x) ((x) << T6_ENABLE_S)
+#define T6_ENABLE_F T6_ENABLE_V(1U)
+
#define PFNUM_S 0
#define PFNUM_V(x) ((x) << PFNUM_S)
@@ -1338,6 +1361,42 @@
#define FLMTXFLSTEMPTY_V(x) ((x) << FLMTXFLSTEMPTY_S)
#define FLMTXFLSTEMPTY_F FLMTXFLSTEMPTY_V(1U)
+#define TP_TX_ORATE_A 0x7ebc
+
+#define OFDRATE3_S 24
+#define OFDRATE3_M 0xffU
+#define OFDRATE3_G(x) (((x) >> OFDRATE3_S) & OFDRATE3_M)
+
+#define OFDRATE2_S 16
+#define OFDRATE2_M 0xffU
+#define OFDRATE2_G(x) (((x) >> OFDRATE2_S) & OFDRATE2_M)
+
+#define OFDRATE1_S 8
+#define OFDRATE1_M 0xffU
+#define OFDRATE1_G(x) (((x) >> OFDRATE1_S) & OFDRATE1_M)
+
+#define OFDRATE0_S 0
+#define OFDRATE0_M 0xffU
+#define OFDRATE0_G(x) (((x) >> OFDRATE0_S) & OFDRATE0_M)
+
+#define TP_TX_TRATE_A 0x7ed0
+
+#define TNLRATE3_S 24
+#define TNLRATE3_M 0xffU
+#define TNLRATE3_G(x) (((x) >> TNLRATE3_S) & TNLRATE3_M)
+
+#define TNLRATE2_S 16
+#define TNLRATE2_M 0xffU
+#define TNLRATE2_G(x) (((x) >> TNLRATE2_S) & TNLRATE2_M)
+
+#define TNLRATE1_S 8
+#define TNLRATE1_M 0xffU
+#define TNLRATE1_G(x) (((x) >> TNLRATE1_S) & TNLRATE1_M)
+
+#define TNLRATE0_S 0
+#define TNLRATE0_M 0xffU
+#define TNLRATE0_G(x) (((x) >> TNLRATE0_S) & TNLRATE0_M)
+
#define TP_VLAN_PRI_MAP_A 0x140
#define FRAGMENTATION_S 9
@@ -1399,6 +1458,8 @@
#define CSUM_HAS_PSEUDO_HDR_F CSUM_HAS_PSEUDO_HDR_V(1U)
#define TP_MIB_MAC_IN_ERR_0_A 0x0
+#define TP_MIB_HDR_IN_ERR_0_A 0x4
+#define TP_MIB_TCP_IN_ERR_0_A 0x8
#define TP_MIB_TCP_OUT_RST_A 0xc
#define TP_MIB_TCP_IN_SEG_HI_A 0x10
#define TP_MIB_TCP_IN_SEG_LO_A 0x11
@@ -1407,11 +1468,19 @@
#define TP_MIB_TCP_RXT_SEG_HI_A 0x14
#define TP_MIB_TCP_RXT_SEG_LO_A 0x15
#define TP_MIB_TNL_CNG_DROP_0_A 0x18
+#define TP_MIB_OFD_CHN_DROP_0_A 0x1c
#define TP_MIB_TCP_V6IN_ERR_0_A 0x28
#define TP_MIB_TCP_V6OUT_RST_A 0x2c
#define TP_MIB_OFD_ARP_DROP_A 0x36
+#define TP_MIB_CPL_IN_REQ_0_A 0x38
+#define TP_MIB_CPL_OUT_RSP_0_A 0x3c
#define TP_MIB_TNL_DROP_0_A 0x44
+#define TP_MIB_FCOE_DDP_0_A 0x48
+#define TP_MIB_FCOE_DROP_0_A 0x4c
+#define TP_MIB_FCOE_BYTE_0_HI_A 0x50
#define TP_MIB_OFD_VLN_DROP_0_A 0x58
+#define TP_MIB_USM_PKTS_A 0x5c
+#define TP_MIB_RQE_DFR_PKT_A 0x64
#define ULP_TX_INT_CAUSE_A 0x8dcc
@@ -1572,6 +1641,7 @@
#define MPS_PORT_STAT_LB_PORT_1519B_MAX_L 0x520
#define MPS_PORT_STAT_LB_PORT_1519B_MAX_H 0x524
#define MPS_PORT_STAT_LB_PORT_DROP_FRAMES 0x528
+#define MPS_PORT_STAT_LB_PORT_DROP_FRAMES_L 0x528
#define MPS_PORT_STAT_RX_PORT_BYTES_L 0x540
#define MPS_PORT_STAT_RX_PORT_BYTES_H 0x544
#define MPS_PORT_STAT_RX_PORT_FRAMES_L 0x548
@@ -2054,6 +2124,11 @@
#define VFLKPIDX_M 0xffU
#define VFLKPIDX_G(x) (((x) >> VFLKPIDX_S) & VFLKPIDX_M)
+#define T6_VFWRADDR_S 8
+#define T6_VFWRADDR_M 0xffU
+#define T6_VFWRADDR_V(x) ((x) << T6_VFWRADDR_S)
+#define T6_VFWRADDR_G(x) (((x) >> T6_VFWRADDR_S) & T6_VFWRADDR_M)
+
#define TP_RSS_CONFIG_CNG_A 0x7e04
#define TP_RSS_SECRET_KEY0_A 0x40
#define TP_RSS_PF0_CONFIG_A 0x30
@@ -2175,7 +2250,28 @@
#define MPS_RX_PERR_INT_CAUSE_A 0x11074
#define MPS_CLS_TCAM_Y_L_A 0xf000
+#define MPS_CLS_TCAM_DATA0_A 0xf000
+#define MPS_CLS_TCAM_DATA1_A 0xf004
+
+#define DMACH_S 0
+#define DMACH_M 0xffffU
+#define DMACH_G(x) (((x) >> DMACH_S) & DMACH_M)
+
#define MPS_CLS_TCAM_X_L_A 0xf008
+#define MPS_CLS_TCAM_DATA2_CTL_A 0xf008
+
+#define CTLCMDTYPE_S 31
+#define CTLCMDTYPE_V(x) ((x) << CTLCMDTYPE_S)
+#define CTLCMDTYPE_F CTLCMDTYPE_V(1U)
+
+#define CTLTCAMSEL_S 25
+#define CTLTCAMSEL_V(x) ((x) << CTLTCAMSEL_S)
+
+#define CTLTCAMINDEX_S 17
+#define CTLTCAMINDEX_V(x) ((x) << CTLTCAMINDEX_S)
+
+#define CTLXYBITSEL_S 16
+#define CTLXYBITSEL_V(x) ((x) << CTLXYBITSEL_S)
#define MPS_CLS_TCAM_Y_L(idx) (MPS_CLS_TCAM_Y_L_A + (idx) * 16)
#define NUM_MPS_CLS_TCAM_Y_L_INSTANCES 512
@@ -2184,6 +2280,45 @@
#define NUM_MPS_CLS_TCAM_X_L_INSTANCES 512
#define MPS_CLS_SRAM_L_A 0xe000
+
+#define T6_MULTILISTEN0_S 26
+
+#define T6_SRAM_PRIO3_S 23
+#define T6_SRAM_PRIO3_M 0x7U
+#define T6_SRAM_PRIO3_G(x) (((x) >> T6_SRAM_PRIO3_S) & T6_SRAM_PRIO3_M)
+
+#define T6_SRAM_PRIO2_S 20
+#define T6_SRAM_PRIO2_M 0x7U
+#define T6_SRAM_PRIO2_G(x) (((x) >> T6_SRAM_PRIO2_S) & T6_SRAM_PRIO2_M)
+
+#define T6_SRAM_PRIO1_S 17
+#define T6_SRAM_PRIO1_M 0x7U
+#define T6_SRAM_PRIO1_G(x) (((x) >> T6_SRAM_PRIO1_S) & T6_SRAM_PRIO1_M)
+
+#define T6_SRAM_PRIO0_S 14
+#define T6_SRAM_PRIO0_M 0x7U
+#define T6_SRAM_PRIO0_G(x) (((x) >> T6_SRAM_PRIO0_S) & T6_SRAM_PRIO0_M)
+
+#define T6_SRAM_VLD_S 13
+#define T6_SRAM_VLD_V(x) ((x) << T6_SRAM_VLD_S)
+#define T6_SRAM_VLD_F T6_SRAM_VLD_V(1U)
+
+#define T6_REPLICATE_S 12
+#define T6_REPLICATE_V(x) ((x) << T6_REPLICATE_S)
+#define T6_REPLICATE_F T6_REPLICATE_V(1U)
+
+#define T6_PF_S 9
+#define T6_PF_M 0x7U
+#define T6_PF_G(x) (((x) >> T6_PF_S) & T6_PF_M)
+
+#define T6_VF_VALID_S 8
+#define T6_VF_VALID_V(x) ((x) << T6_VF_VALID_S)
+#define T6_VF_VALID_F T6_VF_VALID_V(1U)
+
+#define T6_VF_S 0
+#define T6_VF_M 0xffU
+#define T6_VF_G(x) (((x) >> T6_VF_S) & T6_VF_M)
+
#define MPS_CLS_SRAM_H_A 0xe004
#define MPS_CLS_SRAM_L(idx) (MPS_CLS_SRAM_L_A + (idx) * 8)
@@ -2433,6 +2568,8 @@
#define CIM_F CIM_V(1U)
#define MC1_S 31
+#define MC1_V(x) ((x) << MC1_S)
+#define MC1_F MC1_V(1U)
#define PL_INT_ENABLE_A 0x19410
#define PL_INT_MAP0_A 0x19414
@@ -2463,6 +2600,18 @@
#define REV_V(x) ((x) << REV_S)
#define REV_G(x) (((x) >> REV_S) & REV_M)
+#define T6_UNKNOWNCMD_S 3
+#define T6_UNKNOWNCMD_V(x) ((x) << T6_UNKNOWNCMD_S)
+#define T6_UNKNOWNCMD_F T6_UNKNOWNCMD_V(1U)
+
+#define T6_LIP0_S 2
+#define T6_LIP0_V(x) ((x) << T6_LIP0_S)
+#define T6_LIP0_F T6_LIP0_V(1U)
+
+#define T6_LIPMISS_S 1
+#define T6_LIPMISS_V(x) ((x) << T6_LIPMISS_S)
+#define T6_LIPMISS_F T6_LIPMISS_V(1U)
+
#define LE_DB_INT_CAUSE_A 0x19c3c
#define REQQPARERR_S 16
@@ -2485,6 +2634,14 @@
#define LIP0_V(x) ((x) << LIP0_S)
#define LIP0_F LIP0_V(1U)
+#define TCAMINTPERR_S 13
+#define TCAMINTPERR_V(x) ((x) << TCAMINTPERR_S)
+#define TCAMINTPERR_F TCAMINTPERR_V(1U)
+
+#define SSRAMINTPERR_S 10
+#define SSRAMINTPERR_V(x) ((x) << SSRAMINTPERR_S)
+#define SSRAMINTPERR_F SSRAMINTPERR_V(1U)
+
#define NCSI_INT_CAUSE_A 0x1a0d8
#define CIM_DM_PRTY_ERR_S 8
@@ -2638,6 +2795,33 @@
#define CIM_IBQ_DBG_DATA_A 0x7b68
#define CIM_OBQ_DBG_DATA_A 0x7b6c
+#define CIM_DEBUGCFG_A 0x7b70
+#define CIM_DEBUGSTS_A 0x7b74
+
+#define POLADBGRDPTR_S 23
+#define POLADBGRDPTR_M 0x1ffU
+#define POLADBGRDPTR_V(x) ((x) << POLADBGRDPTR_S)
+
+#define POLADBGWRPTR_S 16
+#define POLADBGWRPTR_M 0x1ffU
+#define POLADBGWRPTR_G(x) (((x) >> POLADBGWRPTR_S) & POLADBGWRPTR_M)
+
+#define PILADBGRDPTR_S 14
+#define PILADBGRDPTR_M 0x1ffU
+#define PILADBGRDPTR_V(x) ((x) << PILADBGRDPTR_S)
+
+#define PILADBGWRPTR_S 0
+#define PILADBGWRPTR_M 0x1ffU
+#define PILADBGWRPTR_G(x) (((x) >> PILADBGWRPTR_S) & PILADBGWRPTR_M)
+
+#define LADBGEN_S 12
+#define LADBGEN_V(x) ((x) << LADBGEN_S)
+#define LADBGEN_F LADBGEN_V(1U)
+
+#define CIM_PO_LA_DEBUGDATA_A 0x7b78
+#define CIM_PI_LA_DEBUGDATA_A 0x7b7c
+#define CIM_PO_LA_MADEBUGDATA_A 0x7b80
+#define CIM_PI_LA_MADEBUGDATA_A 0x7b84
#define UPDBGLARDEN_S 1
#define UPDBGLARDEN_V(x) ((x) << UPDBGLARDEN_S)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h
index 19b2dcf6acde..7bdee3bf75ec 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h
@@ -61,6 +61,30 @@
#define SGE_TIMERREGS 6
#define TIMERREG_COUNTER0_X 0
+#define FETCHBURSTMIN_64B_X 2
+
+#define FETCHBURSTMAX_256B_X 2
+#define FETCHBURSTMAX_512B_X 3
+
+#define HOSTFCMODE_STATUS_PAGE_X 2
+
+#define CIDXFLUSHTHRESH_32_X 5
+
+#define UPDATEDELIVERY_INTERRUPT_X 1
+
+#define RSPD_TYPE_FLBUF_X 0
+#define RSPD_TYPE_CPL_X 1
+#define RSPD_TYPE_INTR_X 2
+
+/* Congestion Manager Definitions.
+ */
+#define CONMCTXT_CNGTPMODE_S 19
+#define CONMCTXT_CNGTPMODE_V(x) ((x) << CONMCTXT_CNGTPMODE_S)
+#define CONMCTXT_CNGCHMAP_S 0
+#define CONMCTXT_CNGCHMAP_V(x) ((x) << CONMCTXT_CNGCHMAP_S)
+#define CONMCTXT_CNGTPMODE_CHANNEL_X 2
+#define CONMCTXT_CNGTPMODE_QUEUE_X 1
+
/* T5 and later support a new BAR2-based doorbell mechanism for Egress Queues.
* The User Doorbells are each 128 bytes in length with a Simple Doorbell at
* offsets 8x and a Write Combining single 64-byte Egress Queue Unit
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
index 03fbfd1fb3df..ab4674684acc 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
@@ -772,7 +772,7 @@ struct fw_ldst_cmd {
} addrval;
struct fw_ldst_idctxt {
__be32 physid;
- __be32 msg_pkd;
+ __be32 msg_ctxtflush;
__be32 ctxt_data7;
__be32 ctxt_data6;
__be32 ctxt_data5;
@@ -788,15 +788,27 @@ struct fw_ldst_cmd {
__be16 vctl;
__be16 rval;
} mdio;
- struct fw_ldst_mps {
- __be16 fid_ctl;
- __be16 rplcpf_pkd;
- __be32 rplc127_96;
- __be32 rplc95_64;
- __be32 rplc63_32;
- __be32 rplc31_0;
- __be32 atrb;
- __be16 vlan[16];
+ union fw_ldst_mps {
+ struct fw_ldst_mps_rplc {
+ __be16 fid_idx;
+ __be16 rplcpf_pkd;
+ __be32 rplc255_224;
+ __be32 rplc223_192;
+ __be32 rplc191_160;
+ __be32 rplc159_128;
+ __be32 rplc127_96;
+ __be32 rplc95_64;
+ __be32 rplc63_32;
+ __be32 rplc31_0;
+ } rplc;
+ struct fw_ldst_mps_atrb {
+ __be16 fid_mpsid;
+ __be16 r2[3];
+ __be32 r3[2];
+ __be32 r4;
+ __be32 atrb;
+ __be16 vlan[16];
+ } atrb;
} mps;
struct fw_ldst_func {
u8 access_ctl;
@@ -822,6 +834,10 @@ struct fw_ldst_cmd {
#define FW_LDST_CMD_MSG_S 31
#define FW_LDST_CMD_MSG_V(x) ((x) << FW_LDST_CMD_MSG_S)
+#define FW_LDST_CMD_CTXTFLUSH_S 30
+#define FW_LDST_CMD_CTXTFLUSH_V(x) ((x) << FW_LDST_CMD_CTXTFLUSH_S)
+#define FW_LDST_CMD_CTXTFLUSH_F FW_LDST_CMD_CTXTFLUSH_V(1U)
+
#define FW_LDST_CMD_PADDR_S 8
#define FW_LDST_CMD_PADDR_V(x) ((x) << FW_LDST_CMD_PADDR_S)
@@ -831,8 +847,8 @@ struct fw_ldst_cmd {
#define FW_LDST_CMD_FID_S 15
#define FW_LDST_CMD_FID_V(x) ((x) << FW_LDST_CMD_FID_S)
-#define FW_LDST_CMD_CTL_S 0
-#define FW_LDST_CMD_CTL_V(x) ((x) << FW_LDST_CMD_CTL_S)
+#define FW_LDST_CMD_IDX_S 0
+#define FW_LDST_CMD_IDX_V(x) ((x) << FW_LDST_CMD_IDX_S)
#define FW_LDST_CMD_RPLCPF_S 0
#define FW_LDST_CMD_RPLCPF_V(x) ((x) << FW_LDST_CMD_RPLCPF_S)
@@ -1061,6 +1077,7 @@ enum fw_params_param_dev {
FW_PARAMS_PARAM_DEV_FWREV = 0x0B,
FW_PARAMS_PARAM_DEV_TPREV = 0x0C,
FW_PARAMS_PARAM_DEV_CF = 0x0D,
+ FW_PARAMS_PARAM_DEV_PHYFW = 0x0F,
FW_PARAMS_PARAM_DEV_DIAG = 0x11,
FW_PARAMS_PARAM_DEV_MAXORDIRD_QP = 0x13, /* max supported QP IRD/ORD */
FW_PARAMS_PARAM_DEV_MAXIRD_ADAPTER = 0x14, /* max supported adap IRD */
@@ -1123,6 +1140,12 @@ enum fw_params_param_dmaq {
FW_PARAMS_PARAM_DMAQ_EQ_CMPLIQID_CTRL = 0x11,
FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH = 0x12,
FW_PARAMS_PARAM_DMAQ_EQ_DCBPRIO_ETH = 0x13,
+ FW_PARAMS_PARAM_DMAQ_CONM_CTXT = 0x20,
+};
+
+enum fw_params_param_dev_phyfw {
+ FW_PARAMS_PARAM_DEV_PHYFW_DOWNLOAD = 0x00,
+ FW_PARAMS_PARAM_DEV_PHYFW_VERSION = 0x01,
};
enum fw_params_param_dev_diag {
@@ -1377,6 +1400,7 @@ struct fw_iq_cmd {
#define FW_IQ_CMD_IQFLINTCONGEN_S 27
#define FW_IQ_CMD_IQFLINTCONGEN_V(x) ((x) << FW_IQ_CMD_IQFLINTCONGEN_S)
+#define FW_IQ_CMD_IQFLINTCONGEN_F FW_IQ_CMD_IQFLINTCONGEN_V(1U)
#define FW_IQ_CMD_IQFLINTISCSIC_S 26
#define FW_IQ_CMD_IQFLINTISCSIC_V(x) ((x) << FW_IQ_CMD_IQFLINTISCSIC_S)
@@ -1399,6 +1423,7 @@ struct fw_iq_cmd {
#define FW_IQ_CMD_FL0CONGCIF_S 11
#define FW_IQ_CMD_FL0CONGCIF_V(x) ((x) << FW_IQ_CMD_FL0CONGCIF_S)
+#define FW_IQ_CMD_FL0CONGCIF_F FW_IQ_CMD_FL0CONGCIF_V(1U)
#define FW_IQ_CMD_FL0ONCHIP_S 10
#define FW_IQ_CMD_FL0ONCHIP_V(x) ((x) << FW_IQ_CMD_FL0ONCHIP_S)
@@ -1589,6 +1614,7 @@ struct fw_eq_eth_cmd {
#define FW_EQ_ETH_CMD_FETCHRO_S 22
#define FW_EQ_ETH_CMD_FETCHRO_V(x) ((x) << FW_EQ_ETH_CMD_FETCHRO_S)
+#define FW_EQ_ETH_CMD_FETCHRO_F FW_EQ_ETH_CMD_FETCHRO_V(1U)
#define FW_EQ_ETH_CMD_HOSTFCMODE_S 20
#define FW_EQ_ETH_CMD_HOSTFCMODE_V(x) ((x) << FW_EQ_ETH_CMD_HOSTFCMODE_S)
@@ -2526,13 +2552,8 @@ enum fw_port_mod_sub_type {
FW_PORT_MOD_SUB_TYPE_TWINAX_7 = 0xC,
};
-/* port stats */
-#define FW_NUM_PORT_STATS 50
-#define FW_NUM_PORT_TX_STATS 23
-#define FW_NUM_PORT_RX_STATS 27
-
enum fw_port_stats_tx_index {
- FW_STAT_TX_PORT_BYTES_IX,
+ FW_STAT_TX_PORT_BYTES_IX = 0,
FW_STAT_TX_PORT_FRAMES_IX,
FW_STAT_TX_PORT_BCAST_IX,
FW_STAT_TX_PORT_MCAST_IX,
@@ -2554,11 +2575,12 @@ enum fw_port_stats_tx_index {
FW_STAT_TX_PORT_PPP4_IX,
FW_STAT_TX_PORT_PPP5_IX,
FW_STAT_TX_PORT_PPP6_IX,
- FW_STAT_TX_PORT_PPP7_IX
+ FW_STAT_TX_PORT_PPP7_IX,
+ FW_NUM_PORT_TX_STATS
};
enum fw_port_stat_rx_index {
- FW_STAT_RX_PORT_BYTES_IX,
+ FW_STAT_RX_PORT_BYTES_IX = 0,
FW_STAT_RX_PORT_FRAMES_IX,
FW_STAT_RX_PORT_BCAST_IX,
FW_STAT_RX_PORT_MCAST_IX,
@@ -2584,9 +2606,14 @@ enum fw_port_stat_rx_index {
FW_STAT_RX_PORT_PPP5_IX,
FW_STAT_RX_PORT_PPP6_IX,
FW_STAT_RX_PORT_PPP7_IX,
- FW_STAT_RX_PORT_LESS_64B_IX
+ FW_STAT_RX_PORT_LESS_64B_IX,
+ FW_STAT_RX_PORT_MAC_ERROR_IX,
+ FW_NUM_PORT_RX_STATS
};
+/* port stats */
+#define FW_NUM_PORT_STATS (FW_NUM_PORT_TX_STATS + FW_NUM_PORT_RX_STATS)
+
struct fw_port_stats_cmd {
__be32 op_to_portid;
__be32 retval_len16;
@@ -3015,7 +3042,8 @@ struct fw_hdr {
enum fw_hdr_chip {
FW_HDR_CHIP_T4,
- FW_HDR_CHIP_T5
+ FW_HDR_CHIP_T5,
+ FW_HDR_CHIP_T6
};
#define FW_HDR_FW_VER_MAJOR_S 24
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h
index b9d1cbac0eee..32b213559b02 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h
@@ -45,4 +45,9 @@
#define T5FW_VERSION_MICRO 0x20
#define T5FW_VERSION_BUILD 0x00
+#define T6FW_VERSION_MAJOR 0x01
+#define T6FW_VERSION_MINOR 0x0D
+#define T6FW_VERSION_MICRO 0x2D
+#define T6FW_VERSION_BUILD 0x00
+
#endif
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
index 1d893b0b7ddf..b2b5e5bbe04c 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
@@ -1021,7 +1021,7 @@ static int closest_thres(const struct sge *s, int thres)
static unsigned int qtimer_val(const struct adapter *adapter,
const struct sge_rspq *rspq)
{
- unsigned int timer_idx = QINTR_TIMER_IDX_GET(rspq->intr_params);
+ unsigned int timer_idx = QINTR_TIMER_IDX_G(rspq->intr_params);
return timer_idx < SGE_NTIMERS
? adapter->sge.timer_val[timer_idx]
@@ -1086,8 +1086,8 @@ static int set_rxq_intr_params(struct adapter *adapter, struct sge_rspq *rspq,
* Update the response queue's interrupt coalescing parameters and
* return success.
*/
- rspq->intr_params = (QINTR_TIMER_IDX(timer_idx) |
- (cnt > 0 ? QINTR_CNT_EN : 0));
+ rspq->intr_params = (QINTR_TIMER_IDX_V(timer_idx) |
+ QINTR_CNT_EN_V(cnt > 0));
return 0;
}
@@ -1439,7 +1439,7 @@ static int cxgb4vf_get_coalesce(struct net_device *dev,
coalesce->rx_coalesce_usecs = qtimer_val(adapter, rspq);
coalesce->rx_max_coalesced_frames =
- ((rspq->intr_params & QINTR_CNT_EN)
+ ((rspq->intr_params & QINTR_CNT_EN_F)
? adapter->sge.counter_val[rspq->pktcnt_idx]
: 0);
return 0;
@@ -2393,8 +2393,9 @@ static inline void init_rspq(struct sge_rspq *rspq, u8 timer_idx,
u8 pkt_cnt_idx, unsigned int size,
unsigned int iqe_size)
{
- rspq->intr_params = (QINTR_TIMER_IDX(timer_idx) |
- (pkt_cnt_idx < SGE_NCOUNTERS ? QINTR_CNT_EN : 0));
+ rspq->intr_params = (QINTR_TIMER_IDX_V(timer_idx) |
+ (pkt_cnt_idx < SGE_NCOUNTERS ?
+ QINTR_CNT_EN_F : 0));
rspq->pktcnt_idx = (pkt_cnt_idx < SGE_NCOUNTERS
? pkt_cnt_idx
: 0);
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
index 482f6de6817d..ad53e5ad2acd 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
@@ -524,7 +524,7 @@ static void unmap_rx_buf(struct adapter *adapter, struct sge_fl *fl)
*/
static inline void ring_fl_db(struct adapter *adapter, struct sge_fl *fl)
{
- u32 val;
+ u32 val = adapter->params.arch.sge_fl_db;
/* The SGE keeps track of its Producer and Consumer Indices in terms
* of Egress Queue Units so we can only tell it about integral numbers
@@ -532,11 +532,9 @@ static inline void ring_fl_db(struct adapter *adapter, struct sge_fl *fl)
*/
if (fl->pend_cred >= FL_PER_EQ_UNIT) {
if (is_t4(adapter->params.chip))
- val = PIDX_V(fl->pend_cred / FL_PER_EQ_UNIT);
+ val |= PIDX_V(fl->pend_cred / FL_PER_EQ_UNIT);
else
- val = PIDX_T5_V(fl->pend_cred / FL_PER_EQ_UNIT) |
- DBTYPE_F;
- val |= DBPRIO_F;
+ val |= PIDX_T5_V(fl->pend_cred / FL_PER_EQ_UNIT);
/* Make sure all memory writes to the Free List queue are
* committed before we tell the hardware about them.
@@ -1084,7 +1082,7 @@ static void inline_tx_skb(const struct sk_buff *skb, const struct sge_txq *tq,
* Figure out what HW csum a packet wants and return the appropriate control
* bits.
*/
-static u64 hwcsum(const struct sk_buff *skb)
+static u64 hwcsum(enum chip_type chip, const struct sk_buff *skb)
{
int csum_type;
const struct iphdr *iph = ip_hdr(skb);
@@ -1100,7 +1098,7 @@ nocsum:
* unknown protocol, disable HW csum
* and hope a bad packet is detected
*/
- return TXPKT_L4CSUM_DIS;
+ return TXPKT_L4CSUM_DIS_F;
}
} else {
/*
@@ -1116,16 +1114,21 @@ nocsum:
goto nocsum;
}
- if (likely(csum_type >= TX_CSUM_TCPIP))
- return TXPKT_CSUM_TYPE(csum_type) |
- TXPKT_IPHDR_LEN(skb_network_header_len(skb)) |
- TXPKT_ETHHDR_LEN(skb_network_offset(skb) - ETH_HLEN);
- else {
+ if (likely(csum_type >= TX_CSUM_TCPIP)) {
+ u64 hdr_len = TXPKT_IPHDR_LEN_V(skb_network_header_len(skb));
+ int eth_hdr_len = skb_network_offset(skb) - ETH_HLEN;
+
+ if (chip <= CHELSIO_T5)
+ hdr_len |= TXPKT_ETHHDR_LEN_V(eth_hdr_len);
+ else
+ hdr_len |= T6_TXPKT_ETHHDR_LEN_V(eth_hdr_len);
+ return TXPKT_CSUM_TYPE_V(csum_type) | hdr_len;
+ } else {
int start = skb_transport_offset(skb);
- return TXPKT_CSUM_TYPE(csum_type) |
- TXPKT_CSUM_START(start) |
- TXPKT_CSUM_LOC(start + skb->csum_offset);
+ return TXPKT_CSUM_TYPE_V(csum_type) |
+ TXPKT_CSUM_START_V(start) |
+ TXPKT_CSUM_LOC_V(start + skb->csum_offset);
}
}
@@ -1160,7 +1163,7 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
{
u32 wr_mid;
u64 cntrl, *end;
- int qidx, credits;
+ int qidx, credits, max_pkt_len;
unsigned int flits, ndesc;
struct adapter *adapter;
struct sge_eth_txq *txq;
@@ -1183,6 +1186,13 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(skb->len < fw_hdr_copy_len))
goto out_free;
+ /* Discard the packet if the length is greater than mtu */
+ max_pkt_len = ETH_HLEN + dev->mtu;
+ if (skb_vlan_tag_present(skb))
+ max_pkt_len += VLAN_HLEN;
+ if (!skb_shinfo(skb)->gso_size && (unlikely(skb->len > max_pkt_len)))
+ goto out_free;
+
/*
* Figure out which TX Queue we're going to use.
*/
@@ -1281,29 +1291,35 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
* Fill in the LSO CPL message.
*/
lso->lso_ctrl =
- cpu_to_be32(LSO_OPCODE(CPL_TX_PKT_LSO) |
- LSO_FIRST_SLICE |
- LSO_LAST_SLICE |
- LSO_IPV6(v6) |
- LSO_ETHHDR_LEN(eth_xtra_len/4) |
- LSO_IPHDR_LEN(l3hdr_len/4) |
- LSO_TCPHDR_LEN(tcp_hdr(skb)->doff));
+ cpu_to_be32(LSO_OPCODE_V(CPL_TX_PKT_LSO) |
+ LSO_FIRST_SLICE_F |
+ LSO_LAST_SLICE_F |
+ LSO_IPV6_V(v6) |
+ LSO_ETHHDR_LEN_V(eth_xtra_len / 4) |
+ LSO_IPHDR_LEN_V(l3hdr_len / 4) |
+ LSO_TCPHDR_LEN_V(tcp_hdr(skb)->doff));
lso->ipid_ofst = cpu_to_be16(0);
lso->mss = cpu_to_be16(ssi->gso_size);
lso->seqno_offset = cpu_to_be32(0);
if (is_t4(adapter->params.chip))
lso->len = cpu_to_be32(skb->len);
else
- lso->len = cpu_to_be32(LSO_T5_XFER_SIZE(skb->len));
+ lso->len = cpu_to_be32(LSO_T5_XFER_SIZE_V(skb->len));
/*
* Set up TX Packet CPL pointer, control word and perform
* accounting.
*/
cpl = (void *)(lso + 1);
- cntrl = (TXPKT_CSUM_TYPE(v6 ? TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) |
- TXPKT_IPHDR_LEN(l3hdr_len) |
- TXPKT_ETHHDR_LEN(eth_xtra_len));
+
+ if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5)
+ cntrl = TXPKT_ETHHDR_LEN_V(eth_xtra_len);
+ else
+ cntrl = T6_TXPKT_ETHHDR_LEN_V(eth_xtra_len);
+
+ cntrl |= TXPKT_CSUM_TYPE_V(v6 ?
+ TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) |
+ TXPKT_IPHDR_LEN_V(l3hdr_len);
txq->tso++;
txq->tx_cso += ssi->gso_segs;
} else {
@@ -1320,10 +1336,11 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
*/
cpl = (void *)(wr + 1);
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- cntrl = hwcsum(skb) | TXPKT_IPCSUM_DIS;
+ cntrl = hwcsum(adapter->params.chip, skb) |
+ TXPKT_IPCSUM_DIS_F;
txq->tx_cso++;
} else
- cntrl = TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS;
+ cntrl = TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F;
}
/*
@@ -1332,15 +1349,15 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
*/
if (skb_vlan_tag_present(skb)) {
txq->vlan_ins++;
- cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(skb_vlan_tag_get(skb));
+ cntrl |= TXPKT_VLAN_VLD_F | TXPKT_VLAN_V(skb_vlan_tag_get(skb));
}
/*
* Fill in the TX Packet CPL message header.
*/
- cpl->ctrl0 = cpu_to_be32(TXPKT_OPCODE(CPL_TX_PKT_XT) |
- TXPKT_INTF(pi->port_id) |
- TXPKT_PF(0));
+ cpl->ctrl0 = cpu_to_be32(TXPKT_OPCODE_V(CPL_TX_PKT_XT) |
+ TXPKT_INTF_V(pi->port_id) |
+ TXPKT_PF_V(0));
cpl->pack = cpu_to_be16(0);
cpl->len = cpu_to_be16(skb->len);
cpl->ctrl1 = cpu_to_be64(cntrl);
@@ -1663,7 +1680,7 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
static inline bool is_new_response(const struct rsp_ctrl *rc,
const struct sge_rspq *rspq)
{
- return RSPD_GEN(rc->type_gen) == rspq->gen;
+ return ((rc->type_gen >> RSPD_GEN_S) & 0x1) == rspq->gen;
}
/**
@@ -1752,8 +1769,8 @@ static int process_responses(struct sge_rspq *rspq, int budget)
* SGE.
*/
dma_rmb();
- rsp_type = RSPD_TYPE(rc->type_gen);
- if (likely(rsp_type == RSP_TYPE_FLBUF)) {
+ rsp_type = RSPD_TYPE_G(rc->type_gen);
+ if (likely(rsp_type == RSPD_TYPE_FLBUF_X)) {
struct page_frag *fp;
struct pkt_gl gl;
const struct rx_sw_desc *sdesc;
@@ -1764,7 +1781,7 @@ static int process_responses(struct sge_rspq *rspq, int budget)
* If we get a "new buffer" message from the SGE we
* need to move on to the next Free List buffer.
*/
- if (len & RSPD_NEWBUF) {
+ if (len & RSPD_NEWBUF_F) {
/*
* We get one "new buffer" message when we
* first start up a queue so we need to ignore
@@ -1775,7 +1792,7 @@ static int process_responses(struct sge_rspq *rspq, int budget)
1);
rspq->offset = 0;
}
- len = RSPD_LEN(len);
+ len = RSPD_LEN_G(len);
}
gl.tot_len = len;
@@ -1818,10 +1835,10 @@ static int process_responses(struct sge_rspq *rspq, int budget)
rspq->offset += ALIGN(fp->size, s->fl_align);
else
restore_rx_bufs(&gl, &rxq->fl, frag);
- } else if (likely(rsp_type == RSP_TYPE_CPL)) {
+ } else if (likely(rsp_type == RSPD_TYPE_CPL_X)) {
ret = rspq->handler(rspq, rspq->cur_desc, NULL);
} else {
- WARN_ON(rsp_type > RSP_TYPE_CPL);
+ WARN_ON(rsp_type > RSPD_TYPE_CPL_X);
ret = 0;
}
@@ -1833,7 +1850,7 @@ static int process_responses(struct sge_rspq *rspq, int budget)
*/
const int NOMEM_TIMER_IDX = SGE_NTIMERS-1;
rspq->next_intr_params =
- QINTR_TIMER_IDX(NOMEM_TIMER_IDX);
+ QINTR_TIMER_IDX_V(NOMEM_TIMER_IDX);
break;
}
@@ -1875,7 +1892,7 @@ static int napi_rx_handler(struct napi_struct *napi, int budget)
intr_params = rspq->next_intr_params;
rspq->next_intr_params = rspq->intr_params;
} else
- intr_params = QINTR_TIMER_IDX(SGE_TIMER_UPD_CIDX);
+ intr_params = QINTR_TIMER_IDX_V(SGE_TIMER_UPD_CIDX);
if (unlikely(work_done == 0))
rspq->unhandled_irqs++;
@@ -1936,10 +1953,10 @@ static unsigned int process_intrq(struct adapter *adapter)
* never happen ...
*/
dma_rmb();
- if (unlikely(RSPD_TYPE(rc->type_gen) != RSP_TYPE_INTR)) {
+ if (unlikely(RSPD_TYPE_G(rc->type_gen) != RSPD_TYPE_INTR_X)) {
dev_err(adapter->pdev_dev,
"Unexpected INTRQ response type %d\n",
- RSPD_TYPE(rc->type_gen));
+ RSPD_TYPE_G(rc->type_gen));
continue;
}
@@ -1951,7 +1968,7 @@ static unsigned int process_intrq(struct adapter *adapter)
* want to either make them fatal and/or conditionalized under
* DEBUG.
*/
- qid = RSPD_QID(be32_to_cpu(rc->pldbuflen_qid));
+ qid = RSPD_QID_G(be32_to_cpu(rc->pldbuflen_qid));
iq_idx = IQ_IDX(s, qid);
if (unlikely(iq_idx >= MAX_INGQ)) {
dev_err(adapter->pdev_dev,
@@ -2154,8 +2171,8 @@ static void __iomem *bar2_address(struct adapter *adapter,
u64 bar2_qoffset;
int ret;
- ret = t4_bar2_sge_qregs(adapter, qid, qtype,
- &bar2_qoffset, pbar2_qid);
+ ret = t4vf_bar2_sge_qregs(adapter, qid, qtype,
+ &bar2_qoffset, pbar2_qid);
if (ret)
return NULL;
@@ -2239,12 +2256,18 @@ int t4vf_sge_alloc_rxq(struct adapter *adapter, struct sge_rspq *rspq,
cmd.iqaddr = cpu_to_be64(rspq->phys_addr);
if (fl) {
+ enum chip_type chip =
+ CHELSIO_CHIP_VERSION(adapter->params.chip);
/*
* Allocate the ring for the hardware free list (with space
* for its status page) along with the associated software
* descriptor ring. The free list size needs to be a multiple
- * of the Egress Queue Unit.
+ * of the Egress Queue Unit and at least 2 Egress Units larger
+ * than the SGE's Egress Congrestion Threshold
+ * (fl_starve_thres - 1).
*/
+ if (fl->size < s->fl_starve_thres - 1 + 2 * FL_PER_EQ_UNIT)
+ fl->size = s->fl_starve_thres - 1 + 2 * FL_PER_EQ_UNIT;
fl->size = roundup(fl->size, FL_PER_EQ_UNIT);
fl->desc = alloc_ring(adapter->pdev_dev, fl->size,
sizeof(__be64), sizeof(struct rx_sw_desc),
@@ -2274,7 +2297,9 @@ int t4vf_sge_alloc_rxq(struct adapter *adapter, struct sge_rspq *rspq,
cmd.fl0dcaen_to_fl0cidxfthresh =
cpu_to_be16(
FW_IQ_CMD_FL0FBMIN_V(SGE_FETCHBURSTMIN_64B) |
- FW_IQ_CMD_FL0FBMAX_V(SGE_FETCHBURSTMAX_512B));
+ FW_IQ_CMD_FL0FBMAX_V((chip <= CHELSIO_T5) ?
+ FETCHBURSTMAX_512B_X :
+ FETCHBURSTMAX_256B_X));
cmd.fl0size = cpu_to_be16(flsz);
cmd.fl0addr = cpu_to_be64(fl->addr);
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
index b9debb4f29a3..88b8981b4751 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
@@ -51,6 +51,7 @@
*/
#define CHELSIO_T4 0x4
#define CHELSIO_T5 0x5
+#define CHELSIO_T6 0x6
enum chip_type {
T4_A1 = CHELSIO_CHIP_CODE(CHELSIO_T4, 1),
@@ -156,6 +157,12 @@ struct vpd_params {
u32 cclk; /* Core Clock (KHz) */
};
+/* Stores chip specific parameters */
+struct arch_specific_params {
+ u32 sge_fl_db;
+ u16 mps_tcam_size;
+};
+
/*
* Global Receive Side Scaling (RSS) parameters in host-native format.
*/
@@ -215,6 +222,7 @@ struct adapter_params {
struct vpd_params vpd; /* Vital Product Data */
struct rss_params rss; /* Receive Side Scaling */
struct vf_resources vfres; /* Virtual Function Resource limits */
+ struct arch_specific_params arch; /* chip specific params */
enum chip_type chip; /* chip code */
u8 nports; /* # of Ethernet "ports" */
};
@@ -284,11 +292,11 @@ int t4vf_fw_reset(struct adapter *);
int t4vf_set_params(struct adapter *, unsigned int, const u32 *, const u32 *);
enum t4_bar2_qtype { T4_BAR2_QTYPE_EGRESS, T4_BAR2_QTYPE_INGRESS };
-int t4_bar2_sge_qregs(struct adapter *adapter,
- unsigned int qid,
- enum t4_bar2_qtype qtype,
- u64 *pbar2_qoffset,
- unsigned int *pbar2_qid);
+int t4vf_bar2_sge_qregs(struct adapter *adapter,
+ unsigned int qid,
+ enum t4_bar2_qtype qtype,
+ u64 *pbar2_qoffset,
+ unsigned int *pbar2_qid);
int t4vf_get_sge_params(struct adapter *);
int t4vf_get_vpd_params(struct adapter *);
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
index 966ee900ed00..0db6dc9e9ed2 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
@@ -428,7 +428,7 @@ int t4vf_set_params(struct adapter *adapter, unsigned int nparams,
}
/**
- * t4_bar2_sge_qregs - return BAR2 SGE Queue register information
+ * t4vf_bar2_sge_qregs - return BAR2 SGE Queue register information
* @adapter: the adapter
* @qid: the Queue ID
* @qtype: the Ingress or Egress type for @qid
@@ -452,11 +452,11 @@ int t4vf_set_params(struct adapter *adapter, unsigned int nparams,
* Write Combining Doorbell Buffer. If the BAR2 Queue ID is not 0,
* then these "Inferred Queue ID" register may not be used.
*/
-int t4_bar2_sge_qregs(struct adapter *adapter,
- unsigned int qid,
- enum t4_bar2_qtype qtype,
- u64 *pbar2_qoffset,
- unsigned int *pbar2_qid)
+int t4vf_bar2_sge_qregs(struct adapter *adapter,
+ unsigned int qid,
+ enum t4_bar2_qtype qtype,
+ u64 *pbar2_qoffset,
+ unsigned int *pbar2_qid)
{
unsigned int page_shift, page_size, qpp_shift, qpp_mask;
u64 bar2_page_offset, bar2_qoffset;
@@ -1191,9 +1191,7 @@ int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free,
unsigned nfilters = 0;
unsigned int rem = naddr;
struct fw_vi_mac_cmd cmd, rpl;
- unsigned int max_naddr = is_t4(adapter->params.chip) ?
- NUM_MPS_CLS_SRAM_L_INSTANCES :
- NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
+ unsigned int max_naddr = adapter->params.arch.mps_tcam_size;
if (naddr > max_naddr)
return -EINVAL;
@@ -1285,9 +1283,7 @@ int t4vf_change_mac(struct adapter *adapter, unsigned int viid,
struct fw_vi_mac_exact *p = &cmd.u.exact[0];
size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
u.exact[1]), 16);
- unsigned int max_naddr = is_t4(adapter->params.chip) ?
- NUM_MPS_CLS_SRAM_L_INSTANCES :
- NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
+ unsigned int max_mac_addr = adapter->params.arch.mps_tcam_size;
/*
* If this is a new allocation, determine whether it should be
@@ -1310,7 +1306,7 @@ int t4vf_change_mac(struct adapter *adapter, unsigned int viid,
if (ret == 0) {
p = &rpl.u.exact[0];
ret = FW_VI_MAC_CMD_IDX_G(be16_to_cpu(p->valid_to_idx));
- if (ret >= max_naddr)
+ if (ret >= max_mac_addr)
ret = -ENOMEM;
}
return ret;
@@ -1590,11 +1586,25 @@ int t4vf_prep_adapter(struct adapter *adapter)
switch (CHELSIO_PCI_ID_VER(adapter->pdev->device)) {
case CHELSIO_T4:
adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T4, 0);
+ adapter->params.arch.sge_fl_db = DBPRIO_F;
+ adapter->params.arch.mps_tcam_size =
+ NUM_MPS_CLS_SRAM_L_INSTANCES;
break;
case CHELSIO_T5:
chipid = REV_G(t4_read_reg(adapter, PL_VF_REV_A));
adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T5, chipid);
+ adapter->params.arch.sge_fl_db = DBPRIO_F | DBTYPE_F;
+ adapter->params.arch.mps_tcam_size =
+ NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
+ break;
+
+ case CHELSIO_T6:
+ chipid = REV_G(t4_read_reg(adapter, PL_VF_REV_A));
+ adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T6, chipid);
+ adapter->params.arch.sge_fl_db = 0;
+ adapter->params.arch.mps_tcam_size =
+ NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
break;
}
diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cirrus/Kconfig
index 905ac5f5d9a6..5ab912937aff 100644
--- a/drivers/net/ethernet/cirrus/Kconfig
+++ b/drivers/net/ethernet/cirrus/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_CIRRUS
default y
depends on ISA || EISA || ARM || MAC
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
@@ -23,9 +21,7 @@ config CS89x0
depends on ISA || EISA || ARM
---help---
Support for CS89x0 chipset based Ethernet cards. If you have a
- network (Ethernet) card of this type, say Y and read the
- Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto> as well as
+ network (Ethernet) card of this type, say Y and read the file
<file:Documentation/networking/cs89x0.txt>.
To compile this driver as a module, choose M here. The module
@@ -55,9 +51,7 @@ config MAC89x0
depends on MAC
---help---
Support for CS89x0 chipset based Ethernet cards. If you have a
- Nubus or LC-PDS network (Ethernet) card of this type, say Y and
- read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ Nubus or LC-PDS network (Ethernet) card of this type, say Y here.
To compile this driver as a module, choose M here. This module will
be called mac89x0.
diff --git a/drivers/net/ethernet/cisco/Kconfig b/drivers/net/ethernet/cisco/Kconfig
index 1c7b884e3371..15b713a89620 100644
--- a/drivers/net/ethernet/cisco/Kconfig
+++ b/drivers/net/ethernet/cisco/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_CISCO
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c
index 0be6850be8a2..d106186f4f4a 100644
--- a/drivers/net/ethernet/cisco/enic/enic_clsf.c
+++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c
@@ -5,7 +5,7 @@
#include <linux/in.h>
#include <linux/types.h>
#include <linux/skbuff.h>
-#include <net/flow_keys.h>
+#include <net/flow_dissector.h>
#include "enic_res.h"
#include "enic_clsf.h"
@@ -15,14 +15,14 @@
* @rq: rq number to steer to
*
* This function returns filter_id(hardware_id) of the filter
- * added. In case of error it returns an negative number.
+ * added. In case of error it returns a negative number.
*/
int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq)
{
int res;
struct filter data;
- switch (keys->ip_proto) {
+ switch (keys->basic.ip_proto) {
case IPPROTO_TCP:
data.u.ipv4.protocol = PROTO_TCP;
break;
@@ -33,10 +33,10 @@ int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq)
return -EPROTONOSUPPORT;
};
data.type = FILTER_IPV4_5TUPLE;
- data.u.ipv4.src_addr = ntohl(keys->src);
- data.u.ipv4.dst_addr = ntohl(keys->dst);
- data.u.ipv4.src_port = ntohs(keys->port16[0]);
- data.u.ipv4.dst_port = ntohs(keys->port16[1]);
+ data.u.ipv4.src_addr = ntohl(keys->addrs.v4addrs.src);
+ data.u.ipv4.dst_addr = ntohl(keys->addrs.v4addrs.dst);
+ data.u.ipv4.src_port = ntohs(keys->ports.src);
+ data.u.ipv4.dst_port = ntohs(keys->ports.dst);
data.u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE;
spin_lock_bh(&enic->devcmd_lock);
@@ -158,11 +158,11 @@ static struct enic_rfs_fltr_node *htbl_key_search(struct hlist_head *h,
struct enic_rfs_fltr_node *tpos;
hlist_for_each_entry(tpos, h, node)
- if (tpos->keys.src == k->src &&
- tpos->keys.dst == k->dst &&
- tpos->keys.ports == k->ports &&
- tpos->keys.ip_proto == k->ip_proto &&
- tpos->keys.n_proto == k->n_proto)
+ if (tpos->keys.addrs.v4addrs.src == k->addrs.v4addrs.src &&
+ tpos->keys.addrs.v4addrs.dst == k->addrs.v4addrs.dst &&
+ tpos->keys.ports.ports == k->ports.ports &&
+ tpos->keys.basic.ip_proto == k->basic.ip_proto &&
+ tpos->keys.basic.n_proto == k->basic.n_proto)
return tpos;
return NULL;
}
@@ -177,9 +177,10 @@ int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
int res, i;
enic = netdev_priv(dev);
- res = skb_flow_dissect(skb, &keys);
- if (!res || keys.n_proto != htons(ETH_P_IP) ||
- (keys.ip_proto != IPPROTO_TCP && keys.ip_proto != IPPROTO_UDP))
+ res = skb_flow_dissect_flow_keys(skb, &keys);
+ if (!res || keys.basic.n_proto != htons(ETH_P_IP) ||
+ (keys.basic.ip_proto != IPPROTO_TCP &&
+ keys.basic.ip_proto != IPPROTO_UDP))
return -EPROTONOSUPPORT;
tbl_idx = skb_get_hash_raw(skb) & ENIC_RFS_FLW_MASK;
diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
index 68d47b196dae..f3f1601a76f3 100644
--- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c
+++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
@@ -348,7 +348,7 @@ static int enic_grxclsrule(struct enic *enic, struct ethtool_rxnfc *cmd)
n = htbl_fltr_search(enic, (u16)fsp->location);
if (!n)
return -EINVAL;
- switch (n->keys.ip_proto) {
+ switch (n->keys.basic.ip_proto) {
case IPPROTO_TCP:
fsp->flow_type = TCP_V4_FLOW;
break;
@@ -360,16 +360,16 @@ static int enic_grxclsrule(struct enic *enic, struct ethtool_rxnfc *cmd)
break;
}
- fsp->h_u.tcp_ip4_spec.ip4src = n->keys.src;
+ fsp->h_u.tcp_ip4_spec.ip4src = flow_get_u32_src(&n->keys);
fsp->m_u.tcp_ip4_spec.ip4src = (__u32)~0;
- fsp->h_u.tcp_ip4_spec.ip4dst = n->keys.dst;
+ fsp->h_u.tcp_ip4_spec.ip4dst = flow_get_u32_dst(&n->keys);
fsp->m_u.tcp_ip4_spec.ip4dst = (__u32)~0;
- fsp->h_u.tcp_ip4_spec.psrc = n->keys.port16[0];
+ fsp->h_u.tcp_ip4_spec.psrc = n->keys.ports.src;
fsp->m_u.tcp_ip4_spec.psrc = (__u16)~0;
- fsp->h_u.tcp_ip4_spec.pdst = n->keys.port16[1];
+ fsp->h_u.tcp_ip4_spec.pdst = n->keys.ports.dst;
fsp->m_u.tcp_ip4_spec.pdst = (__u16)~0;
fsp->ring_cookie = n->rq_id;
diff --git a/drivers/net/ethernet/dec/Kconfig b/drivers/net/ethernet/dec/Kconfig
index 68262aa57d01..740bbad5ed38 100644
--- a/drivers/net/ethernet/dec/Kconfig
+++ b/drivers/net/ethernet/dec/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_DEC
default y
depends on PCI || EISA || CARDBUS
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/dec/tulip/Kconfig b/drivers/net/ethernet/dec/tulip/Kconfig
index eb9ba6e97d04..1003201b5d80 100644
--- a/drivers/net/ethernet/dec/tulip/Kconfig
+++ b/drivers/net/ethernet/dec/tulip/Kconfig
@@ -21,8 +21,7 @@ config DE2104X
of this type. (If your card is NOT SMC EtherPower 10/100 PCI
(smc9332dst), you can also try the driver for "Generic DECchip"
cards, below. However, most people with a network card of this type
- will say Y here.) Do read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ will say Y here.)
To compile this driver as a module, choose M here. The module will
be called de2104x.
@@ -50,8 +49,7 @@ config TULIP
of this type. (If your card is NOT SMC EtherPower 10/100 PCI
(smc9332dst), you can also try the driver for "Generic DECchip"
cards, above. However, most people with a network card of this type
- will say Y here.) Do read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ will say Y here.)
To compile this driver as a module, choose M here. The module will
be called tulip.
@@ -113,9 +111,7 @@ config DE4X5
---help---
This is support for the DIGITAL series of PCI/EISA Ethernet cards.
These include the DE425, DE434, DE435, DE450 and DE500 models. If
- you have a network card of this type, say Y and read the
- Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. More specific
+ you have a network card of this type, say Y. More specific
information is contained in
<file:Documentation/networking/de4x5.txt>.
diff --git a/drivers/net/ethernet/dec/tulip/de4x5.c b/drivers/net/ethernet/dec/tulip/de4x5.c
index badff181e719..8966f3159bb2 100644
--- a/drivers/net/ethernet/dec/tulip/de4x5.c
+++ b/drivers/net/ethernet/dec/tulip/de4x5.c
@@ -5189,16 +5189,16 @@ de4x5_parse_params(struct net_device *dev)
if (strstr(p, "fdx") || strstr(p, "FDX")) lp->params.fdx = true;
if (strstr(p, "autosense") || strstr(p, "AUTOSENSE")) {
- if (strstr(p, "TP")) {
- lp->params.autosense = TP;
- } else if (strstr(p, "TP_NW")) {
+ if (strstr(p, "TP_NW")) {
lp->params.autosense = TP_NW;
+ } else if (strstr(p, "TP")) {
+ lp->params.autosense = TP;
+ } else if (strstr(p, "BNC_AUI")) {
+ lp->params.autosense = BNC;
} else if (strstr(p, "BNC")) {
lp->params.autosense = BNC;
} else if (strstr(p, "AUI")) {
lp->params.autosense = AUI;
- } else if (strstr(p, "BNC_AUI")) {
- lp->params.autosense = BNC;
} else if (strstr(p, "10Mb")) {
lp->params.autosense = _10Mb;
} else if (strstr(p, "100Mb")) {
diff --git a/drivers/net/ethernet/dec/tulip/uli526x.c b/drivers/net/ethernet/dec/tulip/uli526x.c
index 2c30c0c83f98..447d09272ab7 100644
--- a/drivers/net/ethernet/dec/tulip/uli526x.c
+++ b/drivers/net/ethernet/dec/tulip/uli526x.c
@@ -1115,7 +1115,7 @@ static void uli526x_timer(unsigned long data)
netif_carrier_off(dev);
}
}
- db->init=0;
+ db->init = 0;
/* Timer active again */
db->timer.expires = ULI526X_TIMER_WUT;
diff --git a/drivers/net/ethernet/dlink/Kconfig b/drivers/net/ethernet/dlink/Kconfig
index c543ac11ce08..f6e858d0b9d4 100644
--- a/drivers/net/ethernet/dlink/Kconfig
+++ b/drivers/net/ethernet/dlink/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_DLINK
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c
index 1274b6fdac8a..cf0a5fcdaaaf 100644
--- a/drivers/net/ethernet/dlink/dl2k.c
+++ b/drivers/net/ethernet/dlink/dl2k.c
@@ -463,10 +463,8 @@ rio_open (struct net_device *dev)
dw32(MACCtrl, dr32(MACCtrl) | AutoVLANuntagging);
}
- init_timer (&np->timer);
+ setup_timer(&np->timer, rio_timer, (unsigned long)dev);
np->timer.expires = jiffies + 1*HZ;
- np->timer.data = (unsigned long) dev;
- np->timer.function = rio_timer;
add_timer (&np->timer);
/* Start Tx/Rx */
diff --git a/drivers/net/ethernet/emulex/Kconfig b/drivers/net/ethernet/emulex/Kconfig
index 1b8d638c6cb1..fdbb27ceb02f 100644
--- a/drivers/net/ethernet/emulex/Kconfig
+++ b/drivers/net/ethernet/emulex/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_EMULEX
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/emulex/benet/Kconfig b/drivers/net/ethernet/emulex/benet/Kconfig
index ea94a8eb6b35..7108563260ae 100644
--- a/drivers/net/ethernet/emulex/benet/Kconfig
+++ b/drivers/net/ethernet/emulex/benet/Kconfig
@@ -5,6 +5,15 @@ config BE2NET
This driver implements the NIC functionality for ServerEngines'
10Gbps network adapter - BladeEngine.
+config BE2NET_HWMON
+ bool "HWMON support for be2net driver"
+ depends on BE2NET && HWMON
+ depends on !(BE2NET=y && HWMON=m)
+ default y
+ ---help---
+ Say Y here if you want to expose thermal sensor data on
+ be2net network adapter.
+
config BE2NET_VXLAN
bool "VXLAN offload support on be2net driver"
default y
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index 1bf1cdce74ac..8d12b41b3b19 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -31,11 +31,13 @@
#include <linux/slab.h>
#include <linux/u64_stats_sync.h>
#include <linux/cpumask.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include "be_hw.h"
#include "be_roce.h"
-#define DRV_VER "10.6.0.1"
+#define DRV_VER "10.6.0.2"
#define DRV_NAME "be2net"
#define BE_NAME "Emulex BladeEngine2"
#define BE3_NAME "Emulex BladeEngine3"
@@ -314,7 +316,6 @@ struct be_rx_obj {
} ____cacheline_aligned_in_smp;
struct be_drv_stats {
- u32 be_on_die_temperature;
u32 eth_red_drops;
u32 dma_map_errors;
u32 rx_drops_no_pbuf;
@@ -366,6 +367,7 @@ struct be_vf_cfg {
u32 tx_rate;
u32 plink_tracking;
u32 privileges;
+ bool spoofchk;
};
enum vf_state {
@@ -382,6 +384,7 @@ enum vf_state {
#define BE_FLAGS_SETUP_DONE BIT(9)
#define BE_FLAGS_EVT_INCOMPATIBLE_SFP BIT(10)
#define BE_FLAGS_ERR_DETECTION_SCHEDULED BIT(11)
+#define BE_FLAGS_OS2BMC BIT(12)
#define BE_UC_PMAC_COUNT 30
#define BE_VF_UC_PMAC_COUNT 2
@@ -426,6 +429,8 @@ struct be_resources {
u32 vf_if_cap_flags; /* VF if capability flags */
};
+#define be_is_os2bmc_enabled(adapter) (adapter->flags & BE_FLAGS_OS2BMC)
+
struct rss_info {
u64 rss_flags;
u8 rsstable[RSS_INDIR_TABLE_LEN];
@@ -433,6 +438,12 @@ struct rss_info {
u8 rss_hkey[RSS_HASH_KEY_LEN];
};
+#define BE_INVALID_DIE_TEMP 0xFF
+struct be_hwmon {
+ struct device *hwmon_dev;
+ u8 be_on_die_temp; /* Unit: millidegree Celsius */
+};
+
/* Macros to read/write the 'features' word of be_wrb_params structure.
*/
#define BE_WRB_F_BIT(name) BE_WRB_F_##name##_BIT
@@ -453,7 +464,8 @@ enum {
BE_WRB_F_LSO_BIT, /* LSO */
BE_WRB_F_LSO6_BIT, /* LSO6 */
BE_WRB_F_VLAN_BIT, /* VLAN */
- BE_WRB_F_VLAN_SKIP_HW_BIT /* Skip VLAN tag (workaround) */
+ BE_WRB_F_VLAN_SKIP_HW_BIT, /* Skip VLAN tag (workaround) */
+ BE_WRB_F_OS2BMC_BIT /* Send packet to the management ring */
};
/* The structure below provides a HW-agnostic abstraction of WRB params
@@ -514,6 +526,7 @@ struct be_adapter {
u16 work_counter;
struct delayed_work be_err_detection_work;
+ u8 err_flags;
u32 flags;
u32 cmd_privileges;
/* Ethtool knobs and info */
@@ -572,8 +585,11 @@ struct be_adapter {
u16 qnq_vid;
u32 msg_enable;
int be_get_temp_freq;
+ struct be_hwmon hwmon_info;
u8 pf_number;
struct rss_info rss_info;
+ /* Filters for packets that need to be sent to BMC */
+ u32 bmc_filt_mask;
};
#define be_physfn(adapter) (!adapter->virtfn)
@@ -772,26 +788,36 @@ static inline bool is_ipv4_pkt(struct sk_buff *skb)
return skb->protocol == htons(ETH_P_IP) && ip_hdr(skb)->version == 4;
}
-static inline bool be_multi_rxq(const struct be_adapter *adapter)
+#define BE_ERROR_EEH 1
+#define BE_ERROR_UE BIT(1)
+#define BE_ERROR_FW BIT(2)
+#define BE_ERROR_HW (BE_ERROR_EEH | BE_ERROR_UE)
+#define BE_ERROR_ANY (BE_ERROR_EEH | BE_ERROR_UE | BE_ERROR_FW)
+#define BE_CLEAR_ALL 0xFF
+
+static inline u8 be_check_error(struct be_adapter *adapter, u32 err_type)
{
- return adapter->num_rx_qs > 1;
+ return (adapter->err_flags & err_type);
}
-static inline bool be_error(struct be_adapter *adapter)
+static inline void be_set_error(struct be_adapter *adapter, int err_type)
{
- return adapter->eeh_error || adapter->hw_error || adapter->fw_timeout;
+ struct net_device *netdev = adapter->netdev;
+
+ adapter->err_flags |= err_type;
+ netif_carrier_off(netdev);
+
+ dev_info(&adapter->pdev->dev, "%s: Link down\n", netdev->name);
}
-static inline bool be_hw_error(struct be_adapter *adapter)
+static inline void be_clear_error(struct be_adapter *adapter, int err_type)
{
- return adapter->eeh_error || adapter->hw_error;
+ adapter->err_flags &= ~err_type;
}
-static inline void be_clear_all_error(struct be_adapter *adapter)
+static inline bool be_multi_rxq(const struct be_adapter *adapter)
{
- adapter->eeh_error = false;
- adapter->hw_error = false;
- adapter->fw_timeout = false;
+ return adapter->num_rx_qs > 1;
}
void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
@@ -804,6 +830,7 @@ bool be_pause_supported(struct be_adapter *adapter);
u32 be_get_fw_log_level(struct be_adapter *adapter);
int be_update_queues(struct be_adapter *adapter);
int be_poll(struct napi_struct *napi, int budget);
+void be_eqd_update(struct be_adapter *adapter, bool force_update);
/*
* internal function to initialize-cleanup roce device.
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index c5e1d0ac75f9..9eac3227d2ca 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -93,7 +93,7 @@ static void be_mcc_notify(struct be_adapter *adapter)
struct be_queue_info *mccq = &adapter->mcc_obj.q;
u32 val = 0;
- if (be_error(adapter))
+ if (be_check_error(adapter, BE_ERROR_ANY))
return;
val |= mccq->id & DB_MCCQ_RING_ID_MASK;
@@ -140,6 +140,7 @@ static bool be_skip_err_log(u8 opcode, u16 base_status, u16 addl_status)
if (base_status == MCC_STATUS_NOT_SUPPORTED ||
base_status == MCC_STATUS_ILLEGAL_REQUEST ||
addl_status == MCC_ADDL_STATUS_TOO_MANY_INTERFACES ||
+ addl_status == MCC_ADDL_STATUS_INSUFFICIENT_VLANS ||
(opcode == OPCODE_COMMON_WRITE_FLASHROM &&
(base_status == MCC_STATUS_ILLEGAL_FIELD ||
addl_status == MCC_ADDL_STATUS_FLASH_IMAGE_CRC_MISMATCH)))
@@ -191,10 +192,12 @@ static void be_async_cmd_process(struct be_adapter *adapter,
if (base_status == MCC_STATUS_SUCCESS) {
struct be_cmd_resp_get_cntl_addnl_attribs *resp =
(void *)resp_hdr;
- adapter->drv_stats.be_on_die_temperature =
+ adapter->hwmon_info.be_on_die_temp =
resp->on_die_temperature;
} else {
adapter->be_get_temp_freq = 0;
+ adapter->hwmon_info.be_on_die_temp =
+ BE_INVALID_DIE_TEMP;
}
return;
}
@@ -330,6 +333,21 @@ static void be_async_grp5_pvid_state_process(struct be_adapter *adapter,
}
}
+#define MGMT_ENABLE_MASK 0x4
+static void be_async_grp5_fw_control_process(struct be_adapter *adapter,
+ struct be_mcc_compl *compl)
+{
+ struct be_async_fw_control *evt = (struct be_async_fw_control *)compl;
+ u32 evt_dw1 = le32_to_cpu(evt->event_data_word1);
+
+ if (evt_dw1 & MGMT_ENABLE_MASK) {
+ adapter->flags |= BE_FLAGS_OS2BMC;
+ adapter->bmc_filt_mask = le32_to_cpu(evt->event_data_word2);
+ } else {
+ adapter->flags &= ~BE_FLAGS_OS2BMC;
+ }
+}
+
static void be_async_grp5_evt_process(struct be_adapter *adapter,
struct be_mcc_compl *compl)
{
@@ -346,6 +364,10 @@ static void be_async_grp5_evt_process(struct be_adapter *adapter,
case ASYNC_EVENT_PVID_STATE:
be_async_grp5_pvid_state_process(adapter, compl);
break;
+ /* Async event to disable/enable os2bmc and/or mac-learning */
+ case ASYNC_EVENT_FW_CONTROL:
+ be_async_grp5_fw_control_process(adapter, compl);
+ break;
default:
break;
}
@@ -486,7 +508,7 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
for (i = 0; i < mcc_timeout; i++) {
- if (be_error(adapter))
+ if (be_check_error(adapter, BE_ERROR_ANY))
return -EIO;
local_bh_disable();
@@ -499,7 +521,7 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
}
if (i == mcc_timeout) {
dev_err(&adapter->pdev->dev, "FW not responding\n");
- adapter->fw_timeout = true;
+ be_set_error(adapter, BE_ERROR_FW);
return -EIO;
}
return status;
@@ -538,7 +560,7 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
u32 ready;
do {
- if (be_error(adapter))
+ if (be_check_error(adapter, BE_ERROR_ANY))
return -EIO;
ready = ioread32(db);
@@ -551,7 +573,7 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
if (msecs > 4000) {
dev_err(&adapter->pdev->dev, "FW not responding\n");
- adapter->fw_timeout = true;
+ be_set_error(adapter, BE_ERROR_FW);
be_detect_error(adapter);
return -1;
}
@@ -1457,7 +1479,7 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
*if_handle = le32_to_cpu(resp->interface_id);
/* Hack to retrieve VF's pmac-id on BE3 */
- if (BE3_chip(adapter) && !be_physfn(adapter))
+ if (BE3_chip(adapter) && be_virtfn(adapter))
adapter->pmac_id[0] = le32_to_cpu(resp->pmac_id);
}
return status;
@@ -3156,7 +3178,7 @@ int be_cmd_set_mac(struct be_adapter *adapter, u8 *mac, int if_id, u32 dom)
}
int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid,
- u32 domain, u16 intf_id, u16 hsw_mode)
+ u32 domain, u16 intf_id, u16 hsw_mode, u8 spoofchk)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_set_hsw_config *req;
@@ -3192,6 +3214,14 @@ int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid,
ctxt, hsw_mode);
}
+ /* Enable/disable both mac and vlan spoof checking */
+ if (!BEx_chip(adapter) && spoofchk) {
+ AMAP_SET_BITS(struct amap_set_hsw_context, mac_spoofchk,
+ ctxt, spoofchk);
+ AMAP_SET_BITS(struct amap_set_hsw_context, vlan_spoofchk,
+ ctxt, spoofchk);
+ }
+
be_dws_cpu_to_le(req->context, sizeof(req->context));
status = be_mcc_notify_wait(adapter);
@@ -3202,7 +3232,7 @@ err:
/* Get Hyper switch config */
int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid,
- u32 domain, u16 intf_id, u8 *mode)
+ u32 domain, u16 intf_id, u8 *mode, bool *spoofchk)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_get_hsw_config *req;
@@ -3250,6 +3280,10 @@ int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid,
if (mode)
*mode = AMAP_GET_BITS(struct amap_get_hsw_resp_context,
port_fwd_type, &resp->context);
+ if (spoofchk)
+ *spoofchk =
+ AMAP_GET_BITS(struct amap_get_hsw_resp_context,
+ spoofchk, &resp->context);
}
err:
@@ -3261,7 +3295,7 @@ static bool be_is_wol_excluded(struct be_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
- if (!be_physfn(adapter))
+ if (be_virtfn(adapter))
return true;
switch (pdev->subsystem_device) {
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 1ec22300e254..2716e6f30d9a 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -65,7 +65,8 @@ enum mcc_base_status {
enum mcc_addl_status {
MCC_ADDL_STATUS_INSUFFICIENT_RESOURCES = 0x16,
MCC_ADDL_STATUS_FLASH_IMAGE_CRC_MISMATCH = 0x4d,
- MCC_ADDL_STATUS_TOO_MANY_INTERFACES = 0x4a
+ MCC_ADDL_STATUS_TOO_MANY_INTERFACES = 0x4a,
+ MCC_ADDL_STATUS_INSUFFICIENT_VLANS = 0xab
};
#define CQE_BASE_STATUS_MASK 0xFFFF
@@ -104,6 +105,7 @@ struct be_mcc_compl {
#define ASYNC_DEBUG_EVENT_TYPE_QNQ 1
#define ASYNC_EVENT_CODE_SLIPORT 0x11
#define ASYNC_EVENT_PORT_MISCONFIG 0x9
+#define ASYNC_EVENT_FW_CONTROL 0x5
enum {
LINK_DOWN = 0x0,
@@ -180,6 +182,22 @@ struct be_async_event_misconfig_port {
u32 flags;
} __packed;
+#define BMC_FILT_BROADCAST_ARP BIT(0)
+#define BMC_FILT_BROADCAST_DHCP_CLIENT BIT(1)
+#define BMC_FILT_BROADCAST_DHCP_SERVER BIT(2)
+#define BMC_FILT_BROADCAST_NET_BIOS BIT(3)
+#define BMC_FILT_BROADCAST BIT(7)
+#define BMC_FILT_MULTICAST_IPV6_NEIGH_ADVER BIT(8)
+#define BMC_FILT_MULTICAST_IPV6_RA BIT(9)
+#define BMC_FILT_MULTICAST_IPV6_RAS BIT(10)
+#define BMC_FILT_MULTICAST BIT(15)
+struct be_async_fw_control {
+ u32 event_data_word1;
+ u32 event_data_word2;
+ u32 evt_tag;
+ u32 event_data_word4;
+} __packed;
+
struct be_mcc_mailbox {
struct be_mcc_wrb wrb;
struct be_mcc_compl compl;
@@ -1109,10 +1127,6 @@ struct be_cmd_req_query_fw_cfg {
u32 rsvd[31];
};
-/* ASIC revisions */
-#define ASIC_REV_B0 0x10
-#define ASIC_REV_P2 0x11
-
struct be_cmd_resp_query_fw_cfg {
struct be_cmd_resp_hdr hdr;
u32 be_config_number;
@@ -1745,18 +1759,24 @@ struct be_cmd_req_set_mac_list {
#define PORT_FWD_TYPE_VEPA 0x3
#define PORT_FWD_TYPE_VEB 0x2
+#define ENABLE_MAC_SPOOFCHK 0x2
+#define DISABLE_MAC_SPOOFCHK 0x3
+
struct amap_set_hsw_context {
u8 interface_id[16];
- u8 rsvd0[14];
+ u8 rsvd0[8];
+ u8 mac_spoofchk[2];
+ u8 rsvd1[4];
u8 pvid_valid;
u8 pport;
- u8 rsvd1[6];
+ u8 rsvd2[6];
u8 port_fwd_type[3];
- u8 rsvd2[7];
+ u8 rsvd3[5];
+ u8 vlan_spoofchk[2];
u8 pvid[16];
- u8 rsvd3[32];
u8 rsvd4[32];
u8 rsvd5[32];
+ u8 rsvd6[32];
} __packed;
struct be_cmd_req_set_hsw_config {
@@ -1774,11 +1794,13 @@ struct amap_get_hsw_req_context {
struct amap_get_hsw_resp_context {
u8 rsvd0[6];
u8 port_fwd_type[3];
- u8 rsvd1[7];
+ u8 rsvd1[5];
+ u8 spoofchk;
+ u8 rsvd2;
u8 pvid[16];
- u8 rsvd2[32];
u8 rsvd3[32];
u8 rsvd4[32];
+ u8 rsvd5[32];
} __packed;
struct be_cmd_req_get_hsw_config {
@@ -2334,9 +2356,9 @@ int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, u8 mac_count,
u32 domain);
int be_cmd_set_mac(struct be_adapter *adapter, u8 *mac, int if_id, u32 dom);
int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid, u32 domain,
- u16 intf_id, u16 hsw_mode);
+ u16 intf_id, u16 hsw_mode, u8 spoofchk);
int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, u32 domain,
- u16 intf_id, u8 *mode);
+ u16 intf_id, u8 *mode, bool *spoofchk);
int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter);
int be_cmd_set_fw_log_level(struct be_adapter *adapter, u32 level);
int be_cmd_get_fw_log_level(struct be_adapter *adapter);
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index 2835dee5dc39..b2476dbfd103 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -123,7 +123,6 @@ static const struct be_ethtool_stat et_stats[] = {
{DRVSTAT_INFO(dma_map_errors)},
/* Number of packets dropped due to random early drop function */
{DRVSTAT_INFO(eth_red_drops)},
- {DRVSTAT_INFO(be_on_die_temperature)},
{DRVSTAT_INFO(rx_roce_bytes_lsd)},
{DRVSTAT_INFO(rx_roce_bytes_msd)},
{DRVSTAT_INFO(rx_roce_frames)},
@@ -368,6 +367,14 @@ static int be_set_coalesce(struct net_device *netdev,
aic++;
}
+ /* For Skyhawk, the EQD setting happens via EQ_DB when AIC is enabled.
+ * When AIC is disabled, persistently force set EQD value via the
+ * FW cmd, so that we don't have to calculate the delay multiplier
+ * encode value each time EQ_DB is rung
+ */
+ if (!et->use_adaptive_rx_coalesce && skyhawk_chip(adapter))
+ be_eqd_update(adapter, true);
+
return 0;
}
diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h
index 48840889db62..c684bb32b487 100644
--- a/drivers/net/ethernet/emulex/benet/be_hw.h
+++ b/drivers/net/ethernet/emulex/benet/be_hw.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -132,6 +132,18 @@
#define DB_EQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
/* Rearm bit */
#define DB_EQ_REARM_SHIFT (29) /* bit 29 */
+/* Rearm to interrupt delay encoding */
+#define DB_EQ_R2I_DLY_SHIFT (30) /* bits 30 - 31 */
+
+/* Rearm to interrupt (R2I) delay multiplier encoding represents 3 different
+ * values configured in CEV_REARM2IRPT_DLY_MULT_CSR register. This value is
+ * programmed by host driver while ringing an EQ doorbell(EQ_DB) if a delay
+ * between rearming the EQ and next interrupt on this EQ is desired.
+ */
+#define R2I_DLY_ENC_0 0 /* No delay */
+#define R2I_DLY_ENC_1 1 /* maps to 160us EQ delay */
+#define R2I_DLY_ENC_2 2 /* maps to 96us EQ delay */
+#define R2I_DLY_ENC_3 3 /* maps to 48us EQ delay */
/********* Compl Q door bell *************/
#define DB_CQ_OFFSET 0x120
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index e43cc8a73ea7..6f642426308c 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -179,7 +179,7 @@ static void be_intr_set(struct be_adapter *adapter, bool enable)
if (lancer_chip(adapter))
return;
- if (adapter->eeh_error)
+ if (be_check_error(adapter, BE_ERROR_EEH))
return;
status = be_cmd_intr_set(adapter, enable);
@@ -191,6 +191,9 @@ static void be_rxq_notify(struct be_adapter *adapter, u16 qid, u16 posted)
{
u32 val = 0;
+ if (be_check_error(adapter, BE_ERROR_HW))
+ return;
+
val |= qid & DB_RQ_RING_ID_MASK;
val |= posted << DB_RQ_NUM_POSTED_SHIFT;
@@ -203,6 +206,9 @@ static void be_txq_notify(struct be_adapter *adapter, struct be_tx_obj *txo,
{
u32 val = 0;
+ if (be_check_error(adapter, BE_ERROR_HW))
+ return;
+
val |= txo->q.id & DB_TXULP_RING_ID_MASK;
val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT;
@@ -211,14 +217,15 @@ static void be_txq_notify(struct be_adapter *adapter, struct be_tx_obj *txo,
}
static void be_eq_notify(struct be_adapter *adapter, u16 qid,
- bool arm, bool clear_int, u16 num_popped)
+ bool arm, bool clear_int, u16 num_popped,
+ u32 eq_delay_mult_enc)
{
u32 val = 0;
val |= qid & DB_EQ_RING_ID_MASK;
val |= ((qid & DB_EQ_RING_ID_EXT_MASK) << DB_EQ_RING_ID_EXT_MASK_SHIFT);
- if (adapter->eeh_error)
+ if (be_check_error(adapter, BE_ERROR_HW))
return;
if (arm)
@@ -227,6 +234,7 @@ static void be_eq_notify(struct be_adapter *adapter, u16 qid,
val |= 1 << DB_EQ_CLR_SHIFT;
val |= 1 << DB_EQ_EVNT_SHIFT;
val |= num_popped << DB_EQ_NUM_POPPED_SHIFT;
+ val |= eq_delay_mult_enc << DB_EQ_R2I_DLY_SHIFT;
iowrite32(val, adapter->db + DB_EQ_OFFSET);
}
@@ -238,7 +246,7 @@ void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped)
val |= ((qid & DB_CQ_RING_ID_EXT_MASK) <<
DB_CQ_RING_ID_EXT_MASK_SHIFT);
- if (adapter->eeh_error)
+ if (be_check_error(adapter, BE_ERROR_HW))
return;
if (arm)
@@ -662,6 +670,8 @@ void be_link_status_update(struct be_adapter *adapter, u8 link_status)
netif_carrier_on(netdev);
else
netif_carrier_off(netdev);
+
+ netdev_info(netdev, "Link is %s\n", link_status ? "Up" : "Down");
}
static void be_tx_stats_update(struct be_tx_obj *txo, struct sk_buff *skb)
@@ -810,6 +820,8 @@ static void wrb_fill_hdr(struct be_adapter *adapter,
SET_TX_WRB_HDR_BITS(num_wrb, hdr, skb_wrb_cnt(skb));
SET_TX_WRB_HDR_BITS(len, hdr, skb->len);
+ SET_TX_WRB_HDR_BITS(mgmt, hdr,
+ BE_WRB_F_GET(wrb_params->features, OS2BMC));
}
static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb,
@@ -1146,6 +1158,130 @@ static void be_xmit_flush(struct be_adapter *adapter, struct be_tx_obj *txo)
txo->pend_wrb_cnt = 0;
}
+/* OS2BMC related */
+
+#define DHCP_CLIENT_PORT 68
+#define DHCP_SERVER_PORT 67
+#define NET_BIOS_PORT1 137
+#define NET_BIOS_PORT2 138
+#define DHCPV6_RAS_PORT 547
+
+#define is_mc_allowed_on_bmc(adapter, eh) \
+ (!is_multicast_filt_enabled(adapter) && \
+ is_multicast_ether_addr(eh->h_dest) && \
+ !is_broadcast_ether_addr(eh->h_dest))
+
+#define is_bc_allowed_on_bmc(adapter, eh) \
+ (!is_broadcast_filt_enabled(adapter) && \
+ is_broadcast_ether_addr(eh->h_dest))
+
+#define is_arp_allowed_on_bmc(adapter, skb) \
+ (is_arp(skb) && is_arp_filt_enabled(adapter))
+
+#define is_broadcast_packet(eh, adapter) \
+ (is_multicast_ether_addr(eh->h_dest) && \
+ !compare_ether_addr(eh->h_dest, adapter->netdev->broadcast))
+
+#define is_arp(skb) (skb->protocol == htons(ETH_P_ARP))
+
+#define is_arp_filt_enabled(adapter) \
+ (adapter->bmc_filt_mask & (BMC_FILT_BROADCAST_ARP))
+
+#define is_dhcp_client_filt_enabled(adapter) \
+ (adapter->bmc_filt_mask & BMC_FILT_BROADCAST_DHCP_CLIENT)
+
+#define is_dhcp_srvr_filt_enabled(adapter) \
+ (adapter->bmc_filt_mask & BMC_FILT_BROADCAST_DHCP_SERVER)
+
+#define is_nbios_filt_enabled(adapter) \
+ (adapter->bmc_filt_mask & BMC_FILT_BROADCAST_NET_BIOS)
+
+#define is_ipv6_na_filt_enabled(adapter) \
+ (adapter->bmc_filt_mask & \
+ BMC_FILT_MULTICAST_IPV6_NEIGH_ADVER)
+
+#define is_ipv6_ra_filt_enabled(adapter) \
+ (adapter->bmc_filt_mask & BMC_FILT_MULTICAST_IPV6_RA)
+
+#define is_ipv6_ras_filt_enabled(adapter) \
+ (adapter->bmc_filt_mask & BMC_FILT_MULTICAST_IPV6_RAS)
+
+#define is_broadcast_filt_enabled(adapter) \
+ (adapter->bmc_filt_mask & BMC_FILT_BROADCAST)
+
+#define is_multicast_filt_enabled(adapter) \
+ (adapter->bmc_filt_mask & BMC_FILT_MULTICAST)
+
+static bool be_send_pkt_to_bmc(struct be_adapter *adapter,
+ struct sk_buff **skb)
+{
+ struct ethhdr *eh = (struct ethhdr *)(*skb)->data;
+ bool os2bmc = false;
+
+ if (!be_is_os2bmc_enabled(adapter))
+ goto done;
+
+ if (!is_multicast_ether_addr(eh->h_dest))
+ goto done;
+
+ if (is_mc_allowed_on_bmc(adapter, eh) ||
+ is_bc_allowed_on_bmc(adapter, eh) ||
+ is_arp_allowed_on_bmc(adapter, (*skb))) {
+ os2bmc = true;
+ goto done;
+ }
+
+ if ((*skb)->protocol == htons(ETH_P_IPV6)) {
+ struct ipv6hdr *hdr = ipv6_hdr((*skb));
+ u8 nexthdr = hdr->nexthdr;
+
+ if (nexthdr == IPPROTO_ICMPV6) {
+ struct icmp6hdr *icmp6 = icmp6_hdr((*skb));
+
+ switch (icmp6->icmp6_type) {
+ case NDISC_ROUTER_ADVERTISEMENT:
+ os2bmc = is_ipv6_ra_filt_enabled(adapter);
+ goto done;
+ case NDISC_NEIGHBOUR_ADVERTISEMENT:
+ os2bmc = is_ipv6_na_filt_enabled(adapter);
+ goto done;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (is_udp_pkt((*skb))) {
+ struct udphdr *udp = udp_hdr((*skb));
+
+ switch (udp->dest) {
+ case DHCP_CLIENT_PORT:
+ os2bmc = is_dhcp_client_filt_enabled(adapter);
+ goto done;
+ case DHCP_SERVER_PORT:
+ os2bmc = is_dhcp_srvr_filt_enabled(adapter);
+ goto done;
+ case NET_BIOS_PORT1:
+ case NET_BIOS_PORT2:
+ os2bmc = is_nbios_filt_enabled(adapter);
+ goto done;
+ case DHCPV6_RAS_PORT:
+ os2bmc = is_ipv6_ras_filt_enabled(adapter);
+ goto done;
+ default:
+ break;
+ }
+ }
+done:
+ /* For packets over a vlan, which are destined
+ * to BMC, asic expects the vlan to be inline in the packet.
+ */
+ if (os2bmc)
+ *skb = be_insert_vlan_in_pkt(adapter, *skb, NULL);
+
+ return os2bmc;
+}
+
static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
@@ -1167,6 +1303,18 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
goto drop;
}
+ /* if os2bmc is enabled and if the pkt is destined to bmc,
+ * enqueue the pkt a 2nd time with mgmt bit set.
+ */
+ if (be_send_pkt_to_bmc(adapter, &skb)) {
+ BE_WRB_F_SET(wrb_params.features, OS2BMC, 1);
+ wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params);
+ if (unlikely(!wrb_cnt))
+ goto drop;
+ else
+ skb_get(skb);
+ }
+
if (be_is_txq_full(txo)) {
netif_stop_subqueue(netdev, q_idx);
tx_stats(txo)->tx_stops++;
@@ -1265,7 +1413,8 @@ static int be_vid_config(struct be_adapter *adapter)
if (status) {
dev_err(dev, "Setting HW VLAN filtering failed\n");
/* Set to VLAN promisc mode as setting VLAN filter failed */
- if (addl_status(status) ==
+ if (addl_status(status) == MCC_ADDL_STATUS_INSUFFICIENT_VLANS ||
+ addl_status(status) ==
MCC_ADDL_STATUS_INSUFFICIENT_RESOURCES)
return be_set_vlan_promisc(adapter);
} else if (adapter->if_flags & BE_IF_FLAGS_VLAN_PROMISCUOUS) {
@@ -1466,6 +1615,7 @@ static int be_get_vf_config(struct net_device *netdev, int vf,
vi->qos = vf_cfg->vlan_tag >> VLAN_PRIO_SHIFT;
memcpy(&vi->mac, vf_cfg->mac_addr, ETH_ALEN);
vi->linkstate = adapter->vf_cfg[vf].plink_tracking;
+ vi->spoofchk = adapter->vf_cfg[vf].spoofchk;
return 0;
}
@@ -1478,7 +1628,7 @@ static int be_set_vf_tvt(struct be_adapter *adapter, int vf, u16 vlan)
int status;
/* Enable Transparent VLAN Tagging */
- status = be_cmd_set_hsw_config(adapter, vlan, vf + 1, vf_if_id, 0);
+ status = be_cmd_set_hsw_config(adapter, vlan, vf + 1, vf_if_id, 0, 0);
if (status)
return status;
@@ -1507,7 +1657,7 @@ static int be_clear_vf_tvt(struct be_adapter *adapter, int vf)
/* Reset Transparent VLAN Tagging. */
status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID, vf + 1,
- vf_cfg->if_handle, 0);
+ vf_cfg->if_handle, 0, 0);
if (status)
return status;
@@ -1642,6 +1792,39 @@ static int be_set_vf_link_state(struct net_device *netdev, int vf,
return 0;
}
+static int be_set_vf_spoofchk(struct net_device *netdev, int vf, bool enable)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
+ u8 spoofchk;
+ int status;
+
+ if (!sriov_enabled(adapter))
+ return -EPERM;
+
+ if (vf >= adapter->num_vfs)
+ return -EINVAL;
+
+ if (BEx_chip(adapter))
+ return -EOPNOTSUPP;
+
+ if (enable == vf_cfg->spoofchk)
+ return 0;
+
+ spoofchk = enable ? ENABLE_MAC_SPOOFCHK : DISABLE_MAC_SPOOFCHK;
+
+ status = be_cmd_set_hsw_config(adapter, 0, vf + 1, vf_cfg->if_handle,
+ 0, spoofchk);
+ if (status) {
+ dev_err(&adapter->pdev->dev,
+ "Spoofchk change on VF %d failed: %#x\n", vf, status);
+ return be_cmd_status(status);
+ }
+
+ vf_cfg->spoofchk = enable;
+ return 0;
+}
+
static void be_aic_update(struct be_aic_obj *aic, u64 rx_pkts, u64 tx_pkts,
ulong now)
{
@@ -1650,61 +1833,110 @@ static void be_aic_update(struct be_aic_obj *aic, u64 rx_pkts, u64 tx_pkts,
aic->jiffies = now;
}
-static void be_eqd_update(struct be_adapter *adapter)
+static int be_get_new_eqd(struct be_eq_obj *eqo)
{
- struct be_set_eqd set_eqd[MAX_EVT_QS];
- int eqd, i, num = 0, start;
+ struct be_adapter *adapter = eqo->adapter;
+ int eqd, start;
struct be_aic_obj *aic;
- struct be_eq_obj *eqo;
struct be_rx_obj *rxo;
struct be_tx_obj *txo;
- u64 rx_pkts, tx_pkts;
+ u64 rx_pkts = 0, tx_pkts = 0;
ulong now;
u32 pps, delta;
+ int i;
- for_all_evt_queues(adapter, eqo, i) {
- aic = &adapter->aic_obj[eqo->idx];
- if (!aic->enable) {
- if (aic->jiffies)
- aic->jiffies = 0;
- eqd = aic->et_eqd;
- goto modify_eqd;
- }
+ aic = &adapter->aic_obj[eqo->idx];
+ if (!aic->enable) {
+ if (aic->jiffies)
+ aic->jiffies = 0;
+ eqd = aic->et_eqd;
+ return eqd;
+ }
- rxo = &adapter->rx_obj[eqo->idx];
+ for_all_rx_queues_on_eq(adapter, eqo, rxo, i) {
do {
start = u64_stats_fetch_begin_irq(&rxo->stats.sync);
- rx_pkts = rxo->stats.rx_pkts;
+ rx_pkts += rxo->stats.rx_pkts;
} while (u64_stats_fetch_retry_irq(&rxo->stats.sync, start));
+ }
- txo = &adapter->tx_obj[eqo->idx];
+ for_all_tx_queues_on_eq(adapter, eqo, txo, i) {
do {
start = u64_stats_fetch_begin_irq(&txo->stats.sync);
- tx_pkts = txo->stats.tx_reqs;
+ tx_pkts += txo->stats.tx_reqs;
} while (u64_stats_fetch_retry_irq(&txo->stats.sync, start));
+ }
- /* Skip, if wrapped around or first calculation */
- now = jiffies;
- if (!aic->jiffies || time_before(now, aic->jiffies) ||
- rx_pkts < aic->rx_pkts_prev ||
- tx_pkts < aic->tx_reqs_prev) {
- be_aic_update(aic, rx_pkts, tx_pkts, now);
- continue;
- }
+ /* Skip, if wrapped around or first calculation */
+ now = jiffies;
+ if (!aic->jiffies || time_before(now, aic->jiffies) ||
+ rx_pkts < aic->rx_pkts_prev ||
+ tx_pkts < aic->tx_reqs_prev) {
+ be_aic_update(aic, rx_pkts, tx_pkts, now);
+ return aic->prev_eqd;
+ }
- delta = jiffies_to_msecs(now - aic->jiffies);
- pps = (((u32)(rx_pkts - aic->rx_pkts_prev) * 1000) / delta) +
- (((u32)(tx_pkts - aic->tx_reqs_prev) * 1000) / delta);
- eqd = (pps / 15000) << 2;
+ delta = jiffies_to_msecs(now - aic->jiffies);
+ if (delta == 0)
+ return aic->prev_eqd;
- if (eqd < 8)
- eqd = 0;
- eqd = min_t(u32, eqd, aic->max_eqd);
- eqd = max_t(u32, eqd, aic->min_eqd);
+ pps = (((u32)(rx_pkts - aic->rx_pkts_prev) * 1000) / delta) +
+ (((u32)(tx_pkts - aic->tx_reqs_prev) * 1000) / delta);
+ eqd = (pps / 15000) << 2;
- be_aic_update(aic, rx_pkts, tx_pkts, now);
-modify_eqd:
- if (eqd != aic->prev_eqd) {
+ if (eqd < 8)
+ eqd = 0;
+ eqd = min_t(u32, eqd, aic->max_eqd);
+ eqd = max_t(u32, eqd, aic->min_eqd);
+
+ be_aic_update(aic, rx_pkts, tx_pkts, now);
+
+ return eqd;
+}
+
+/* For Skyhawk-R only */
+static u32 be_get_eq_delay_mult_enc(struct be_eq_obj *eqo)
+{
+ struct be_adapter *adapter = eqo->adapter;
+ struct be_aic_obj *aic = &adapter->aic_obj[eqo->idx];
+ ulong now = jiffies;
+ int eqd;
+ u32 mult_enc;
+
+ if (!aic->enable)
+ return 0;
+
+ if (time_before_eq(now, aic->jiffies) ||
+ jiffies_to_msecs(now - aic->jiffies) < 1)
+ eqd = aic->prev_eqd;
+ else
+ eqd = be_get_new_eqd(eqo);
+
+ if (eqd > 100)
+ mult_enc = R2I_DLY_ENC_1;
+ else if (eqd > 60)
+ mult_enc = R2I_DLY_ENC_2;
+ else if (eqd > 20)
+ mult_enc = R2I_DLY_ENC_3;
+ else
+ mult_enc = R2I_DLY_ENC_0;
+
+ aic->prev_eqd = eqd;
+
+ return mult_enc;
+}
+
+void be_eqd_update(struct be_adapter *adapter, bool force_update)
+{
+ struct be_set_eqd set_eqd[MAX_EVT_QS];
+ struct be_aic_obj *aic;
+ struct be_eq_obj *eqo;
+ int i, num = 0, eqd;
+
+ for_all_evt_queues(adapter, eqo, i) {
+ aic = &adapter->aic_obj[eqo->idx];
+ eqd = be_get_new_eqd(eqo);
+ if (force_update || eqd != aic->prev_eqd) {
set_eqd[num].delay_multiplier = (eqd * 65)/100;
set_eqd[num].eq_id = eqo->q.id;
aic->prev_eqd = eqd;
@@ -2212,7 +2444,7 @@ static void be_eq_clean(struct be_eq_obj *eqo)
{
int num = events_get(eqo);
- be_eq_notify(eqo->adapter, eqo->q.id, false, true, num);
+ be_eq_notify(eqo->adapter, eqo->q.id, false, true, num, 0);
}
static void be_rx_cq_clean(struct be_rx_obj *rxo)
@@ -2236,7 +2468,9 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo)
if (lancer_chip(adapter))
break;
- if (flush_wait++ > 10 || be_hw_error(adapter)) {
+ if (flush_wait++ > 50 ||
+ be_check_error(adapter,
+ BE_ERROR_HW)) {
dev_warn(&adapter->pdev->dev,
"did not receive flush compl\n");
break;
@@ -2297,7 +2531,8 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
pending_txqs--;
}
- if (pending_txqs == 0 || ++timeo > 10 || be_hw_error(adapter))
+ if (pending_txqs == 0 || ++timeo > 10 ||
+ be_check_error(adapter, BE_ERROR_HW))
break;
mdelay(1);
@@ -2573,7 +2808,7 @@ static irqreturn_t be_intx(int irq, void *dev)
if (num_evts)
eqo->spurious_intr = 0;
}
- be_eq_notify(adapter, eqo->q.id, false, true, num_evts);
+ be_eq_notify(adapter, eqo->q.id, false, true, num_evts, 0);
/* Return IRQ_HANDLED only for the the first spurious intr
* after a valid intr to stop the kernel from branding
@@ -2589,7 +2824,7 @@ static irqreturn_t be_msix(int irq, void *dev)
{
struct be_eq_obj *eqo = dev;
- be_eq_notify(eqo->adapter, eqo->q.id, false, true, 0);
+ be_eq_notify(eqo->adapter, eqo->q.id, false, true, 0, 0);
napi_schedule(&eqo->napi);
return IRQ_HANDLED;
}
@@ -2838,6 +3073,7 @@ int be_poll(struct napi_struct *napi, int budget)
int max_work = 0, work, i, num_evts;
struct be_rx_obj *rxo;
struct be_tx_obj *txo;
+ u32 mult_enc = 0;
num_evts = events_get(eqo);
@@ -2863,10 +3099,18 @@ int be_poll(struct napi_struct *napi, int budget)
if (max_work < budget) {
napi_complete(napi);
- be_eq_notify(adapter, eqo->q.id, true, false, num_evts);
+
+ /* Skyhawk EQ_DB has a provision to set the rearm to interrupt
+ * delay via a delay multiplier encoding value
+ */
+ if (skyhawk_chip(adapter))
+ mult_enc = be_get_eq_delay_mult_enc(eqo);
+
+ be_eq_notify(adapter, eqo->q.id, true, false, num_evts,
+ mult_enc);
} else {
/* As we'll continue in polling mode, count and clear events */
- be_eq_notify(adapter, eqo->q.id, false, false, num_evts);
+ be_eq_notify(adapter, eqo->q.id, false, false, num_evts, 0);
}
return max_work;
}
@@ -2898,22 +3142,19 @@ void be_detect_error(struct be_adapter *adapter)
u32 ue_lo = 0, ue_hi = 0, ue_lo_mask = 0, ue_hi_mask = 0;
u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
u32 i;
- bool error_detected = false;
struct device *dev = &adapter->pdev->dev;
- struct net_device *netdev = adapter->netdev;
- if (be_hw_error(adapter))
+ if (be_check_error(adapter, BE_ERROR_HW))
return;
if (lancer_chip(adapter)) {
sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET);
if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
+ be_set_error(adapter, BE_ERROR_UE);
sliport_err1 = ioread32(adapter->db +
SLIPORT_ERROR1_OFFSET);
sliport_err2 = ioread32(adapter->db +
SLIPORT_ERROR2_OFFSET);
- adapter->hw_error = true;
- error_detected = true;
/* Do not log error messages if its a FW reset */
if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 &&
sliport_err2 == SLIPORT_ERROR_FW_RESET2) {
@@ -2945,12 +3186,12 @@ void be_detect_error(struct be_adapter *adapter)
*/
if (ue_lo || ue_hi) {
- error_detected = true;
dev_err(dev,
"Unrecoverable Error detected in the adapter");
dev_err(dev, "Please reboot server to recover");
if (skyhawk_chip(adapter))
- adapter->hw_error = true;
+ be_set_error(adapter, BE_ERROR_UE);
+
for (i = 0; ue_lo; ue_lo >>= 1, i++) {
if (ue_lo & 1)
dev_err(dev, "UE: %s bit set\n",
@@ -2963,8 +3204,6 @@ void be_detect_error(struct be_adapter *adapter)
}
}
}
- if (error_detected)
- netif_carrier_off(netdev);
}
static void be_msix_disable(struct be_adapter *adapter)
@@ -3015,7 +3254,7 @@ fail:
dev_warn(dev, "MSIx enable failed\n");
/* INTx is not supported in VFs, so fail probe if enable_msix fails */
- if (!be_physfn(adapter))
+ if (be_virtfn(adapter))
return num_vec;
return 0;
}
@@ -3062,7 +3301,7 @@ static int be_irq_register(struct be_adapter *adapter)
if (status == 0)
goto done;
/* INTx is not supported for VF */
- if (!be_physfn(adapter))
+ if (be_virtfn(adapter))
return status;
}
@@ -3229,9 +3468,12 @@ static int be_rx_qs_create(struct be_adapter *adapter)
memcpy(rss->rss_hkey, rss_key, RSS_HASH_KEY_LEN);
- /* First time posting */
+ /* Post 1 less than RXQ-len to avoid head being equal to tail,
+ * which is a queue empty condition
+ */
for_all_rx_queues(adapter, rxo, i)
- be_post_rx_frags(rxo, GFP_KERNEL, MAX_RX_POST);
+ be_post_rx_frags(rxo, GFP_KERNEL, RX_Q_LEN - 1);
+
return 0;
}
@@ -3263,7 +3505,7 @@ static int be_open(struct net_device *netdev)
for_all_evt_queues(adapter, eqo, i) {
napi_enable(&eqo->napi);
be_enable_busy_poll(eqo);
- be_eq_notify(adapter, eqo->q.id, true, true, 0);
+ be_eq_notify(adapter, eqo->q.id, true, true, 0, 0);
}
adapter->flags |= BE_FLAGS_NAPI_ENABLED;
@@ -3563,7 +3805,7 @@ static int be_vfs_if_create(struct be_adapter *adapter)
/* If a FW profile exists, then cap_flags are updated */
cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
- BE_IF_FLAGS_MULTICAST;
+ BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS;
for_all_vfs(adapter, vf_cfg, vf) {
if (!BE3_chip(adapter)) {
@@ -3610,6 +3852,7 @@ static int be_vf_setup(struct be_adapter *adapter)
struct device *dev = &adapter->pdev->dev;
struct be_vf_cfg *vf_cfg;
int status, old_vfs, vf;
+ bool spoofchk;
old_vfs = pci_num_vf(adapter->pdev);
@@ -3657,6 +3900,12 @@ static int be_vf_setup(struct be_adapter *adapter)
if (!old_vfs)
be_cmd_config_qos(adapter, 0, 0, vf + 1);
+ status = be_cmd_get_hsw_config(adapter, NULL, vf + 1,
+ vf_cfg->if_handle, NULL,
+ &spoofchk);
+ if (!status)
+ vf_cfg->spoofchk = spoofchk;
+
if (!old_vfs) {
be_cmd_enable_vf(adapter, vf + 1);
be_cmd_set_logical_link_config(adapter,
@@ -3733,8 +3982,9 @@ static void BEx_get_resources(struct be_adapter *adapter,
* *only* if it is RSS-capable.
*/
if (BE2_chip(adapter) || use_sriov || (adapter->port_num > 1) ||
- !be_physfn(adapter) || (be_is_mc(adapter) &&
- !(adapter->function_caps & BE_FUNCTION_CAPS_RSS))) {
+ be_virtfn(adapter) ||
+ (be_is_mc(adapter) &&
+ !(adapter->function_caps & BE_FUNCTION_CAPS_RSS))) {
res->max_tx_qs = 1;
} else if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC) {
struct be_resources super_nic_res = {0};
@@ -4075,7 +4325,7 @@ static int be_func_init(struct be_adapter *adapter)
msleep(100);
/* We can clear all errors when function reset succeeds */
- be_clear_all_error(adapter);
+ be_clear_error(adapter, BE_CLEAR_ALL);
}
/* Tell FW we're ready to fire cmds */
@@ -4182,7 +4432,7 @@ static void be_netpoll(struct net_device *netdev)
int i;
for_all_evt_queues(adapter, eqo, i) {
- be_eq_notify(eqo->adapter, eqo->q.id, false, true, 0);
+ be_eq_notify(eqo->adapter, eqo->q.id, false, true, 0, 0);
napi_schedule(&eqo->napi);
}
}
@@ -4666,14 +4916,11 @@ static int lancer_fw_download(struct be_adapter *adapter,
return 0;
}
-#define BE2_UFI 2
-#define BE3_UFI 3
-#define BE3R_UFI 10
-#define SH_UFI 4
-#define SH_P2_UFI 11
-
-static int be_get_ufi_type(struct be_adapter *adapter,
- struct flash_file_hdr_g3 *fhdr)
+/* Check if the flash image file is compatible with the adapter that
+ * is being flashed.
+ */
+static bool be_check_ufi_compatibility(struct be_adapter *adapter,
+ struct flash_file_hdr_g3 *fhdr)
{
if (!fhdr) {
dev_err(&adapter->pdev->dev, "Invalid FW UFI file");
@@ -4685,43 +4932,22 @@ static int be_get_ufi_type(struct be_adapter *adapter,
*/
switch (fhdr->build[0]) {
case BLD_STR_UFI_TYPE_SH:
- return (fhdr->asic_type_rev == ASIC_REV_P2) ? SH_P2_UFI :
- SH_UFI;
+ if (!skyhawk_chip(adapter))
+ return false;
+ break;
case BLD_STR_UFI_TYPE_BE3:
- return (fhdr->asic_type_rev == ASIC_REV_B0) ? BE3R_UFI :
- BE3_UFI;
+ if (!BE3_chip(adapter))
+ return false;
+ break;
case BLD_STR_UFI_TYPE_BE2:
- return BE2_UFI;
- default:
- return -1;
- }
-}
-
-/* Check if the flash image file is compatible with the adapter that
- * is being flashed.
- * BE3 chips with asic-rev B0 must be flashed only with BE3R_UFI type.
- * Skyhawk chips with asic-rev P2 must be flashed only with SH_P2_UFI type.
- */
-static bool be_check_ufi_compatibility(struct be_adapter *adapter,
- struct flash_file_hdr_g3 *fhdr)
-{
- int ufi_type = be_get_ufi_type(adapter, fhdr);
-
- switch (ufi_type) {
- case SH_P2_UFI:
- return skyhawk_chip(adapter);
- case SH_UFI:
- return (skyhawk_chip(adapter) &&
- adapter->asic_rev < ASIC_REV_P2);
- case BE3R_UFI:
- return BE3_chip(adapter);
- case BE3_UFI:
- return (BE3_chip(adapter) && adapter->asic_rev < ASIC_REV_B0);
- case BE2_UFI:
- return BE2_chip(adapter);
+ if (!BE2_chip(adapter))
+ return false;
+ break;
default:
return false;
}
+
+ return (fhdr->asic_type_rev >= adapter->asic_rev);
}
static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw)
@@ -4829,7 +5055,7 @@ static int be_ndo_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
adapter->if_handle,
mode == BRIDGE_MODE_VEPA ?
PORT_FWD_TYPE_VEPA :
- PORT_FWD_TYPE_VEB);
+ PORT_FWD_TYPE_VEB, 0);
if (status)
goto err;
@@ -4861,7 +5087,8 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
hsw_mode = PORT_FWD_TYPE_VEB;
} else {
status = be_cmd_get_hsw_config(adapter, NULL, 0,
- adapter->if_handle, &hsw_mode);
+ adapter->if_handle, &hsw_mode,
+ NULL);
if (status)
return 0;
}
@@ -4869,7 +5096,7 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
return ndo_dflt_bridge_getlink(skb, pid, seq, dev,
hsw_mode == PORT_FWD_TYPE_VEPA ?
BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB,
- 0, 0, nlflags);
+ 0, 0, nlflags, filter_mask, NULL);
}
#ifdef CONFIG_BE2NET_VXLAN
@@ -5014,6 +5241,7 @@ static const struct net_device_ops be_netdev_ops = {
.ndo_set_vf_rate = be_set_vf_tx_rate,
.ndo_get_vf_config = be_get_vf_config,
.ndo_set_vf_link_state = be_set_vf_link_state,
+ .ndo_set_vf_spoofchk = be_set_vf_spoofchk,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = be_netpoll,
#endif
@@ -5118,7 +5346,7 @@ static void be_err_detection_task(struct work_struct *work)
be_detect_error(adapter);
- if (adapter->hw_error) {
+ if (be_check_error(adapter, BE_ERROR_HW)) {
be_cleanup(adapter);
/* As of now error recovery support is in Lancer only */
@@ -5182,7 +5410,9 @@ static void be_worker(struct work_struct *work)
be_post_rx_frags(rxo, GFP_KERNEL, MAX_RX_POST);
}
- be_eqd_update(adapter);
+ /* EQ-delay update for Skyhawk is done while notifying EQ */
+ if (!skyhawk_chip(adapter))
+ be_eqd_update(adapter, false);
if (adapter->flags & BE_FLAGS_EVT_INCOMPATIBLE_SFP)
be_log_sfp_info(adapter);
@@ -5202,7 +5432,7 @@ static void be_unmap_pci_bars(struct be_adapter *adapter)
static int db_bar(struct be_adapter *adapter)
{
- if (lancer_chip(adapter) || !be_physfn(adapter))
+ if (lancer_chip(adapter) || be_virtfn(adapter))
return 0;
else
return 4;
@@ -5381,6 +5611,30 @@ static void be_remove(struct pci_dev *pdev)
free_netdev(adapter->netdev);
}
+static ssize_t be_hwmon_show_temp(struct device *dev,
+ struct device_attribute *dev_attr,
+ char *buf)
+{
+ struct be_adapter *adapter = dev_get_drvdata(dev);
+
+ /* Unit: millidegree Celsius */
+ if (adapter->hwmon_info.be_on_die_temp == BE_INVALID_DIE_TEMP)
+ return -EIO;
+ else
+ return sprintf(buf, "%u\n",
+ adapter->hwmon_info.be_on_die_temp * 1000);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+ be_hwmon_show_temp, NULL, 1);
+
+static struct attribute *be_hwmon_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ NULL
+};
+
+ATTRIBUTE_GROUPS(be_hwmon);
+
static char *mc_name(struct be_adapter *adapter)
{
char *str = ""; /* default */
@@ -5500,6 +5754,16 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
be_schedule_err_detection(adapter);
+ /* On Die temperature not supported for VF. */
+ if (be_physfn(adapter) && IS_ENABLED(CONFIG_BE2NET_HWMON)) {
+ adapter->hwmon_info.hwmon_dev =
+ devm_hwmon_device_register_with_groups(&pdev->dev,
+ DRV_NAME,
+ adapter,
+ be_hwmon_groups);
+ adapter->hwmon_info.be_on_die_temp = BE_INVALID_DIE_TEMP;
+ }
+
dev_info(&pdev->dev, "%s: %s %s port %c\n", nic_name(pdev),
func_name(adapter), mc_name(adapter), adapter->port_name);
@@ -5592,8 +5856,8 @@ static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev,
dev_err(&adapter->pdev->dev, "EEH error detected\n");
- if (!adapter->eeh_error) {
- adapter->eeh_error = true;
+ if (!be_check_error(adapter, BE_ERROR_EEH)) {
+ be_set_error(adapter, BE_ERROR_EEH);
be_cancel_err_detection(adapter);
@@ -5640,7 +5904,7 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev)
return PCI_ERS_RESULT_DISCONNECT;
pci_cleanup_aer_uncorrect_error_status(pdev);
- be_clear_all_error(adapter);
+ be_clear_error(adapter, BE_CLEAR_ALL);
return PCI_ERS_RESULT_RECOVERED;
}
diff --git a/drivers/net/ethernet/emulex/benet/be_roce.c b/drivers/net/ethernet/emulex/benet/be_roce.c
index 132866433a25..60368207bf58 100644
--- a/drivers/net/ethernet/emulex/benet/be_roce.c
+++ b/drivers/net/ethernet/emulex/benet/be_roce.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/net/ethernet/emulex/benet/be_roce.h b/drivers/net/ethernet/emulex/benet/be_roce.h
index e6f7eb1a7d87..cde6ef905ec4 100644
--- a/drivers/net/ethernet/emulex/benet/be_roce.h
+++ b/drivers/net/ethernet/emulex/benet/be_roce.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2014 Emulex
+ * Copyright (C) 2005 - 2015 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/net/ethernet/ezchip/Kconfig b/drivers/net/ethernet/ezchip/Kconfig
new file mode 100644
index 000000000000..48ecbc8aaaea
--- /dev/null
+++ b/drivers/net/ethernet/ezchip/Kconfig
@@ -0,0 +1,26 @@
+#
+# EZchip network device configuration
+#
+
+config NET_VENDOR_EZCHIP
+ bool "EZchip devices"
+ default y
+ ---help---
+ If you have a network (Ethernet) device belonging to this class, say Y.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about EZchip devices. If you say Y, you will be asked for
+ your specific device in the following questions.
+
+if NET_VENDOR_EZCHIP
+
+config EZCHIP_NPS_MANAGEMENT_ENET
+ tristate "EZchip NPS management enet support"
+ depends on OF_IRQ && OF_NET
+ ---help---
+ Simple LAN device for debug or management purposes.
+ Device supports interrupts for RX and TX(completion).
+ Device does not have DMA ability.
+
+endif
diff --git a/drivers/net/ethernet/ezchip/Makefile b/drivers/net/ethernet/ezchip/Makefile
new file mode 100644
index 000000000000..e490176a8137
--- /dev/null
+++ b/drivers/net/ethernet/ezchip/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_EZCHIP_NPS_MANAGEMENT_ENET) += nps_enet.o
diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c
new file mode 100644
index 000000000000..24a85b292007
--- /dev/null
+++ b/drivers/net/ethernet/ezchip/nps_enet.c
@@ -0,0 +1,658 @@
+/*
+ * Copyright(c) 2015 EZchip Technologies.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ */
+
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include "nps_enet.h"
+
+#define DRV_NAME "nps_mgt_enet"
+
+static void nps_enet_clean_rx_fifo(struct net_device *ndev, u32 frame_len)
+{
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+ u32 i, len = DIV_ROUND_UP(frame_len, sizeof(u32));
+
+ /* Empty Rx FIFO buffer by reading all words */
+ for (i = 0; i < len; i++)
+ nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
+}
+
+static void nps_enet_read_rx_fifo(struct net_device *ndev,
+ unsigned char *dst, u32 length)
+{
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+ s32 i, last = length & (sizeof(u32) - 1);
+ u32 *reg = (u32 *)dst, len = length / sizeof(u32);
+ bool dst_is_aligned = IS_ALIGNED((unsigned long)dst, sizeof(u32));
+
+ /* In case dst is not aligned we need an intermediate buffer */
+ if (dst_is_aligned)
+ for (i = 0; i < len; i++, reg++)
+ *reg = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
+ else { /* !dst_is_aligned */
+ for (i = 0; i < len; i++, reg++) {
+ u32 buf =
+ nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
+
+ /* to accommodate word-unaligned address of "reg"
+ * we have to do memcpy_toio() instead of simple "=".
+ */
+ memcpy_toio((void __iomem *)reg, &buf, sizeof(buf));
+ }
+ }
+
+ /* copy last bytes (if any) */
+ if (last) {
+ u32 buf = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
+
+ memcpy_toio((void __iomem *)reg, &buf, last);
+ }
+}
+
+static u32 nps_enet_rx_handler(struct net_device *ndev)
+{
+ u32 frame_len, err = 0;
+ u32 work_done = 0;
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+ struct sk_buff *skb;
+ struct nps_enet_rx_ctl rx_ctrl;
+
+ rx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_RX_CTL);
+ frame_len = rx_ctrl.nr;
+
+ /* Check if we got RX */
+ if (!rx_ctrl.cr)
+ return work_done;
+
+ /* If we got here there is a work for us */
+ work_done++;
+
+ /* Check Rx error */
+ if (rx_ctrl.er) {
+ ndev->stats.rx_errors++;
+ err = 1;
+ }
+
+ /* Check Rx CRC error */
+ if (rx_ctrl.crc) {
+ ndev->stats.rx_crc_errors++;
+ ndev->stats.rx_dropped++;
+ err = 1;
+ }
+
+ /* Check Frame length Min 64b */
+ if (unlikely(frame_len < ETH_ZLEN)) {
+ ndev->stats.rx_length_errors++;
+ ndev->stats.rx_dropped++;
+ err = 1;
+ }
+
+ if (err)
+ goto rx_irq_clean;
+
+ /* Skb allocation */
+ skb = netdev_alloc_skb_ip_align(ndev, frame_len);
+ if (unlikely(!skb)) {
+ ndev->stats.rx_errors++;
+ ndev->stats.rx_dropped++;
+ goto rx_irq_clean;
+ }
+
+ /* Copy frame from Rx fifo into the skb */
+ nps_enet_read_rx_fifo(ndev, skb->data, frame_len);
+
+ skb_put(skb, frame_len);
+ skb->protocol = eth_type_trans(skb, ndev);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += frame_len;
+ netif_receive_skb(skb);
+
+ goto rx_irq_frame_done;
+
+rx_irq_clean:
+ /* Clean Rx fifo */
+ nps_enet_clean_rx_fifo(ndev, frame_len);
+
+rx_irq_frame_done:
+ /* Ack Rx ctrl register */
+ nps_enet_reg_set(priv, NPS_ENET_REG_RX_CTL, 0);
+
+ return work_done;
+}
+
+static void nps_enet_tx_handler(struct net_device *ndev)
+{
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+ struct nps_enet_tx_ctl tx_ctrl;
+
+ tx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_TX_CTL);
+
+ /* Check if we got TX */
+ if (!priv->tx_packet_sent || tx_ctrl.ct)
+ return;
+
+ /* Check Tx transmit error */
+ if (unlikely(tx_ctrl.et)) {
+ ndev->stats.tx_errors++;
+ } else {
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += tx_ctrl.nt;
+ }
+
+ if (priv->tx_skb) {
+ dev_kfree_skb(priv->tx_skb);
+ priv->tx_skb = NULL;
+ }
+
+ priv->tx_packet_sent = false;
+
+ if (netif_queue_stopped(ndev))
+ netif_wake_queue(ndev);
+}
+
+/**
+ * nps_enet_poll - NAPI poll handler.
+ * @napi: Pointer to napi_struct structure.
+ * @budget: How many frames to process on one call.
+ *
+ * returns: Number of processed frames
+ */
+static int nps_enet_poll(struct napi_struct *napi, int budget)
+{
+ struct net_device *ndev = napi->dev;
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+ struct nps_enet_buf_int_enable buf_int_enable;
+ u32 work_done;
+
+ buf_int_enable.rx_rdy = NPS_ENET_ENABLE;
+ buf_int_enable.tx_done = NPS_ENET_ENABLE;
+ nps_enet_tx_handler(ndev);
+ work_done = nps_enet_rx_handler(ndev);
+ if (work_done < budget) {
+ napi_complete(napi);
+ nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE,
+ buf_int_enable.value);
+ }
+
+ return work_done;
+}
+
+/**
+ * nps_enet_irq_handler - Global interrupt handler for ENET.
+ * @irq: irq number.
+ * @dev_instance: device instance.
+ *
+ * returns: IRQ_HANDLED for all cases.
+ *
+ * EZchip ENET has 2 interrupt causes, and depending on bits raised in
+ * CTRL registers we may tell what is a reason for interrupt to fire up.
+ * We got one for RX and the other for TX (completion).
+ */
+static irqreturn_t nps_enet_irq_handler(s32 irq, void *dev_instance)
+{
+ struct net_device *ndev = dev_instance;
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+ struct nps_enet_buf_int_cause buf_int_cause;
+
+ buf_int_cause.value =
+ nps_enet_reg_get(priv, NPS_ENET_REG_BUF_INT_CAUSE);
+
+ if (buf_int_cause.tx_done || buf_int_cause.rx_rdy)
+ if (likely(napi_schedule_prep(&priv->napi))) {
+ nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0);
+ __napi_schedule(&priv->napi);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void nps_enet_set_hw_mac_address(struct net_device *ndev)
+{
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+ struct nps_enet_ge_mac_cfg_1 ge_mac_cfg_1;
+ struct nps_enet_ge_mac_cfg_2 *ge_mac_cfg_2 = &priv->ge_mac_cfg_2;
+
+ /* set MAC address in HW */
+ ge_mac_cfg_1.octet_0 = ndev->dev_addr[0];
+ ge_mac_cfg_1.octet_1 = ndev->dev_addr[1];
+ ge_mac_cfg_1.octet_2 = ndev->dev_addr[2];
+ ge_mac_cfg_1.octet_3 = ndev->dev_addr[3];
+ ge_mac_cfg_2->octet_4 = ndev->dev_addr[4];
+ ge_mac_cfg_2->octet_5 = ndev->dev_addr[5];
+
+ nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_1,
+ ge_mac_cfg_1.value);
+
+ nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2,
+ ge_mac_cfg_2->value);
+}
+
+/**
+ * nps_enet_hw_reset - Reset the network device.
+ * @ndev: Pointer to the network device.
+ *
+ * This function reset the PCS and TX fifo.
+ * The programming model is to set the relevant reset bits
+ * wait for some time for this to propagate and then unset
+ * the reset bits. This way we ensure that reset procedure
+ * is done successfully by device.
+ */
+static void nps_enet_hw_reset(struct net_device *ndev)
+{
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+ struct nps_enet_ge_rst ge_rst;
+ struct nps_enet_phase_fifo_ctl phase_fifo_ctl;
+
+ ge_rst.value = 0;
+ phase_fifo_ctl.value = 0;
+ /* Pcs reset sequence*/
+ ge_rst.gmac_0 = NPS_ENET_ENABLE;
+ nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst.value);
+ usleep_range(10, 20);
+ ge_rst.value = 0;
+ nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst.value);
+
+ /* Tx fifo reset sequence */
+ phase_fifo_ctl.rst = NPS_ENET_ENABLE;
+ phase_fifo_ctl.init = NPS_ENET_ENABLE;
+ nps_enet_reg_set(priv, NPS_ENET_REG_PHASE_FIFO_CTL,
+ phase_fifo_ctl.value);
+ usleep_range(10, 20);
+ phase_fifo_ctl.value = 0;
+ nps_enet_reg_set(priv, NPS_ENET_REG_PHASE_FIFO_CTL,
+ phase_fifo_ctl.value);
+}
+
+static void nps_enet_hw_enable_control(struct net_device *ndev)
+{
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+ struct nps_enet_ge_mac_cfg_0 ge_mac_cfg_0;
+ struct nps_enet_buf_int_enable buf_int_enable;
+ struct nps_enet_ge_mac_cfg_2 *ge_mac_cfg_2 = &priv->ge_mac_cfg_2;
+ struct nps_enet_ge_mac_cfg_3 *ge_mac_cfg_3 = &priv->ge_mac_cfg_3;
+ s32 max_frame_length;
+
+ ge_mac_cfg_0.value = 0;
+ buf_int_enable.value = 0;
+ /* Enable Rx and Tx statistics */
+ ge_mac_cfg_2->stat_en = NPS_ENET_GE_MAC_CFG_2_STAT_EN;
+
+ /* Discard packets with different MAC address */
+ ge_mac_cfg_2->disc_da = NPS_ENET_ENABLE;
+
+ /* Discard multicast packets */
+ ge_mac_cfg_2->disc_mc = NPS_ENET_ENABLE;
+
+ nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2,
+ ge_mac_cfg_2->value);
+
+ /* Discard Packets bigger than max frame length */
+ max_frame_length = ETH_HLEN + ndev->mtu + ETH_FCS_LEN;
+ if (max_frame_length <= NPS_ENET_MAX_FRAME_LENGTH) {
+ ge_mac_cfg_3->max_len = max_frame_length;
+ nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_3,
+ ge_mac_cfg_3->value);
+ }
+
+ /* Enable interrupts */
+ buf_int_enable.rx_rdy = NPS_ENET_ENABLE;
+ buf_int_enable.tx_done = NPS_ENET_ENABLE;
+ nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE,
+ buf_int_enable.value);
+
+ /* Write device MAC address to HW */
+ nps_enet_set_hw_mac_address(ndev);
+
+ /* Rx and Tx HW features */
+ ge_mac_cfg_0.tx_pad_en = NPS_ENET_ENABLE;
+ ge_mac_cfg_0.tx_crc_en = NPS_ENET_ENABLE;
+ ge_mac_cfg_0.rx_crc_strip = NPS_ENET_ENABLE;
+
+ /* IFG configuration */
+ ge_mac_cfg_0.rx_ifg = NPS_ENET_GE_MAC_CFG_0_RX_IFG;
+ ge_mac_cfg_0.tx_ifg = NPS_ENET_GE_MAC_CFG_0_TX_IFG;
+
+ /* preamble configuration */
+ ge_mac_cfg_0.rx_pr_check_en = NPS_ENET_ENABLE;
+ ge_mac_cfg_0.tx_pr_len = NPS_ENET_GE_MAC_CFG_0_TX_PR_LEN;
+
+ /* enable flow control frames */
+ ge_mac_cfg_0.tx_fc_en = NPS_ENET_ENABLE;
+ ge_mac_cfg_0.rx_fc_en = NPS_ENET_ENABLE;
+ ge_mac_cfg_0.tx_fc_retr = NPS_ENET_GE_MAC_CFG_0_TX_FC_RETR;
+
+ /* Enable Rx and Tx */
+ ge_mac_cfg_0.rx_en = NPS_ENET_ENABLE;
+ ge_mac_cfg_0.tx_en = NPS_ENET_ENABLE;
+
+ nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_0,
+ ge_mac_cfg_0.value);
+}
+
+static void nps_enet_hw_disable_control(struct net_device *ndev)
+{
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+
+ /* Disable interrupts */
+ nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0);
+
+ /* Disable Rx and Tx */
+ nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_0, 0);
+}
+
+static void nps_enet_send_frame(struct net_device *ndev,
+ struct sk_buff *skb)
+{
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+ struct nps_enet_tx_ctl tx_ctrl;
+ short length = skb->len;
+ u32 i, len = DIV_ROUND_UP(length, sizeof(u32));
+ u32 *src = (u32 *)virt_to_phys(skb->data);
+ bool src_is_aligned = IS_ALIGNED((unsigned long)src, sizeof(u32));
+
+ tx_ctrl.value = 0;
+ /* In case src is not aligned we need an intermediate buffer */
+ if (src_is_aligned)
+ for (i = 0; i < len; i++, src++)
+ nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, *src);
+ else { /* !src_is_aligned */
+ for (i = 0; i < len; i++, src++) {
+ u32 buf;
+
+ /* to accommodate word-unaligned address of "src"
+ * we have to do memcpy_fromio() instead of simple "="
+ */
+ memcpy_fromio(&buf, (void __iomem *)src, sizeof(buf));
+ nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, buf);
+ }
+ }
+ /* Write the length of the Frame */
+ tx_ctrl.nt = length;
+
+ /* Indicate SW is done */
+ priv->tx_packet_sent = true;
+ tx_ctrl.ct = NPS_ENET_ENABLE;
+
+ /* Send Frame */
+ nps_enet_reg_set(priv, NPS_ENET_REG_TX_CTL, tx_ctrl.value);
+}
+
+/**
+ * nps_enet_set_mac_address - Set the MAC address for this device.
+ * @ndev: Pointer to net_device structure.
+ * @p: 6 byte Address to be written as MAC address.
+ *
+ * This function copies the HW address from the sockaddr structure to the
+ * net_device structure and updates the address in HW.
+ *
+ * returns: -EBUSY if the net device is busy or 0 if the address is set
+ * successfully.
+ */
+static s32 nps_enet_set_mac_address(struct net_device *ndev, void *p)
+{
+ struct sockaddr *addr = p;
+ s32 res;
+
+ if (netif_running(ndev))
+ return -EBUSY;
+
+ res = eth_mac_addr(ndev, p);
+ if (!res) {
+ ether_addr_copy(ndev->dev_addr, addr->sa_data);
+ nps_enet_set_hw_mac_address(ndev);
+ }
+
+ return res;
+}
+
+/**
+ * nps_enet_set_rx_mode - Change the receive filtering mode.
+ * @ndev: Pointer to the network device.
+ *
+ * This function enables/disables promiscuous mode
+ */
+static void nps_enet_set_rx_mode(struct net_device *ndev)
+{
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+ struct nps_enet_ge_mac_cfg_2 ge_mac_cfg_2;
+
+ ge_mac_cfg_2.value = priv->ge_mac_cfg_2.value;
+
+ if (ndev->flags & IFF_PROMISC) {
+ ge_mac_cfg_2.disc_da = NPS_ENET_DISABLE;
+ ge_mac_cfg_2.disc_mc = NPS_ENET_DISABLE;
+ } else {
+ ge_mac_cfg_2.disc_da = NPS_ENET_ENABLE;
+ ge_mac_cfg_2.disc_mc = NPS_ENET_ENABLE;
+ }
+
+ nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2, ge_mac_cfg_2.value);
+}
+
+/**
+ * nps_enet_open - Open the network device.
+ * @ndev: Pointer to the network device.
+ *
+ * returns: 0, on success or non-zero error value on failure.
+ *
+ * This function sets the MAC address, requests and enables an IRQ
+ * for the ENET device and starts the Tx queue.
+ */
+static s32 nps_enet_open(struct net_device *ndev)
+{
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+ s32 err;
+
+ /* Reset private variables */
+ priv->tx_packet_sent = false;
+ priv->ge_mac_cfg_2.value = 0;
+ priv->ge_mac_cfg_3.value = 0;
+
+ /* ge_mac_cfg_3 default values */
+ priv->ge_mac_cfg_3.rx_ifg_th = NPS_ENET_GE_MAC_CFG_3_RX_IFG_TH;
+ priv->ge_mac_cfg_3.max_len = NPS_ENET_GE_MAC_CFG_3_MAX_LEN;
+
+ /* Disable HW device */
+ nps_enet_hw_disable_control(ndev);
+
+ /* irq Rx allocation */
+ err = request_irq(priv->irq, nps_enet_irq_handler,
+ 0, "enet-rx-tx", ndev);
+ if (err)
+ return err;
+
+ napi_enable(&priv->napi);
+
+ /* Enable HW device */
+ nps_enet_hw_reset(ndev);
+ nps_enet_hw_enable_control(ndev);
+
+ netif_start_queue(ndev);
+
+ return 0;
+}
+
+/**
+ * nps_enet_stop - Close the network device.
+ * @ndev: Pointer to the network device.
+ *
+ * This function stops the Tx queue, disables interrupts for the ENET device.
+ */
+static s32 nps_enet_stop(struct net_device *ndev)
+{
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+
+ napi_disable(&priv->napi);
+ netif_stop_queue(ndev);
+ nps_enet_hw_disable_control(ndev);
+ free_irq(priv->irq, ndev);
+
+ return 0;
+}
+
+/**
+ * nps_enet_start_xmit - Starts the data transmission.
+ * @skb: sk_buff pointer that contains data to be Transmitted.
+ * @ndev: Pointer to net_device structure.
+ *
+ * returns: NETDEV_TX_OK, on success
+ * NETDEV_TX_BUSY, if any of the descriptors are not free.
+ *
+ * This function is invoked from upper layers to initiate transmission.
+ */
+static netdev_tx_t nps_enet_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+
+ /* This driver handles one frame at a time */
+ netif_stop_queue(ndev);
+
+ nps_enet_send_frame(ndev, skb);
+
+ priv->tx_skb = skb;
+
+ return NETDEV_TX_OK;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void nps_enet_poll_controller(struct net_device *ndev)
+{
+ disable_irq(ndev->irq);
+ nps_enet_irq_handler(ndev->irq, ndev);
+ enable_irq(ndev->irq);
+}
+#endif
+
+static const struct net_device_ops nps_netdev_ops = {
+ .ndo_open = nps_enet_open,
+ .ndo_stop = nps_enet_stop,
+ .ndo_start_xmit = nps_enet_start_xmit,
+ .ndo_set_mac_address = nps_enet_set_mac_address,
+ .ndo_set_rx_mode = nps_enet_set_rx_mode,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = nps_enet_poll_controller,
+#endif
+};
+
+static s32 nps_enet_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct net_device *ndev;
+ struct nps_enet_priv *priv;
+ s32 err = 0;
+ const char *mac_addr;
+ struct resource *res_regs;
+
+ if (!dev->of_node)
+ return -ENODEV;
+
+ ndev = alloc_etherdev(sizeof(struct nps_enet_priv));
+ if (!ndev)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ndev);
+ SET_NETDEV_DEV(ndev, dev);
+ priv = netdev_priv(ndev);
+
+ /* The EZ NET specific entries in the device structure. */
+ ndev->netdev_ops = &nps_netdev_ops;
+ ndev->watchdog_timeo = (400 * HZ / 1000);
+ /* FIXME :: no multicast support yet */
+ ndev->flags &= ~IFF_MULTICAST;
+
+ res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->regs_base = devm_ioremap_resource(dev, res_regs);
+ if (IS_ERR(priv->regs_base)) {
+ err = PTR_ERR(priv->regs_base);
+ goto out_netdev;
+ }
+ dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs_base);
+
+ /* set kernel MAC address to dev */
+ mac_addr = of_get_mac_address(dev->of_node);
+ if (mac_addr)
+ ether_addr_copy(ndev->dev_addr, mac_addr);
+ else
+ eth_hw_addr_random(ndev);
+
+ /* Get IRQ number */
+ priv->irq = platform_get_irq(pdev, 0);
+ if (!priv->irq) {
+ dev_err(dev, "failed to retrieve <irq Rx-Tx> value from device tree\n");
+ err = -ENODEV;
+ goto out_netdev;
+ }
+
+ netif_napi_add(ndev, &priv->napi, nps_enet_poll,
+ NPS_ENET_NAPI_POLL_WEIGHT);
+
+ /* Register the driver. Should be the last thing in probe */
+ err = register_netdev(ndev);
+ if (err) {
+ dev_err(dev, "Failed to register ndev for %s, err = 0x%08x\n",
+ ndev->name, (s32)err);
+ goto out_netif_api;
+ }
+
+ dev_info(dev, "(rx/tx=%d)\n", priv->irq);
+ return 0;
+
+out_netif_api:
+ netif_napi_del(&priv->napi);
+out_netdev:
+ if (err)
+ free_netdev(ndev);
+
+ return err;
+}
+
+static s32 nps_enet_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct nps_enet_priv *priv = netdev_priv(ndev);
+
+ unregister_netdev(ndev);
+ free_netdev(ndev);
+ netif_napi_del(&priv->napi);
+
+ return 0;
+}
+
+static const struct of_device_id nps_enet_dt_ids[] = {
+ { .compatible = "ezchip,nps-mgt-enet" },
+ { /* Sentinel */ }
+};
+
+static struct platform_driver nps_enet_driver = {
+ .probe = nps_enet_probe,
+ .remove = nps_enet_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = nps_enet_dt_ids,
+ },
+};
+
+module_platform_driver(nps_enet_driver);
+
+MODULE_AUTHOR("EZchip Semiconductor");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/ezchip/nps_enet.h b/drivers/net/ethernet/ezchip/nps_enet.h
new file mode 100644
index 000000000000..fc45c9daa1c2
--- /dev/null
+++ b/drivers/net/ethernet/ezchip/nps_enet.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright(c) 2015 EZchip Technologies.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ */
+
+#ifndef _NPS_ENET_H
+#define _NPS_ENET_H
+
+/* default values */
+#define NPS_ENET_NAPI_POLL_WEIGHT 0x2
+#define NPS_ENET_MAX_FRAME_LENGTH 0x3FFF
+#define NPS_ENET_GE_MAC_CFG_0_TX_FC_RETR 0x7
+#define NPS_ENET_GE_MAC_CFG_0_RX_IFG 0x5
+#define NPS_ENET_GE_MAC_CFG_0_TX_IFG 0xC
+#define NPS_ENET_GE_MAC_CFG_0_TX_PR_LEN 0x7
+#define NPS_ENET_GE_MAC_CFG_2_STAT_EN 0x3
+#define NPS_ENET_GE_MAC_CFG_3_RX_IFG_TH 0x14
+#define NPS_ENET_GE_MAC_CFG_3_MAX_LEN 0x3FFC
+#define NPS_ENET_ENABLE 1
+#define NPS_ENET_DISABLE 0
+
+/* register definitions */
+#define NPS_ENET_REG_TX_CTL 0x800
+#define NPS_ENET_REG_TX_BUF 0x808
+#define NPS_ENET_REG_RX_CTL 0x810
+#define NPS_ENET_REG_RX_BUF 0x818
+#define NPS_ENET_REG_BUF_INT_ENABLE 0x8C0
+#define NPS_ENET_REG_BUF_INT_CAUSE 0x8C4
+#define NPS_ENET_REG_GE_MAC_CFG_0 0x1000
+#define NPS_ENET_REG_GE_MAC_CFG_1 0x1004
+#define NPS_ENET_REG_GE_MAC_CFG_2 0x1008
+#define NPS_ENET_REG_GE_MAC_CFG_3 0x100C
+#define NPS_ENET_REG_GE_RST 0x1400
+#define NPS_ENET_REG_PHASE_FIFO_CTL 0x1404
+
+/* Tx control register */
+struct nps_enet_tx_ctl {
+ union {
+ /* ct: SW sets to indicate frame ready in Tx buffer for
+ * transmission. HW resets to when transmission done
+ * et: Transmit error
+ * nt: Length in bytes of Tx frame loaded to Tx buffer
+ */
+ struct {
+ u32
+ __reserved_1:16,
+ ct:1,
+ et:1,
+ __reserved_2:3,
+ nt:11;
+ };
+
+ u32 value;
+ };
+};
+
+/* Rx control register */
+struct nps_enet_rx_ctl {
+ union {
+ /* cr: HW sets to indicate frame ready in Rx buffer.
+ * SW resets to indicate host read received frame
+ * and new frames can be written to Rx buffer
+ * er: Rx error indication
+ * crc: Rx CRC error indication
+ * nr: Length in bytes of Rx frame loaded by MAC to Rx buffer
+ */
+ struct {
+ u32
+ __reserved_1:16,
+ cr:1,
+ er:1,
+ crc:1,
+ __reserved_2:2,
+ nr:11;
+ };
+
+ u32 value;
+ };
+};
+
+/* Interrupt enable for data buffer events register */
+struct nps_enet_buf_int_enable {
+ union {
+ /* tx_done: Interrupt generation in the case when new frame
+ * is ready in Rx buffer
+ * rx_rdy: Interrupt generation in the case when current frame
+ * was read from TX buffer
+ */
+ struct {
+ u32
+ __reserved:30,
+ tx_done:1,
+ rx_rdy:1;
+ };
+
+ u32 value;
+ };
+};
+
+/* Interrupt cause for data buffer events register */
+struct nps_enet_buf_int_cause {
+ union {
+ /* tx_done: Interrupt in the case when current frame was
+ * read from TX buffer.
+ * rx_rdy: Interrupt in the case when new frame is ready
+ * in RX buffer.
+ */
+ struct {
+ u32
+ __reserved:30,
+ tx_done:1,
+ rx_rdy:1;
+ };
+
+ u32 value;
+ };
+};
+
+/* Gbps Eth MAC Configuration 0 register */
+struct nps_enet_ge_mac_cfg_0 {
+ union {
+ /* tx_pr_len: Transmit preamble length in bytes
+ * tx_ifg_nib: Tx idle pattern
+ * nib_mode: Nibble (4-bit) Mode
+ * rx_pr_check_en: Receive preamble Check Enable
+ * tx_ifg: Transmit inter-Frame Gap
+ * rx_ifg: Receive inter-Frame Gap
+ * tx_fc_retr: Transmit Flow Control Retransmit Mode
+ * rx_length_check_en: Receive Length Check Enable
+ * rx_crc_ignore: Results of the CRC check are ignored
+ * rx_crc_strip: MAC strips the CRC from received frames
+ * rx_fc_en: Receive Flow Control Enable
+ * tx_crc_en: Transmit CRC Enabled
+ * tx_pad_en: Transmit Padding Enable
+ * tx_cf_en: Transmit Flow Control Enable
+ * tx_en: Transmit Enable
+ * rx_en: Receive Enable
+ */
+ struct {
+ u32
+ tx_pr_len:4,
+ tx_ifg_nib:4,
+ nib_mode:1,
+ rx_pr_check_en:1,
+ tx_ifg:6,
+ rx_ifg:4,
+ tx_fc_retr:3,
+ rx_length_check_en:1,
+ rx_crc_ignore:1,
+ rx_crc_strip:1,
+ rx_fc_en:1,
+ tx_crc_en:1,
+ tx_pad_en:1,
+ tx_fc_en:1,
+ tx_en:1,
+ rx_en:1;
+ };
+
+ u32 value;
+ };
+};
+
+/* Gbps Eth MAC Configuration 1 register */
+struct nps_enet_ge_mac_cfg_1 {
+ union {
+ /* octet_3: MAC address octet 3
+ * octet_2: MAC address octet 2
+ * octet_1: MAC address octet 1
+ * octet_0: MAC address octet 0
+ */
+ struct {
+ u32
+ octet_3:8,
+ octet_2:8,
+ octet_1:8,
+ octet_0:8;
+ };
+
+ u32 value;
+ };
+};
+
+/* Gbps Eth MAC Configuration 2 register */
+struct nps_enet_ge_mac_cfg_2 {
+ union {
+ /* transmit_flush_en: MAC flush enable
+ * stat_en: RMON statistics interface enable
+ * disc_da: Discard frames with DA different
+ * from MAC address
+ * disc_bc: Discard broadcast frames
+ * disc_mc: Discard multicast frames
+ * octet_5: MAC address octet 5
+ * octet_4: MAC address octet 4
+ */
+ struct {
+ u32
+ transmit_flush_en:1,
+ __reserved_1:5,
+ stat_en:2,
+ __reserved_2:1,
+ disc_da:1,
+ disc_bc:1,
+ disc_mc:1,
+ __reserved_3:4,
+ octet_5:8,
+ octet_4:8;
+ };
+
+ u32 value;
+ };
+};
+
+/* Gbps Eth MAC Configuration 3 register */
+struct nps_enet_ge_mac_cfg_3 {
+ union {
+ /* ext_oob_cbfc_sel: Selects one of the 4 profiles for
+ * extended OOB in-flow-control indication
+ * max_len: Maximum receive frame length in bytes
+ * tx_cbfc_en: Enable transmission of class-based
+ * flow control packets
+ * rx_ifg_th: Threshold for IFG status reporting via OOB
+ * cf_timeout: Configurable time to decrement FC counters
+ * cf_drop: Drop control frames
+ * redirect_cbfc_sel: Selects one of CBFC redirect profiles
+ * rx_cbfc_redir_en: Enable Rx class-based flow
+ * control redirect
+ * rx_cbfc_en: Enable Rx class-based flow control
+ * tm_hd_mode: TM header mode
+ */
+ struct {
+ u32
+ ext_oob_cbfc_sel:2,
+ max_len:14,
+ tx_cbfc_en:1,
+ rx_ifg_th:5,
+ cf_timeout:4,
+ cf_drop:1,
+ redirect_cbfc_sel:2,
+ rx_cbfc_redir_en:1,
+ rx_cbfc_en:1,
+ tm_hd_mode:1;
+ };
+
+ u32 value;
+ };
+};
+
+/* GE MAC, PCS reset control register */
+struct nps_enet_ge_rst {
+ union {
+ /* gmac_0: GE MAC reset
+ * spcs_0: SGMII PCS reset
+ */
+ struct {
+ u32
+ __reserved_1:23,
+ gmac_0:1,
+ __reserved_2:7,
+ spcs_0:1;
+ };
+
+ u32 value;
+ };
+};
+
+/* Tx phase sync FIFO control register */
+struct nps_enet_phase_fifo_ctl {
+ union {
+ /* init: initialize serdes TX phase sync FIFO pointers
+ * rst: reset serdes TX phase sync FIFO
+ */
+ struct {
+ u32
+ __reserved:30,
+ init:1,
+ rst:1;
+ };
+
+ u32 value;
+ };
+};
+
+/**
+ * struct nps_enet_priv - Storage of ENET's private information.
+ * @regs_base: Base address of ENET memory-mapped control registers.
+ * @irq: For RX/TX IRQ number.
+ * @tx_packet_sent: SW indication if frame is being sent.
+ * @tx_skb: socket buffer of sent frame.
+ * @napi: Structure for NAPI.
+ */
+struct nps_enet_priv {
+ void __iomem *regs_base;
+ s32 irq;
+ bool tx_packet_sent;
+ struct sk_buff *tx_skb;
+ struct napi_struct napi;
+ struct nps_enet_ge_mac_cfg_2 ge_mac_cfg_2;
+ struct nps_enet_ge_mac_cfg_3 ge_mac_cfg_3;
+};
+
+/**
+ * nps_reg_set - Sets ENET register with provided value.
+ * @priv: Pointer to EZchip ENET private data structure.
+ * @reg: Register offset from base address.
+ * @value: Value to set in register.
+ */
+static inline void nps_enet_reg_set(struct nps_enet_priv *priv,
+ s32 reg, s32 value)
+{
+ iowrite32be(value, priv->regs_base + reg);
+}
+
+/**
+ * nps_reg_get - Gets value of specified ENET register.
+ * @priv: Pointer to EZchip ENET private data structure.
+ * @reg: Register offset from base address.
+ *
+ * returns: Value of requested register.
+ */
+static inline u32 nps_enet_reg_get(struct nps_enet_priv *priv, s32 reg)
+{
+ return ioread32be(priv->regs_base + reg);
+}
+
+#endif /* _NPS_ENET_H */
diff --git a/drivers/net/ethernet/faraday/Kconfig b/drivers/net/ethernet/faraday/Kconfig
index 5918c6891694..040c7f163325 100644
--- a/drivers/net/ethernet/faraday/Kconfig
+++ b/drivers/net/ethernet/faraday/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_FARADAY
default y
depends on ARM
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index 25e3425729d0..b8de87b03046 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -9,9 +9,7 @@ config NET_VENDOR_FREESCALE
M523x || M527x || M5272 || M528x || M520x || M532x || \
ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM)
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 66d47e448e4d..e464aeaeed2c 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -2118,6 +2118,82 @@ static void fec_enet_get_drvinfo(struct net_device *ndev,
strlcpy(info->bus_info, dev_name(&ndev->dev), sizeof(info->bus_info));
}
+static int fec_enet_get_regs_len(struct net_device *ndev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ struct resource *r;
+ int s = 0;
+
+ r = platform_get_resource(fep->pdev, IORESOURCE_MEM, 0);
+ if (r)
+ s = resource_size(r);
+
+ return s;
+}
+
+/* List of registers that can be safety be read to dump them with ethtool */
+#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+ defined(CONFIG_M520x) || defined(CONFIG_M532x) || \
+ defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28)
+static u32 fec_enet_register_offset[] = {
+ FEC_IEVENT, FEC_IMASK, FEC_R_DES_ACTIVE_0, FEC_X_DES_ACTIVE_0,
+ FEC_ECNTRL, FEC_MII_DATA, FEC_MII_SPEED, FEC_MIB_CTRLSTAT, FEC_R_CNTRL,
+ FEC_X_CNTRL, FEC_ADDR_LOW, FEC_ADDR_HIGH, FEC_OPD, FEC_TXIC0, FEC_TXIC1,
+ FEC_TXIC2, FEC_RXIC0, FEC_RXIC1, FEC_RXIC2, FEC_HASH_TABLE_HIGH,
+ FEC_HASH_TABLE_LOW, FEC_GRP_HASH_TABLE_HIGH, FEC_GRP_HASH_TABLE_LOW,
+ FEC_X_WMRK, FEC_R_BOUND, FEC_R_FSTART, FEC_R_DES_START_1,
+ FEC_X_DES_START_1, FEC_R_BUFF_SIZE_1, FEC_R_DES_START_2,
+ FEC_X_DES_START_2, FEC_R_BUFF_SIZE_2, FEC_R_DES_START_0,
+ FEC_X_DES_START_0, FEC_R_BUFF_SIZE_0, FEC_R_FIFO_RSFL, FEC_R_FIFO_RSEM,
+ FEC_R_FIFO_RAEM, FEC_R_FIFO_RAFL, FEC_RACC, FEC_RCMR_1, FEC_RCMR_2,
+ FEC_DMA_CFG_1, FEC_DMA_CFG_2, FEC_R_DES_ACTIVE_1, FEC_X_DES_ACTIVE_1,
+ FEC_R_DES_ACTIVE_2, FEC_X_DES_ACTIVE_2, FEC_QOS_SCHEME,
+ RMON_T_DROP, RMON_T_PACKETS, RMON_T_BC_PKT, RMON_T_MC_PKT,
+ RMON_T_CRC_ALIGN, RMON_T_UNDERSIZE, RMON_T_OVERSIZE, RMON_T_FRAG,
+ RMON_T_JAB, RMON_T_COL, RMON_T_P64, RMON_T_P65TO127, RMON_T_P128TO255,
+ RMON_T_P256TO511, RMON_T_P512TO1023, RMON_T_P1024TO2047,
+ RMON_T_P_GTE2048, RMON_T_OCTETS,
+ IEEE_T_DROP, IEEE_T_FRAME_OK, IEEE_T_1COL, IEEE_T_MCOL, IEEE_T_DEF,
+ IEEE_T_LCOL, IEEE_T_EXCOL, IEEE_T_MACERR, IEEE_T_CSERR, IEEE_T_SQE,
+ IEEE_T_FDXFC, IEEE_T_OCTETS_OK,
+ RMON_R_PACKETS, RMON_R_BC_PKT, RMON_R_MC_PKT, RMON_R_CRC_ALIGN,
+ RMON_R_UNDERSIZE, RMON_R_OVERSIZE, RMON_R_FRAG, RMON_R_JAB,
+ RMON_R_RESVD_O, RMON_R_P64, RMON_R_P65TO127, RMON_R_P128TO255,
+ RMON_R_P256TO511, RMON_R_P512TO1023, RMON_R_P1024TO2047,
+ RMON_R_P_GTE2048, RMON_R_OCTETS,
+ IEEE_R_DROP, IEEE_R_FRAME_OK, IEEE_R_CRC, IEEE_R_ALIGN, IEEE_R_MACERR,
+ IEEE_R_FDXFC, IEEE_R_OCTETS_OK
+};
+#else
+static u32 fec_enet_register_offset[] = {
+ FEC_ECNTRL, FEC_IEVENT, FEC_IMASK, FEC_IVEC, FEC_R_DES_ACTIVE_0,
+ FEC_R_DES_ACTIVE_1, FEC_R_DES_ACTIVE_2, FEC_X_DES_ACTIVE_0,
+ FEC_X_DES_ACTIVE_1, FEC_X_DES_ACTIVE_2, FEC_MII_DATA, FEC_MII_SPEED,
+ FEC_R_BOUND, FEC_R_FSTART, FEC_X_WMRK, FEC_X_FSTART, FEC_R_CNTRL,
+ FEC_MAX_FRM_LEN, FEC_X_CNTRL, FEC_ADDR_LOW, FEC_ADDR_HIGH,
+ FEC_GRP_HASH_TABLE_HIGH, FEC_GRP_HASH_TABLE_LOW, FEC_R_DES_START_0,
+ FEC_R_DES_START_1, FEC_R_DES_START_2, FEC_X_DES_START_0,
+ FEC_X_DES_START_1, FEC_X_DES_START_2, FEC_R_BUFF_SIZE_0,
+ FEC_R_BUFF_SIZE_1, FEC_R_BUFF_SIZE_2
+};
+#endif
+
+static void fec_enet_get_regs(struct net_device *ndev,
+ struct ethtool_regs *regs, void *regbuf)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ u32 __iomem *theregs = (u32 __iomem *)fep->hwp;
+ u32 *buf = (u32 *)regbuf;
+ u32 i, off;
+
+ memset(buf, 0, regs->len);
+
+ for (i = 0; i < ARRAY_SIZE(fec_enet_register_offset); i++) {
+ off = fec_enet_register_offset[i] / 4;
+ buf[off] = readl(&theregs[off]);
+ }
+}
+
static int fec_enet_get_ts_info(struct net_device *ndev,
struct ethtool_ts_info *info)
{
@@ -2515,6 +2591,8 @@ static const struct ethtool_ops fec_enet_ethtool_ops = {
.get_settings = fec_enet_get_settings,
.set_settings = fec_enet_set_settings,
.get_drvinfo = fec_enet_get_drvinfo,
+ .get_regs_len = fec_enet_get_regs_len,
+ .get_regs = fec_enet_get_regs,
.nway_reset = fec_enet_nway_reset,
.get_link = ethtool_op_get_link,
.get_coalesce = fec_enet_get_coalesce,
@@ -2778,12 +2856,14 @@ fec_enet_open(struct net_device *ndev)
if (ret)
goto err_enet_alloc;
+ /* Init MAC prior to mii bus probe */
+ fec_restart(ndev);
+
/* Probe and connect to PHY when open the interface */
ret = fec_enet_mii_probe(ndev);
if (ret)
goto err_enet_mii_probe;
- fec_restart(ndev);
napi_enable(&fep->napi);
phy_start(fep->phy_dev);
netif_tx_start_all_queues(ndev);
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index a583d89b13c4..a15663ad7f5e 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -353,6 +353,7 @@ static int fec_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
tmp = readl(fep->hwp + FEC_ATIME_INC) & FEC_T_INC_MASK;
tmp |= corr_ns << FEC_T_INC_CORR_OFFSET;
writel(tmp, fep->hwp + FEC_ATIME_INC);
+ corr_period = corr_period > 1 ? corr_period - 1 : corr_period;
writel(corr_period, fep->hwp + FEC_ATIME_CORR);
/* dummy read to update the timer. */
timecounter_read(&fep->tc);
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
index 9b3639eae676..56316db6c5a6 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
@@ -86,7 +86,7 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget)
struct net_device *dev = fep->ndev;
const struct fs_platform_info *fpi = fep->fpi;
cbd_t __iomem *bdp;
- struct sk_buff *skb, *skbn, *skbt;
+ struct sk_buff *skb, *skbn;
int received = 0;
u16 pkt_len, sc;
int curidx;
@@ -161,10 +161,7 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget)
skb_reserve(skbn, 2); /* align IP header */
skb_copy_from_linear_data(skb,
skbn->data, pkt_len);
- /* swap */
- skbt = skb;
- skb = skbn;
- skbn = skbt;
+ swap(skb, skbn);
}
} else {
skbn = netdev_alloc_skb(dev, ENET_RX_FRSIZE);
@@ -490,6 +487,9 @@ static struct sk_buff *tx_skb_align_workaround(struct net_device *dev,
{
struct sk_buff *new_skb;
+ if (skb_linearize(skb))
+ return NULL;
+
/* Alloc new skb */
new_skb = netdev_alloc_skb(dev, skb->len + 4);
if (!new_skb)
@@ -515,12 +515,27 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
cbd_t __iomem *bdp;
int curidx;
u16 sc;
- int nr_frags = skb_shinfo(skb)->nr_frags;
+ int nr_frags;
skb_frag_t *frag;
int len;
-
#ifdef CONFIG_FS_ENET_MPC5121_FEC
- if (((unsigned long)skb->data) & 0x3) {
+ int is_aligned = 1;
+ int i;
+
+ if (!IS_ALIGNED((unsigned long)skb->data, 4)) {
+ is_aligned = 0;
+ } else {
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ frag = skb_shinfo(skb)->frags;
+ for (i = 0; i < nr_frags; i++, frag++) {
+ if (!IS_ALIGNED(frag->page_offset, 4)) {
+ is_aligned = 0;
+ break;
+ }
+ }
+ }
+
+ if (!is_aligned) {
skb = tx_skb_align_workaround(dev, skb);
if (!skb) {
/*
@@ -532,6 +547,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
#endif
+
spin_lock(&fep->tx_lock);
/*
@@ -539,6 +555,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
bdp = fep->cur_tx;
+ nr_frags = skb_shinfo(skb)->nr_frags;
if (fep->tx_free <= nr_frags || (CBDR_SC(bdp) & BD_ENET_TX_READY)) {
netif_stop_queue(dev);
spin_unlock(&fep->tx_lock);
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 4ee080d49bc0..ff875028fdff 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -516,6 +516,15 @@ static struct net_device_stats *gfar_get_stats(struct net_device *dev)
return &dev->stats;
}
+static int gfar_set_mac_addr(struct net_device *dev, void *p)
+{
+ eth_mac_addr(dev, p);
+
+ gfar_set_mac_for_addr(dev, 0, dev->dev_addr);
+
+ return 0;
+}
+
static const struct net_device_ops gfar_netdev_ops = {
.ndo_open = gfar_enet_open,
.ndo_start_xmit = gfar_start_xmit,
@@ -526,7 +535,7 @@ static const struct net_device_ops gfar_netdev_ops = {
.ndo_tx_timeout = gfar_timeout,
.ndo_do_ioctl = gfar_ioctl,
.ndo_get_stats = gfar_get_stats,
- .ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_mac_address = gfar_set_mac_addr,
.ndo_validate_addr = eth_validate_addr,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = gfar_netpoll,
@@ -1411,6 +1420,8 @@ static int gfar_probe(struct platform_device *ofdev)
dev->features |= NETIF_F_HW_VLAN_CTAG_RX;
}
+ dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+
gfar_init_addr_hash_table(priv);
/* Insert receive time stamps into padding alignment bytes */
@@ -2254,7 +2265,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
int i, rq = 0;
int do_tstamp, do_csum, do_vlan;
u32 bufaddr;
- unsigned long flags;
unsigned int nr_frags, nr_txbds, bytes_sent, fcb_len = 0;
rq = skb->queue_mapping;
@@ -2434,19 +2444,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
netdev_tx_sent_queue(txq, bytes_sent);
- /* We can work in parallel with gfar_clean_tx_ring(), except
- * when modifying num_txbdfree. Note that we didn't grab the lock
- * when we were reading the num_txbdfree and checking for available
- * space, that's because outside of this function it can only grow,
- * and once we've got needed space, it cannot suddenly disappear.
- *
- * The lock also protects us from gfar_error(), which can modify
- * regs->tstat and thus retrigger the transfers, which is why we
- * also must grab the lock before setting ready bit for the first
- * to be transmitted BD.
- */
- spin_lock_irqsave(&tx_queue->txlock, flags);
-
gfar_wmb();
txbdp_start->lstatus = cpu_to_be32(lstatus);
@@ -2463,8 +2460,15 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
tx_queue->cur_tx = next_txbd(txbdp, base, tx_queue->tx_ring_size);
+ /* We can work in parallel with gfar_clean_tx_ring(), except
+ * when modifying num_txbdfree. Note that we didn't grab the lock
+ * when we were reading the num_txbdfree and checking for available
+ * space, that's because outside of this function it can only grow.
+ */
+ spin_lock_bh(&tx_queue->txlock);
/* reduce TxBD free count */
tx_queue->num_txbdfree -= (nr_txbds);
+ spin_unlock_bh(&tx_queue->txlock);
/* If the next BD still needs to be cleaned up, then the bds
* are full. We need to tell the kernel to stop sending us stuff.
@@ -2478,9 +2482,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Tell the DMA to go go go */
gfar_write(&regs->tstat, TSTAT_CLEAR_THALT >> tx_queue->qindex);
- /* Unlock priv */
- spin_unlock_irqrestore(&tx_queue->txlock, flags);
-
return NETDEV_TX_OK;
dma_map_err:
@@ -2622,7 +2623,6 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
skb_dirtytx = tx_queue->skb_dirtytx;
while ((skb = tx_queue->tx_skbuff[skb_dirtytx])) {
- unsigned long flags;
frags = skb_shinfo(skb)->nr_frags;
@@ -2686,9 +2686,9 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
TX_RING_MOD_MASK(tx_ring_size);
howmany++;
- spin_lock_irqsave(&tx_queue->txlock, flags);
+ spin_lock(&tx_queue->txlock);
tx_queue->num_txbdfree += nr_txbds;
- spin_unlock_irqrestore(&tx_queue->txlock, flags);
+ spin_unlock(&tx_queue->txlock);
}
/* If we freed a buffer, we can restart transmission, if necessary */
@@ -3411,21 +3411,12 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
if (events & IEVENT_CRL)
dev->stats.tx_aborted_errors++;
if (events & IEVENT_XFUN) {
- unsigned long flags;
-
netif_dbg(priv, tx_err, dev,
"TX FIFO underrun, packet dropped\n");
dev->stats.tx_dropped++;
atomic64_inc(&priv->extra_stats.tx_underrun);
- local_irq_save(flags);
- lock_tx_qs(priv);
-
- /* Reactivate the Tx Queues */
- gfar_write(&regs->tstat, gfargrp->tstat);
-
- unlock_tx_qs(priv);
- local_irq_restore(flags);
+ schedule_work(&priv->reset_task);
}
netif_dbg(priv, tx_err, dev, "Transmit Error\n");
}
diff --git a/drivers/net/ethernet/fujitsu/Kconfig b/drivers/net/ethernet/fujitsu/Kconfig
index 1085257385d2..faee34e44a35 100644
--- a/drivers/net/ethernet/fujitsu/Kconfig
+++ b/drivers/net/ethernet/fujitsu/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_FUJITSU
default y
depends on PCMCIA
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
the questions about Fujitsu cards. If you say Y, you will be asked for
diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig
index a54d89791311..dead17b5d769 100644
--- a/drivers/net/ethernet/hisilicon/Kconfig
+++ b/drivers/net/ethernet/hisilicon/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_HISILICON
default y
depends on ARM
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c
index 3b39fdddeb57..d49bee38cd31 100644
--- a/drivers/net/ethernet/hisilicon/hip04_eth.c
+++ b/drivers/net/ethernet/hisilicon/hip04_eth.c
@@ -798,7 +798,7 @@ static void hip04_free_ring(struct net_device *ndev, struct device *d)
for (i = 0; i < RX_DESC_NUM; i++)
if (priv->rx_buf[i])
- put_page(virt_to_head_page(priv->rx_buf[i]));
+ skb_free_frag(priv->rx_buf[i]);
for (i = 0; i < TX_DESC_NUM; i++)
if (priv->tx_skb[i])
diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
index 0ffdcd381fdd..a5e077eac99a 100644
--- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
@@ -500,7 +500,6 @@ static int hix5hd2_rx(struct net_device *dev, int limit)
napi_gro_receive(&priv->napi, skb);
dev->stats.rx_packets++;
dev->stats.rx_bytes += skb->len;
- dev->last_rx = jiffies;
next:
pos = dma_ring_incr(pos, RX_DESC_NUM);
}
diff --git a/drivers/net/ethernet/hp/Kconfig b/drivers/net/ethernet/hp/Kconfig
index a0b8ece1e3bc..d4df78c2abce 100644
--- a/drivers/net/ethernet/hp/Kconfig
+++ b/drivers/net/ethernet/hp/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_HP
default y
depends on ISA || EISA || PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
@@ -22,9 +20,7 @@ config HP100
tristate "HP 10/100VG PCLAN (ISA, EISA, PCI) support"
depends on (ISA || EISA || PCI)
---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card of this type, say Y here.
To compile this driver as a module, choose M here. The module
will be called hp100.
diff --git a/drivers/net/ethernet/i825xx/Kconfig b/drivers/net/ethernet/i825xx/Kconfig
index 9521e68aa3b3..e8d61f670479 100644
--- a/drivers/net/ethernet/i825xx/Kconfig
+++ b/drivers/net/ethernet/i825xx/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_I825XX
default y
depends on NET_VENDOR_INTEL
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question does not directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/ibm/Kconfig b/drivers/net/ethernet/ibm/Kconfig
index 563a1ac71dbc..99c1cebd002d 100644
--- a/drivers/net/ethernet/ibm/Kconfig
+++ b/drivers/net/ethernet/ibm/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_IBM
default y
depends on PPC_PSERIES || PPC_DCR || (IBMEBUS && SPARSEMEM)
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index b9df0cbd0a38..b60a34d982a9 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -2999,7 +2999,7 @@ static struct platform_driver emac_driver = {
static void __init emac_make_bootlist(void)
{
struct device_node *np = NULL;
- int j, max, i = 0, k;
+ int j, max, i = 0;
int cell_indices[EMAC_BOOT_LIST_SIZE];
/* Collect EMACs */
@@ -3026,12 +3026,8 @@ static void __init emac_make_bootlist(void)
for (i = 0; max > 1 && (i < (max - 1)); i++)
for (j = i; j < max; j++) {
if (cell_indices[i] > cell_indices[j]) {
- np = emac_boot_list[i];
- emac_boot_list[i] = emac_boot_list[j];
- emac_boot_list[j] = np;
- k = cell_indices[i];
- cell_indices[i] = cell_indices[j];
- cell_indices[j] = k;
+ swap(emac_boot_list[i], emac_boot_list[j]);
+ swap(cell_indices[i], cell_indices[j]);
}
}
}
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 18134766a114..29bbb628d712 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -58,7 +58,7 @@ static struct kobj_type ktype_veth_pool;
static const char ibmveth_driver_name[] = "ibmveth";
static const char ibmveth_driver_string[] = "IBM Power Virtual Ethernet Driver";
-#define ibmveth_driver_version "1.04"
+#define ibmveth_driver_version "1.05"
MODULE_AUTHOR("Santiago Leon <santil@linux.vnet.ibm.com>");
MODULE_DESCRIPTION("IBM Power Virtual Ethernet Driver");
@@ -100,6 +100,8 @@ struct ibmveth_stat ibmveth_stats[] = {
{ "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) },
{ "fw_enabled_ipv4_csum", IBMVETH_STAT_OFF(fw_ipv4_csum_support) },
{ "fw_enabled_ipv6_csum", IBMVETH_STAT_OFF(fw_ipv6_csum_support) },
+ { "tx_large_packets", IBMVETH_STAT_OFF(tx_large_packets) },
+ { "rx_large_packets", IBMVETH_STAT_OFF(rx_large_packets) }
};
/* simple methods of getting data from the current rxq entry */
@@ -852,6 +854,10 @@ static int ibmveth_set_features(struct net_device *dev,
struct ibmveth_adapter *adapter = netdev_priv(dev);
int rx_csum = !!(features & NETIF_F_RXCSUM);
int rc;
+ netdev_features_t changed = features ^ dev->features;
+
+ if (features & NETIF_F_TSO & changed)
+ netdev_info(dev, "TSO feature requires all partitions to have updated driver");
if (rx_csum == adapter->rx_csum)
return 0;
@@ -1035,6 +1041,15 @@ retry_bounce:
descs[i+1].fields.address = dma_addr;
}
+ if (skb_is_gso(skb) && !skb_is_gso_v6(skb)) {
+ /* Put -1 in the IP checksum to tell phyp it
+ * is a largesend packet and put the mss in the TCP checksum.
+ */
+ ip_hdr(skb)->check = 0xffff;
+ tcp_hdr(skb)->check = cpu_to_be16(skb_shinfo(skb)->gso_size);
+ adapter->tx_large_packets++;
+ }
+
if (ibmveth_send(adapter, descs)) {
adapter->tx_send_failed++;
netdev->stats.tx_dropped++;
@@ -1080,6 +1095,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
struct net_device *netdev = adapter->netdev;
int frames_processed = 0;
unsigned long lpar_rc;
+ struct iphdr *iph;
restart_poll:
while (frames_processed < budget) {
@@ -1122,10 +1138,23 @@ restart_poll:
skb_put(skb, length);
skb->protocol = eth_type_trans(skb, netdev);
- if (csum_good)
+ if (csum_good) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
+ if (be16_to_cpu(skb->protocol) == ETH_P_IP) {
+ iph = (struct iphdr *)skb->data;
+
+ /* If the IP checksum is not offloaded and if the packet
+ * is large send, the checksum must be rebuilt.
+ */
+ if (iph->check == 0xffff) {
+ iph->check = 0;
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+ adapter->rx_large_packets++;
+ }
+ }
+ }
- netif_receive_skb(skb); /* send it up */
+ napi_gro_receive(napi, skb); /* send it up */
netdev->stats.rx_packets++;
netdev->stats.rx_bytes += length;
@@ -1422,8 +1451,14 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
netdev->features |= netdev->hw_features;
+ /* TSO is disabled by default */
+ netdev->hw_features |= NETIF_F_TSO;
+
memcpy(netdev->dev_addr, mac_addr_p, ETH_ALEN);
+ if (firmware_has_feature(FW_FEATURE_CMO))
+ memcpy(pool_count, pool_count_cmo, sizeof(pool_count));
+
for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
struct kobject *kobj = &adapter->rx_buff_pool[i].kobj;
int error;
diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h
index 1f37499d4398..41dedb1fb2ae 100644
--- a/drivers/net/ethernet/ibm/ibmveth.h
+++ b/drivers/net/ethernet/ibm/ibmveth.h
@@ -104,7 +104,8 @@ static inline long h_illan_attributes(unsigned long unit_address,
static int pool_size[] = { 512, 1024 * 2, 1024 * 16, 1024 * 32, 1024 * 64 };
static int pool_count[] = { 256, 512, 256, 256, 256 };
-static int pool_active[] = { 1, 1, 0, 0, 0};
+static int pool_count_cmo[] = { 256, 512, 256, 256, 64 };
+static int pool_active[] = { 1, 1, 0, 0, 1};
#define IBM_VETH_INVALID_MAP ((u16)0xffff)
@@ -160,6 +161,8 @@ struct ibmveth_adapter {
u64 rx_no_buffer;
u64 tx_map_failed;
u64 tx_send_failed;
+ u64 tx_large_packets;
+ u64 rx_large_packets;
};
/*
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index f4ff465584a0..4163b16489b3 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -6,9 +6,7 @@ config NET_VENDOR_INTEL
bool "Intel devices"
default y
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c
index 1a450f4b6b12..d2657a412768 100644
--- a/drivers/net/ethernet/intel/e100.c
+++ b/drivers/net/ethernet/intel/e100.c
@@ -874,7 +874,7 @@ static int e100_exec_cb(struct nic *nic, struct sk_buff *skb,
{
struct cb *cb;
unsigned long flags;
- int err = 0;
+ int err;
spin_lock_irqsave(&nic->cb_lock, flags);
@@ -2922,9 +2922,7 @@ static int e100_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
- init_timer(&nic->watchdog);
- nic->watchdog.function = e100_watchdog;
- nic->watchdog.data = (unsigned long)nic;
+ setup_timer(&nic->watchdog, e100_watchdog, (unsigned long)nic);
INIT_WORK(&nic->tx_timeout_task, e100_tx_timeout_task);
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 983eb4e6f7aa..74dc15055971 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -2079,11 +2079,6 @@ static void *e1000_alloc_frag(const struct e1000_adapter *a)
return data;
}
-static void e1000_free_frag(const void *data)
-{
- put_page(virt_to_head_page(data));
-}
-
/**
* e1000_clean_rx_ring - Free Rx Buffers per Queue
* @adapter: board private structure
@@ -2107,7 +2102,7 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
adapter->rx_buffer_len,
DMA_FROM_DEVICE);
if (buffer_info->rxbuf.data) {
- e1000_free_frag(buffer_info->rxbuf.data);
+ skb_free_frag(buffer_info->rxbuf.data);
buffer_info->rxbuf.data = NULL;
}
} else if (adapter->clean_rx == e1000_clean_jumbo_rx_irq) {
@@ -4594,28 +4589,28 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
data = e1000_alloc_frag(adapter);
/* Failed allocation, critical failure */
if (!data) {
- e1000_free_frag(olddata);
+ skb_free_frag(olddata);
adapter->alloc_rx_buff_failed++;
break;
}
if (!e1000_check_64k_bound(adapter, data, bufsz)) {
/* give up */
- e1000_free_frag(data);
- e1000_free_frag(olddata);
+ skb_free_frag(data);
+ skb_free_frag(olddata);
adapter->alloc_rx_buff_failed++;
break;
}
/* Use new allocation */
- e1000_free_frag(olddata);
+ skb_free_frag(olddata);
}
buffer_info->dma = dma_map_single(&pdev->dev,
data,
adapter->rx_buffer_len,
DMA_FROM_DEVICE);
if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
- e1000_free_frag(data);
+ skb_free_frag(data);
buffer_info->dma = 0;
adapter->alloc_rx_buff_failed++;
break;
@@ -4637,7 +4632,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
adapter->rx_buffer_len,
DMA_FROM_DEVICE);
- e1000_free_frag(data);
+ skb_free_frag(data);
buffer_info->rxbuf.data = NULL;
buffer_info->dma = 0;
diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.c b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
index 08f22f348800..2af603f3e418 100644
--- a/drivers/net/ethernet/intel/e1000e/80003es2lan.c
+++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.h b/drivers/net/ethernet/intel/e1000e/80003es2lan.h
index 535a9430976d..a2162e11673e 100644
--- a/drivers/net/ethernet/intel/e1000e/80003es2lan.h
+++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.h
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c
index dc79ed85030b..5f7016442ec4 100644
--- a/drivers/net/ethernet/intel/e1000e/82571.c
+++ b/drivers/net/ethernet/intel/e1000e/82571.c
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -2010,7 +2010,7 @@ const struct e1000_info e1000_82573_info = {
.flags2 = FLAG2_DISABLE_ASPM_L1
| FLAG2_DISABLE_ASPM_L0S,
.pba = 20,
- .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN,
+ .max_hw_frame_size = VLAN_ETH_FRAME_LEN + ETH_FCS_LEN,
.get_variants = e1000_get_variants_82571,
.mac_ops = &e82571_mac_ops,
.phy_ops = &e82_phy_ops_m88,
diff --git a/drivers/net/ethernet/intel/e1000e/82571.h b/drivers/net/ethernet/intel/e1000e/82571.h
index 2e758f796d60..abc6a9abff98 100644
--- a/drivers/net/ethernet/intel/e1000e/82571.h
+++ b/drivers/net/ethernet/intel/e1000e/82571.h
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h
index 0570c668ec3d..133d4074dbe4 100644
--- a/drivers/net/ethernet/intel/e1000e/defines.h
+++ b/drivers/net/ethernet/intel/e1000e/defines.h
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index 0abc942c966e..0b748d1959d9 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -98,6 +98,8 @@ struct e1000_info;
#define DEFAULT_RADV 8
#define BURST_RDTR 0x20
#define BURST_RADV 0x20
+#define PCICFG_DESC_RING_STATUS 0xe4
+#define FLUSH_DESC_REQUIRED 0x100
/* in the case of WTHRESH, it appears at least the 82571/2 hardware
* writes back 4 descriptors when WTHRESH=5, and 3 descriptors when
@@ -384,6 +386,10 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca);
#define INCVALUE_SHIFT_25MHz 18
#define INCPERIOD_25MHz 1
+#define INCVALUE_24MHz 125
+#define INCVALUE_SHIFT_24MHz 14
+#define INCPERIOD_24MHz 3
+
/* Another drawback of scaling the incvalue by a large factor is the
* 64-bit SYSTIM register overflows more quickly. This is dealt with
* by simply reading the clock before it overflows.
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index 11f486e4ff7b..ad6daa656d3e 100644
--- a/drivers/net/ethernet/intel/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -1516,8 +1516,19 @@ static int e1000_set_es2lan_mac_loopback(struct e1000_adapter *adapter)
static int e1000_setup_loopback_test(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
- u32 rctl;
-
+ u32 rctl, fext_nvm11, tarc0;
+
+ if (hw->mac.type == e1000_pch_spt) {
+ fext_nvm11 = er32(FEXTNVM11);
+ fext_nvm11 |= E1000_FEXTNVM11_DISABLE_MULR_FIX;
+ ew32(FEXTNVM11, fext_nvm11);
+ tarc0 = er32(TARC(0));
+ /* clear bits 28 & 29 (control of MULR concurrent requests) */
+ tarc0 &= 0xcfffffff;
+ /* set bit 29 (value of MULR requests is now 2) */
+ tarc0 |= 0x20000000;
+ ew32(TARC(0), tarc0);
+ }
if (hw->phy.media_type == e1000_media_type_fiber ||
hw->phy.media_type == e1000_media_type_internal_serdes) {
switch (hw->mac.type) {
@@ -1542,7 +1553,7 @@ static int e1000_setup_loopback_test(struct e1000_adapter *adapter)
static void e1000_loopback_cleanup(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
- u32 rctl;
+ u32 rctl, fext_nvm11, tarc0;
u16 phy_reg;
rctl = er32(RCTL);
@@ -1550,6 +1561,16 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter)
ew32(RCTL, rctl);
switch (hw->mac.type) {
+ case e1000_pch_spt:
+ fext_nvm11 = er32(FEXTNVM11);
+ fext_nvm11 &= ~E1000_FEXTNVM11_DISABLE_MULR_FIX;
+ ew32(FEXTNVM11, fext_nvm11);
+ tarc0 = er32(TARC(0));
+ /* clear bits 28 & 29 (control of MULR concurrent requests) */
+ /* set bit 29 (value of MULR requests is now 0) */
+ tarc0 &= 0xcfffffff;
+ ew32(TARC(0), tarc0);
+ /* fall through */
case e1000_80003es2lan:
if (hw->phy.media_type == e1000_media_type_fiber ||
hw->phy.media_type == e1000_media_type_internal_serdes) {
diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h
index 19e8c487db06..c9da4654e9ca 100644
--- a/drivers/net/ethernet/intel/e1000e/hw.h
+++ b/drivers/net/ethernet/intel/e1000e/hw.h
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 9d81c0317433..b074b9a667b3 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -1014,8 +1014,7 @@ static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link)
u16 speed, duplex, scale = 0;
u16 max_snoop, max_nosnoop;
u16 max_ltr_enc; /* max LTR latency encoded */
- s64 lat_ns; /* latency (ns) */
- s64 value;
+ u64 value;
u32 rxa;
if (!hw->adapter->max_frame_size) {
@@ -1040,14 +1039,11 @@ static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link)
* 2^25*(2^10-1) ns. The scale is encoded as 0=2^0ns,
* 1=2^5ns, 2=2^10ns,...5=2^25ns.
*/
- lat_ns = ((s64)rxa * 1024 -
- (2 * (s64)hw->adapter->max_frame_size)) * 8 * 1000;
- if (lat_ns < 0)
- lat_ns = 0;
- else
- do_div(lat_ns, speed);
+ rxa *= 512;
+ value = (rxa > hw->adapter->max_frame_size) ?
+ (rxa - hw->adapter->max_frame_size) * (16000 / speed) :
+ 0;
- value = lat_ns;
while (value > PCI_LTR_VALUE_MASK) {
scale++;
value = DIV_ROUND_UP(value, (1 << 5));
@@ -1563,7 +1559,7 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
((adapter->hw.mac.type >= e1000_pch2lan) &&
(!(er32(CTRL_EXT) & E1000_CTRL_EXT_LSECCK)))) {
adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES;
- adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN;
+ adapter->max_hw_frame_size = VLAN_ETH_FRAME_LEN + ETH_FCS_LEN;
hw->mac.ops.blink_led = NULL;
}
@@ -5681,7 +5677,7 @@ const struct e1000_info e1000_ich8_info = {
| FLAG_HAS_FLASH
| FLAG_APME_IN_WUC,
.pba = 8,
- .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN,
+ .max_hw_frame_size = VLAN_ETH_FRAME_LEN + ETH_FCS_LEN,
.get_variants = e1000_get_variants_ich8lan,
.mac_ops = &ich8_mac_ops,
.phy_ops = &ich8_phy_ops,
@@ -5754,7 +5750,7 @@ const struct e1000_info e1000_pch2_info = {
.flags2 = FLAG2_HAS_PHY_STATS
| FLAG2_HAS_EEE,
.pba = 26,
- .max_hw_frame_size = 9018,
+ .max_hw_frame_size = 9022,
.get_variants = e1000_get_variants_ich8lan,
.mac_ops = &ich8_mac_ops,
.phy_ops = &ich8_phy_ops,
@@ -5774,7 +5770,7 @@ const struct e1000_info e1000_pch_lpt_info = {
.flags2 = FLAG2_HAS_PHY_STATS
| FLAG2_HAS_EEE,
.pba = 26,
- .max_hw_frame_size = 9018,
+ .max_hw_frame_size = 9022,
.get_variants = e1000_get_variants_ich8lan,
.mac_ops = &ich8_mac_ops,
.phy_ops = &ich8_phy_ops,
@@ -5794,7 +5790,7 @@ const struct e1000_info e1000_pch_spt_info = {
.flags2 = FLAG2_HAS_PHY_STATS
| FLAG2_HAS_EEE,
.pba = 26,
- .max_hw_frame_size = 9018,
+ .max_hw_frame_size = 9022,
.get_variants = e1000_get_variants_ich8lan,
.mac_ops = &ich8_mac_ops,
.phy_ops = &ich8_phy_ops,
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h
index 770a573b9eea..26459853c6be 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.h
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -98,8 +98,15 @@
#define E1000_FEXTNVM6_K1_OFF_ENABLE 0x80000000
/* bit for disabling packet buffer read */
#define E1000_FEXTNVM7_DISABLE_PB_READ 0x00040000
-
+#define E1000_FEXTNVM7_SIDE_CLK_UNGATE 0x00000004
#define E1000_FEXTNVM7_DISABLE_SMB_PERST 0x00000020
+#define E1000_FEXTNVM9_IOSFSB_CLKGATE_DIS 0x00000800
+#define E1000_FEXTNVM9_IOSFSB_CLKREQ_DIS 0x00001000
+#define E1000_FEXTNVM11_DISABLE_PB_READ 0x00000200
+#define E1000_FEXTNVM11_DISABLE_MULR_FIX 0x00002000
+
+/* bit24: RXDCTL thresholds granularity: 0 - cache lines, 1 - descriptors */
+#define E1000_RXDCTL_THRESH_UNIT_DESC 0x01000000
#define K1_ENTRY_LATENCY 0
#define K1_MIN_TIME 1
diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c
index 30b74d590bee..e59d7c283cd4 100644
--- a/drivers/net/ethernet/intel/e1000e/mac.c
+++ b/drivers/net/ethernet/intel/e1000e/mac.c
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/e1000e/mac.h b/drivers/net/ethernet/intel/e1000e/mac.h
index 0513d90cdeea..8284618af9ff 100644
--- a/drivers/net/ethernet/intel/e1000e/mac.h
+++ b/drivers/net/ethernet/intel/e1000e/mac.h
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/e1000e/manage.c b/drivers/net/ethernet/intel/e1000e/manage.c
index 06edfca1a35e..cc9b3befc2bc 100644
--- a/drivers/net/ethernet/intel/e1000e/manage.c
+++ b/drivers/net/ethernet/intel/e1000e/manage.c
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/e1000e/manage.h b/drivers/net/ethernet/intel/e1000e/manage.h
index a8c27f98f7b0..0b9ea5952b07 100644
--- a/drivers/net/ethernet/intel/e1000e/manage.h
+++ b/drivers/net/ethernet/intel/e1000e/manage.h
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index c509a5c900f5..e62b9dcb91fe 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -48,7 +48,7 @@
#define DRV_EXTRAVERSION "-k"
-#define DRV_VERSION "2.3.2" DRV_EXTRAVERSION
+#define DRV_VERSION "3.2.5" DRV_EXTRAVERSION
char e1000e_driver_name[] = "e1000e";
const char e1000e_driver_version[] = DRV_VERSION;
@@ -3525,22 +3525,30 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
switch (hw->mac.type) {
case e1000_pch2lan:
case e1000_pch_lpt:
- case e1000_pch_spt:
- /* On I217, I218 and I219, the clock frequency is 25MHz
- * or 96MHz as indicated by the System Clock Frequency
- * Indication
- */
- if (((hw->mac.type != e1000_pch_lpt) &&
- (hw->mac.type != e1000_pch_spt)) ||
- (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) {
+ if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) {
/* Stable 96MHz frequency */
incperiod = INCPERIOD_96MHz;
incvalue = INCVALUE_96MHz;
shift = INCVALUE_SHIFT_96MHz;
adapter->cc.shift = shift + INCPERIOD_SHIFT_96MHz;
+ } else {
+ /* Stable 25MHz frequency */
+ incperiod = INCPERIOD_25MHz;
+ incvalue = INCVALUE_25MHz;
+ shift = INCVALUE_SHIFT_25MHz;
+ adapter->cc.shift = shift;
+ }
+ break;
+ case e1000_pch_spt:
+ if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) {
+ /* Stable 24MHz frequency */
+ incperiod = INCPERIOD_24MHz;
+ incvalue = INCVALUE_24MHz;
+ shift = INCVALUE_SHIFT_24MHz;
+ adapter->cc.shift = shift;
break;
}
- /* fall-through */
+ return -EINVAL;
case e1000_82574:
case e1000_82583:
/* Stable 25MHz frequency */
@@ -3788,6 +3796,108 @@ static void e1000_power_down_phy(struct e1000_adapter *adapter)
}
/**
+ * e1000_flush_tx_ring - remove all descriptors from the tx_ring
+ *
+ * We want to clear all pending descriptors from the TX ring.
+ * zeroing happens when the HW reads the regs. We assign the ring itself as
+ * the data of the next descriptor. We don't care about the data we are about
+ * to reset the HW.
+ */
+static void e1000_flush_tx_ring(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_tx_desc *tx_desc = NULL;
+ u32 tdt, tctl, txd_lower = E1000_TXD_CMD_IFCS;
+ u16 size = 512;
+
+ tctl = er32(TCTL);
+ ew32(TCTL, tctl | E1000_TCTL_EN);
+ tdt = er32(TDT(0));
+ BUG_ON(tdt != tx_ring->next_to_use);
+ tx_desc = E1000_TX_DESC(*tx_ring, tx_ring->next_to_use);
+ tx_desc->buffer_addr = tx_ring->dma;
+
+ tx_desc->lower.data = cpu_to_le32(txd_lower | size);
+ tx_desc->upper.data = 0;
+ /* flush descriptors to memory before notifying the HW */
+ wmb();
+ tx_ring->next_to_use++;
+ if (tx_ring->next_to_use == tx_ring->count)
+ tx_ring->next_to_use = 0;
+ ew32(TDT(0), tx_ring->next_to_use);
+ mmiowb();
+ usleep_range(200, 250);
+}
+
+/**
+ * e1000_flush_rx_ring - remove all descriptors from the rx_ring
+ *
+ * Mark all descriptors in the RX ring as consumed and disable the rx ring
+ */
+static void e1000_flush_rx_ring(struct e1000_adapter *adapter)
+{
+ u32 rctl, rxdctl;
+ struct e1000_hw *hw = &adapter->hw;
+
+ rctl = er32(RCTL);
+ ew32(RCTL, rctl & ~E1000_RCTL_EN);
+ e1e_flush();
+ usleep_range(100, 150);
+
+ rxdctl = er32(RXDCTL(0));
+ /* zero the lower 14 bits (prefetch and host thresholds) */
+ rxdctl &= 0xffffc000;
+
+ /* update thresholds: prefetch threshold to 31, host threshold to 1
+ * and make sure the granularity is "descriptors" and not "cache lines"
+ */
+ rxdctl |= (0x1F | (1 << 8) | E1000_RXDCTL_THRESH_UNIT_DESC);
+
+ ew32(RXDCTL(0), rxdctl);
+ /* momentarily enable the RX ring for the changes to take effect */
+ ew32(RCTL, rctl | E1000_RCTL_EN);
+ e1e_flush();
+ usleep_range(100, 150);
+ ew32(RCTL, rctl & ~E1000_RCTL_EN);
+}
+
+/**
+ * e1000_flush_desc_rings - remove all descriptors from the descriptor rings
+ *
+ * In i219, the descriptor rings must be emptied before resetting the HW
+ * or before changing the device state to D3 during runtime (runtime PM).
+ *
+ * Failure to do this will cause the HW to enter a unit hang state which can
+ * only be released by PCI reset on the device
+ *
+ */
+
+static void e1000_flush_desc_rings(struct e1000_adapter *adapter)
+{
+ u16 hang_state;
+ u32 fext_nvm11, tdlen;
+ struct e1000_hw *hw = &adapter->hw;
+
+ /* First, disable MULR fix in FEXTNVM11 */
+ fext_nvm11 = er32(FEXTNVM11);
+ fext_nvm11 |= E1000_FEXTNVM11_DISABLE_MULR_FIX;
+ ew32(FEXTNVM11, fext_nvm11);
+ /* do nothing if we're not in faulty state, or if the queue is empty */
+ tdlen = er32(TDLEN(0));
+ pci_read_config_word(adapter->pdev, PCICFG_DESC_RING_STATUS,
+ &hang_state);
+ if (!(hang_state & FLUSH_DESC_REQUIRED) || !tdlen)
+ return;
+ e1000_flush_tx_ring(adapter);
+ /* recheck, maybe the fault is caused by the rx ring */
+ pci_read_config_word(adapter->pdev, PCICFG_DESC_RING_STATUS,
+ &hang_state);
+ if (hang_state & FLUSH_DESC_REQUIRED)
+ e1000_flush_rx_ring(adapter);
+}
+
+/**
* e1000e_reset - bring the hardware into a known good state
*
* This function boots the hardware and enables some settings that
@@ -3807,7 +3917,7 @@ void e1000e_reset(struct e1000_adapter *adapter)
/* reset Packet Buffer Allocation to default */
ew32(PBA, pba);
- if (adapter->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) {
+ if (adapter->max_frame_size > (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)) {
/* To maintain wire speed transmits, the Tx FIFO should be
* large enough to accommodate two full transmit packets,
* rounded up to the next 1KB and expressed in KB. Likewise,
@@ -3943,6 +4053,8 @@ void e1000e_reset(struct e1000_adapter *adapter)
}
}
+ if (hw->mac.type == e1000_pch_spt)
+ e1000_flush_desc_rings(adapter);
/* Allow time for pending master requests to run */
mac->ops.reset_hw(hw);
@@ -4016,6 +4128,20 @@ void e1000e_reset(struct e1000_adapter *adapter)
phy_data &= ~IGP02E1000_PM_SPD;
e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
}
+ if (hw->mac.type == e1000_pch_spt && adapter->int_mode == 0) {
+ u32 reg;
+
+ /* Fextnvm7 @ 0xe4[2] = 1 */
+ reg = er32(FEXTNVM7);
+ reg |= E1000_FEXTNVM7_SIDE_CLK_UNGATE;
+ ew32(FEXTNVM7, reg);
+ /* Fextnvm9 @ 0x5bb4[13:12] = 11 */
+ reg = er32(FEXTNVM9);
+ reg |= E1000_FEXTNVM9_IOSFSB_CLKGATE_DIS |
+ E1000_FEXTNVM9_IOSFSB_CLKREQ_DIS;
+ ew32(FEXTNVM9, reg);
+ }
+
}
int e1000e_up(struct e1000_adapter *adapter)
@@ -4115,8 +4241,6 @@ void e1000e_down(struct e1000_adapter *adapter, bool reset)
spin_unlock(&adapter->stats64_lock);
e1000e_flush_descriptors(adapter);
- e1000_clean_tx_ring(adapter->tx_ring);
- e1000_clean_rx_ring(adapter->rx_ring);
adapter->link_speed = 0;
adapter->link_duplex = 0;
@@ -4127,8 +4251,14 @@ void e1000e_down(struct e1000_adapter *adapter, bool reset)
e1000_lv_jumbo_workaround_ich8lan(hw, false))
e_dbg("failed to disable jumbo frame workaround mode\n");
- if (reset && !pci_channel_offline(adapter->pdev))
- e1000e_reset(adapter);
+ if (!pci_channel_offline(adapter->pdev)) {
+ if (reset)
+ e1000e_reset(adapter);
+ else if (hw->mac.type == e1000_pch_spt)
+ e1000_flush_desc_rings(adapter);
+ }
+ e1000_clean_tx_ring(adapter->tx_ring);
+ e1000_clean_rx_ring(adapter->rx_ring);
}
void e1000e_reinit_locked(struct e1000_adapter *adapter)
@@ -4151,9 +4281,16 @@ static cycle_t e1000e_cyclecounter_read(const struct cyclecounter *cc)
cc);
struct e1000_hw *hw = &adapter->hw;
cycle_t systim, systim_next;
+ /* SYSTIMH latching upon SYSTIML read does not work well. To fix that
+ * we don't want to allow overflow of SYSTIML and a change to SYSTIMH
+ * to occur between reads, so if we read a vale close to overflow, we
+ * wait for overflow to occur and read both registers when its safe.
+ */
+ u32 systim_overflow_latch_fix = 0x3FFFFFFF;
- /* latch SYSTIMH on read of SYSTIML */
- systim = (cycle_t)er32(SYSTIML);
+ do {
+ systim = (cycle_t)er32(SYSTIML);
+ } while (systim > systim_overflow_latch_fix);
systim |= (cycle_t)er32(SYSTIMH) << 32;
if ((hw->mac.type == e1000_82574) || (hw->mac.type == e1000_82583)) {
@@ -4196,9 +4333,9 @@ static int e1000_sw_init(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN;
+ adapter->rx_buffer_len = VLAN_ETH_FRAME_LEN + ETH_FCS_LEN;
adapter->rx_ps_bsize0 = 128;
- adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+ adapter->max_frame_size = netdev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
adapter->tx_ring_count = E1000_DEFAULT_TXD;
adapter->rx_ring_count = E1000_DEFAULT_RXD;
@@ -5781,17 +5918,17 @@ struct rtnl_link_stats64 *e1000e_get_stats64(struct net_device *netdev,
static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
- int max_frame = new_mtu + VLAN_HLEN + ETH_HLEN + ETH_FCS_LEN;
+ int max_frame = new_mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
/* Jumbo frame support */
- if ((max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) &&
+ if ((max_frame > (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)) &&
!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) {
e_err("Jumbo Frames not supported.\n");
return -EINVAL;
}
/* Supported frame sizes */
- if ((new_mtu < ETH_ZLEN + ETH_FCS_LEN + VLAN_HLEN) ||
+ if ((new_mtu < (VLAN_ETH_ZLEN + ETH_FCS_LEN)) ||
(max_frame > adapter->max_hw_frame_size)) {
e_err("Unsupported MTU setting\n");
return -EINVAL;
@@ -5831,10 +5968,8 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
adapter->rx_buffer_len = 4096;
/* adjust allocation if LPE protects us, and we aren't using SBP */
- if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) ||
- (max_frame == ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN))
- adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN
- + ETH_FCS_LEN;
+ if (max_frame <= (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN))
+ adapter->rx_buffer_len = VLAN_ETH_FRAME_LEN + ETH_FCS_LEN;
if (netif_running(netdev))
e1000e_up(adapter);
@@ -6678,6 +6813,19 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter)
}
}
+static netdev_features_t e1000_fix_features(struct net_device *netdev,
+ netdev_features_t features)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ /* Jumbo frame workaround on 82579 and newer requires CRC be stripped */
+ if ((hw->mac.type >= e1000_pch2lan) && (netdev->mtu > ETH_DATA_LEN))
+ features &= ~NETIF_F_RXFCS;
+
+ return features;
+}
+
static int e1000_set_features(struct net_device *netdev,
netdev_features_t features)
{
@@ -6734,6 +6882,7 @@ static const struct net_device_ops e1000e_netdev_ops = {
.ndo_poll_controller = e1000_netpoll,
#endif
.ndo_set_features = e1000_set_features,
+ .ndo_fix_features = e1000_fix_features,
};
/**
@@ -7289,7 +7438,7 @@ static int __init e1000_init_module(void)
pr_info("Intel(R) PRO/1000 Network Driver - %s\n",
e1000e_driver_version);
- pr_info("Copyright(c) 1999 - 2014 Intel Corporation.\n");
+ pr_info("Copyright(c) 1999 - 2015 Intel Corporation.\n");
ret = pci_register_driver(&e1000_driver);
return ret;
diff --git a/drivers/net/ethernet/intel/e1000e/nvm.c b/drivers/net/ethernet/intel/e1000e/nvm.c
index fa6b1036a327..49f205c023bf 100644
--- a/drivers/net/ethernet/intel/e1000e/nvm.c
+++ b/drivers/net/ethernet/intel/e1000e/nvm.c
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/e1000e/nvm.h b/drivers/net/ethernet/intel/e1000e/nvm.h
index 342bf69efab5..5d46967e0d1f 100644
--- a/drivers/net/ethernet/intel/e1000e/nvm.h
+++ b/drivers/net/ethernet/intel/e1000e/nvm.h
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/e1000e/param.c b/drivers/net/ethernet/intel/e1000e/param.c
index aa1923f7ebdd..6d8c39abee16 100644
--- a/drivers/net/ethernet/intel/e1000e/param.c
+++ b/drivers/net/ethernet/intel/e1000e/param.c
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c
index b2005e13fb01..de13aeacae97 100644
--- a/drivers/net/ethernet/intel/e1000e/phy.c
+++ b/drivers/net/ethernet/intel/e1000e/phy.c
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/e1000e/phy.h b/drivers/net/ethernet/intel/e1000e/phy.h
index 537d2780b408..55bfe473514d 100644
--- a/drivers/net/ethernet/intel/e1000e/phy.h
+++ b/drivers/net/ethernet/intel/e1000e/phy.h
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c
index 8d7b21dc7e19..25a0ad5102d6 100644
--- a/drivers/net/ethernet/intel/e1000e/ptp.c
+++ b/drivers/net/ethernet/intel/e1000e/ptp.c
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/e1000e/regs.h b/drivers/net/ethernet/intel/e1000e/regs.h
index 85eefc4832ba..b24e5fee17f2 100644
--- a/drivers/net/ethernet/intel/e1000e/regs.h
+++ b/drivers/net/ethernet/intel/e1000e/regs.h
@@ -1,5 +1,5 @@
/* Intel PRO/1000 Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -38,6 +38,8 @@
#define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */
#define E1000_FEXTNVM6 0x00010 /* Future Extended NVM 6 - RW */
#define E1000_FEXTNVM7 0x000E4 /* Future Extended NVM 7 - RW */
+#define E1000_FEXTNVM9 0x5BB4 /* Future Extended NVM 9 - RW */
+#define E1000_FEXTNVM11 0x5BBC /* Future Extended NVM 11 - RW */
#define E1000_PCIEANACFG 0x00F18 /* PCIE Analog Config */
#define E1000_FCT 0x00030 /* Flow Control Type - RW */
#define E1000_VET 0x00038 /* VLAN Ether Type - RW */
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c
index 4b9d9f88af70..c6dc9683429e 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c
@@ -124,7 +124,7 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
struct fm10k_intfc *interface = netdev_priv(dev);
char *p = (char *)data;
- int i;
+ unsigned int i;
switch (stringset) {
case ETH_SS_TEST:
@@ -143,12 +143,13 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset, u8 *data)
p += ETH_GSTRING_LEN;
}
- if (interface->hw.mac.type != fm10k_mac_vf)
+ if (interface->hw.mac.type != fm10k_mac_vf) {
for (i = 0; i < FM10K_PF_STATS_LEN; i++) {
memcpy(p, fm10k_gstrings_pf_stats[i].stat_string,
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
+ }
for (i = 0; i < interface->hw.mac.max_queues; i++) {
sprintf(p, "tx_queue_%u_packets", i);
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_iov.c b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c
index 5b08e6284a3c..94571e6e790c 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_iov.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c
@@ -400,11 +400,31 @@ int fm10k_iov_configure(struct pci_dev *pdev, int num_vfs)
return num_vfs;
}
+static inline void fm10k_reset_vf_info(struct fm10k_intfc *interface,
+ struct fm10k_vf_info *vf_info)
+{
+ struct fm10k_hw *hw = &interface->hw;
+
+ /* assigning the MAC address will send a mailbox message */
+ fm10k_mbx_lock(interface);
+
+ /* disable LPORT for this VF which clears switch rules */
+ hw->iov.ops.reset_lport(hw, vf_info);
+
+ /* assign new MAC+VLAN for this VF */
+ hw->iov.ops.assign_default_mac_vlan(hw, vf_info);
+
+ /* re-enable the LPORT for this VF */
+ hw->iov.ops.set_lport(hw, vf_info, vf_info->vf_idx,
+ FM10K_VF_FLAG_MULTI_CAPABLE);
+
+ fm10k_mbx_unlock(interface);
+}
+
int fm10k_ndo_set_vf_mac(struct net_device *netdev, int vf_idx, u8 *mac)
{
struct fm10k_intfc *interface = netdev_priv(netdev);
struct fm10k_iov_data *iov_data = interface->iov_data;
- struct fm10k_hw *hw = &interface->hw;
struct fm10k_vf_info *vf_info;
/* verify SR-IOV is active and that vf idx is valid */
@@ -419,13 +439,7 @@ int fm10k_ndo_set_vf_mac(struct net_device *netdev, int vf_idx, u8 *mac)
vf_info = &iov_data->vf_info[vf_idx];
ether_addr_copy(vf_info->mac, mac);
- /* assigning the MAC will send a mailbox message so lock is needed */
- fm10k_mbx_lock(interface);
-
- /* assign MAC address to VF */
- hw->iov.ops.assign_default_mac_vlan(hw, vf_info);
-
- fm10k_mbx_unlock(interface);
+ fm10k_reset_vf_info(interface, vf_info);
return 0;
}
@@ -455,16 +469,10 @@ int fm10k_ndo_set_vf_vlan(struct net_device *netdev, int vf_idx, u16 vid,
/* record default VLAN ID for VF */
vf_info->pf_vid = vid;
- /* assigning the VLAN will send a mailbox message so lock is needed */
- fm10k_mbx_lock(interface);
-
/* Clear the VLAN table for the VF */
hw->mac.ops.update_vlan(hw, FM10K_VLAN_ALL, vf_info->vsi, false);
- /* Update VF assignment and trigger reset */
- hw->iov.ops.assign_default_mac_vlan(hw, vf_info);
-
- fm10k_mbx_unlock(interface);
+ fm10k_reset_vf_info(interface, vf_info);
return 0;
}
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
index c754b2027281..982fdcdc795b 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
@@ -269,16 +269,19 @@ static bool fm10k_add_rx_frag(struct fm10k_rx_buffer *rx_buffer,
struct sk_buff *skb)
{
struct page *page = rx_buffer->page;
+ unsigned char *va = page_address(page) + rx_buffer->page_offset;
unsigned int size = le16_to_cpu(rx_desc->w.length);
#if (PAGE_SIZE < 8192)
unsigned int truesize = FM10K_RX_BUFSZ;
#else
- unsigned int truesize = ALIGN(size, L1_CACHE_BYTES);
+ unsigned int truesize = SKB_DATA_ALIGN(size);
#endif
+ unsigned int pull_len;
- if ((size <= FM10K_RX_HDR_LEN) && !skb_is_nonlinear(skb)) {
- unsigned char *va = page_address(page) + rx_buffer->page_offset;
+ if (unlikely(skb_is_nonlinear(skb)))
+ goto add_tail_frag;
+ if (likely(size <= FM10K_RX_HDR_LEN)) {
memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long)));
/* page is not reserved, we can reuse buffer as-is */
@@ -290,8 +293,21 @@ static bool fm10k_add_rx_frag(struct fm10k_rx_buffer *rx_buffer,
return false;
}
+ /* we need the header to contain the greater of either ETH_HLEN or
+ * 60 bytes if the skb->len is less than 60 for skb_pad.
+ */
+ pull_len = eth_get_headlen(va, FM10K_RX_HDR_LEN);
+
+ /* align pull length to size of long to optimize memcpy performance */
+ memcpy(__skb_put(skb, pull_len), va, ALIGN(pull_len, sizeof(long)));
+
+ /* update all of the pointers */
+ va += pull_len;
+ size -= pull_len;
+
+add_tail_frag:
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
- rx_buffer->page_offset, size, truesize);
+ (unsigned long)va & ~PAGE_MASK, size, truesize);
return fm10k_can_reuse_rx_page(rx_buffer, page, truesize);
}
@@ -518,44 +534,6 @@ static bool fm10k_is_non_eop(struct fm10k_ring *rx_ring,
}
/**
- * fm10k_pull_tail - fm10k specific version of skb_pull_tail
- * @skb: pointer to current skb being adjusted
- *
- * This function is an fm10k specific version of __pskb_pull_tail. The
- * main difference between this version and the original function is that
- * this function can make several assumptions about the state of things
- * that allow for significant optimizations versus the standard function.
- * As a result we can do things like drop a frag and maintain an accurate
- * truesize for the skb.
- */
-static void fm10k_pull_tail(struct sk_buff *skb)
-{
- struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
- unsigned char *va;
- unsigned int pull_len;
-
- /* it is valid to use page_address instead of kmap since we are
- * working with pages allocated out of the lomem pool per
- * alloc_page(GFP_ATOMIC)
- */
- va = skb_frag_address(frag);
-
- /* we need the header to contain the greater of either ETH_HLEN or
- * 60 bytes if the skb->len is less than 60 for skb_pad.
- */
- pull_len = eth_get_headlen(va, FM10K_RX_HDR_LEN);
-
- /* align pull length to size of long to optimize memcpy performance */
- skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));
-
- /* update all of the pointers */
- skb_frag_size_sub(frag, pull_len);
- frag->page_offset += pull_len;
- skb->data_len -= pull_len;
- skb->tail += pull_len;
-}
-
-/**
* fm10k_cleanup_headers - Correct corrupted or empty headers
* @rx_ring: rx descriptor ring packet is being transacted on
* @rx_desc: pointer to the EOP Rx descriptor
@@ -580,10 +558,6 @@ static bool fm10k_cleanup_headers(struct fm10k_ring *rx_ring,
return true;
}
- /* place header in linear portion of buffer */
- if (skb_is_nonlinear(skb))
- fm10k_pull_tail(skb);
-
/* if eth_skb_pad returns an error the skb was freed */
if (eth_skb_pad(skb))
return true;
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c b/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c
index 1b2738380518..1a4b52637de9 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c
@@ -1259,16 +1259,11 @@ static s32 fm10k_mbx_process_error(struct fm10k_hw *hw,
struct fm10k_mbx_info *mbx)
{
const u32 *hdr = &mbx->mbx_hdr;
- s32 err_no;
u16 head;
/* we will need to pull all of the fields for verification */
head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
- /* we only have lower 10 bits of error number so add upper bits */
- err_no = FM10K_MSG_HDR_FIELD_GET(*hdr, ERR_NO);
- err_no |= ~FM10K_MSG_HDR_MASK(ERR_NO);
-
switch (mbx->state) {
case FM10K_STATE_OPEN:
case FM10K_STATE_DISCONNECT:
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
index 2f4f41b7eae7..99228bf46c12 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
@@ -923,18 +923,12 @@ static int __fm10k_mc_sync(struct net_device *dev,
struct fm10k_intfc *interface = netdev_priv(dev);
struct fm10k_hw *hw = &interface->hw;
u16 vid, glort = interface->glort;
- s32 err;
-
- if (!is_multicast_ether_addr(addr))
- return -EADDRNOTAVAIL;
/* update table with current entries */
for (vid = hw->mac.default_vid ? fm10k_find_next_vlan(interface, 0) : 0;
vid < VLAN_N_VID;
vid = fm10k_find_next_vlan(interface, vid)) {
- err = hw->mac.ops.update_mc_addr(hw, glort, addr, vid, sync);
- if (err)
- return err;
+ hw->mac.ops.update_mc_addr(hw, glort, addr, vid, sync);
}
return 0;
@@ -1339,8 +1333,7 @@ static void fm10k_dfwd_del_station(struct net_device *dev, void *priv)
dglort.rss_l = fls(interface->ring_feature[RING_F_RSS].mask);
dglort.pc_l = fls(interface->ring_feature[RING_F_QOS].mask);
dglort.glort = interface->glort;
- if (l2_accel)
- dglort.shared_l = fls(l2_accel->size);
+ dglort.shared_l = fls(l2_accel->size);
hw->mac.ops.configure_dglort_map(hw, &dglort);
/* If table is empty remove it */
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
index df9fda38bdd1..ce53ff25f88d 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
@@ -1559,6 +1559,7 @@ void fm10k_down(struct fm10k_intfc *interface)
/* free any buffers still on the rings */
fm10k_clean_all_tx_rings(interface);
+ fm10k_clean_all_rx_rings(interface);
}
/**
@@ -1740,30 +1741,18 @@ static int fm10k_probe(struct pci_dev *pdev,
struct fm10k_intfc *interface;
struct fm10k_hw *hw;
int err;
- u64 dma_mask;
err = pci_enable_device_mem(pdev);
if (err)
return err;
- /* By default fm10k only supports a 48 bit DMA mask */
- dma_mask = DMA_BIT_MASK(48) | dma_get_required_mask(&pdev->dev);
-
- if ((dma_mask <= DMA_BIT_MASK(32)) ||
- dma_set_mask_and_coherent(&pdev->dev, dma_mask)) {
- dma_mask &= DMA_BIT_MASK(32);
-
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48));
+ if (err)
err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
- err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (err) {
- err = dma_set_coherent_mask(&pdev->dev,
- DMA_BIT_MASK(32));
- if (err) {
- dev_err(&pdev->dev,
- "No usable DMA configuration, aborting\n");
- goto err_dma;
- }
- }
+ if (err) {
+ dev_err(&pdev->dev,
+ "DMA configuration failed: %d\n", err);
+ goto err_dma;
}
err = pci_request_selected_regions(pdev,
@@ -1772,7 +1761,7 @@ static int fm10k_probe(struct pci_dev *pdev,
fm10k_driver_name);
if (err) {
dev_err(&pdev->dev,
- "pci_request_selected_regions failed 0x%x\n", err);
+ "pci_request_selected_regions failed: %d\n", err);
goto err_pci_reg;
}
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c
index 891e21874b2a..3ca0233b3ea2 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c
@@ -1046,6 +1046,12 @@ static s32 fm10k_iov_reset_resources_pf(struct fm10k_hw *hw,
fm10k_write_reg(hw, FM10K_RQMAP(qmap_idx + i), vf_q_idx + i);
}
+ /* repeat the first ring for all the remaining VF rings */
+ for (i = queues_per_pool; i < qmap_stride; i++) {
+ fm10k_write_reg(hw, FM10K_TQMAP(qmap_idx + i), vf_q_idx);
+ fm10k_write_reg(hw, FM10K_RQMAP(qmap_idx + i), vf_q_idx);
+ }
+
return 0;
}
@@ -1345,6 +1351,14 @@ s32 fm10k_iov_msg_lport_state_pf(struct fm10k_hw *hw, u32 **results,
err = fm10k_update_lport_state_pf(hw, vf_info->glort,
1, false);
+ /* we need to clear VF_FLAG_ENABLED flags in order to ensure
+ * that we actually re-enable the LPORT state below. Note that
+ * this has no impact if the VF is already disabled, as the
+ * flags are already cleared.
+ */
+ if (!err)
+ vf_info->vf_flags = FM10K_VF_FLAG_CAPABLE(vf_info);
+
/* when enabling the port we should reset the rate limiters */
hw->iov.ops.configure_tc(hw, vf_info->vf_idx, vf_info->rate);
@@ -1786,8 +1800,8 @@ static s32 fm10k_adjust_systime_pf(struct fm10k_hw *hw, s32 ppb)
if (systime_adjust > FM10K_SW_SYSTIME_ADJUST_MASK)
return FM10K_ERR_PARAM;
- if (ppb < 0)
- systime_adjust |= FM10K_SW_SYSTIME_ADJUST_DIR_NEGATIVE;
+ if (ppb > 0)
+ systime_adjust |= FM10K_SW_SYSTIME_ADJUST_DIR_POSITIVE;
fm10k_write_sw_reg(hw, FM10K_SW_SYSTIME_ADJUST, (u32)systime_adjust);
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pf.h b/drivers/net/ethernet/intel/fm10k/fm10k_pf.h
index 7ab1db4fff32..40a0dbc62a04 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_pf.h
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_pf.h
@@ -81,26 +81,26 @@ struct fm10k_mac_update {
__le16 glort;
u8 flags;
u8 action;
-};
+} __packed;
struct fm10k_global_table_data {
__le32 used;
__le32 avail;
-};
+} __packed;
struct fm10k_swapi_error {
__le32 status;
struct fm10k_global_table_data mac;
struct fm10k_global_table_data nexthop;
struct fm10k_global_table_data ffu;
-};
+} __packed;
struct fm10k_swapi_1588_timestamp {
__le64 egress;
__le64 ingress;
__le16 dglort;
__le16 sglort;
-};
+} __packed;
s32 fm10k_msg_lport_map_pf(struct fm10k_hw *, u32 **, struct fm10k_mbx_info *);
extern const struct fm10k_tlv_attr fm10k_lport_map_msg_attr[];
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c b/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c
index 9043633c3e50..b4945e8abe03 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c
@@ -70,16 +70,16 @@ void fm10k_ts_tx_enqueue(struct fm10k_intfc *interface, struct sk_buff *skb)
* if none are present then insert skb in tail of list
*/
skb = fm10k_ts_tx_skb(interface, FM10K_CB(clone)->fi.w.dglort);
- if (!skb)
+ if (!skb) {
+ skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS;
__skb_queue_tail(list, clone);
+ }
spin_unlock_irqrestore(&list->lock, flags);
/* if list is already has one then we just free the clone */
if (skb)
- kfree_skb(skb);
- else
- skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS;
+ dev_kfree_skb(clone);
}
void fm10k_ts_tx_hwtstamp(struct fm10k_intfc *interface, __le16 dglort,
@@ -103,9 +103,10 @@ void fm10k_ts_tx_hwtstamp(struct fm10k_intfc *interface, __le16 dglort,
if (!skb)
return;
- /* timestamp the sk_buff and return it to the socket */
+ /* timestamp the sk_buff and free out copy */
fm10k_systime_to_hwtstamp(interface, &shhwtstamps, systime);
- skb_complete_tx_timestamp(skb, &shhwtstamps);
+ skb_tstamp_tx(skb, &shhwtstamps);
+ dev_kfree_skb_any(skb);
}
void fm10k_ts_tx_subtask(struct fm10k_intfc *interface)
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_type.h b/drivers/net/ethernet/intel/fm10k/fm10k_type.h
index 4af96686c584..2a17d82fa37d 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_type.h
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_type.h
@@ -369,7 +369,7 @@ struct fm10k_hw;
/* Registers contained in BAR 4 for Switch management */
#define FM10K_SW_SYSTIME_ADJUST 0x0224D
#define FM10K_SW_SYSTIME_ADJUST_MASK 0x3FFFFFFF
-#define FM10K_SW_SYSTIME_ADJUST_DIR_NEGATIVE 0x80000000
+#define FM10K_SW_SYSTIME_ADJUST_DIR_POSITIVE 0x80000000
#define FM10K_SW_SYSTIME_PULSE(_n) ((_n) + 0x02252)
enum fm10k_int_source {
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index 5d47307121ab..ec76c3fa3a04 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -182,6 +182,7 @@ struct i40e_lump_tracking {
enum i40e_fd_stat_idx {
I40E_FD_STAT_ATR,
I40E_FD_STAT_SB,
+ I40E_FD_STAT_ATR_TUNNEL,
I40E_FD_STAT_PF_COUNT
};
#define I40E_FD_STAT_PF_IDX(pf_id) ((pf_id) * I40E_FD_STAT_PF_COUNT)
@@ -189,6 +190,8 @@ enum i40e_fd_stat_idx {
(I40E_FD_STAT_PF_IDX(pf_id) + I40E_FD_STAT_ATR)
#define I40E_FD_SB_STAT_IDX(pf_id) \
(I40E_FD_STAT_PF_IDX(pf_id) + I40E_FD_STAT_SB)
+#define I40E_FD_ATR_TUNNEL_STAT_IDX(pf_id) \
+ (I40E_FD_STAT_PF_IDX(pf_id) + I40E_FD_STAT_ATR_TUNNEL)
struct i40e_fdir_filter {
struct hlist_node fdir_node;
@@ -263,8 +266,6 @@ struct i40e_pf {
struct hlist_head fdir_filter_list;
u16 fdir_pf_active_filters;
- u16 fd_sb_cnt_idx;
- u16 fd_atr_cnt_idx;
unsigned long fd_flush_timestamp;
u32 fd_flush_cnt;
u32 fd_add_err;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index 4cbaaeb902c4..9a68c65b17ea 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -147,6 +147,7 @@ static struct i40e_stats i40e_gstrings_stats[] = {
I40E_PF_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
I40E_PF_STAT("fdir_flush_cnt", fd_flush_cnt),
I40E_PF_STAT("fdir_atr_match", stats.fd_atr_match),
+ I40E_PF_STAT("fdir_atr_tunnel_match", stats.fd_atr_tunnel_match),
I40E_PF_STAT("fdir_sb_match", stats.fd_sb_match),
/* LPI stats */
@@ -1548,6 +1549,17 @@ static int i40e_loopback_test(struct net_device *netdev, u64 *data)
return *data;
}
+static inline bool i40e_active_vfs(struct i40e_pf *pf)
+{
+ struct i40e_vf *vfs = pf->vf;
+ int i;
+
+ for (i = 0; i < pf->num_alloc_vfs; i++)
+ if (vfs[i].vf_states & I40E_VF_STAT_ACTIVE)
+ return true;
+ return false;
+}
+
static void i40e_diag_test(struct net_device *netdev,
struct ethtool_test *eth_test, u64 *data)
{
@@ -1560,6 +1572,20 @@ static void i40e_diag_test(struct net_device *netdev,
netif_info(pf, drv, netdev, "offline testing starting\n");
set_bit(__I40E_TESTING, &pf->state);
+
+ if (i40e_active_vfs(pf)) {
+ dev_warn(&pf->pdev->dev,
+ "Please take active VFS offline and restart the adapter before running NIC diagnostics\n");
+ data[I40E_ETH_TEST_REG] = 1;
+ data[I40E_ETH_TEST_EEPROM] = 1;
+ data[I40E_ETH_TEST_INTR] = 1;
+ data[I40E_ETH_TEST_LOOPBACK] = 1;
+ data[I40E_ETH_TEST_LINK] = 1;
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+ clear_bit(__I40E_TESTING, &pf->state);
+ goto skip_ol_tests;
+ }
+
/* If the device is online then take it offline */
if (if_running)
/* indicate we're in test mode */
@@ -1605,6 +1631,8 @@ static void i40e_diag_test(struct net_device *netdev,
data[I40E_ETH_TEST_LOOPBACK] = 0;
}
+skip_ol_tests:
+
netif_info(pf, drv, netdev, "testing finished\n");
}
@@ -2265,7 +2293,7 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
input->pctype = 0;
input->dest_vsi = vsi->id;
input->fd_status = I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID;
- input->cnt_index = pf->fd_sb_cnt_idx;
+ input->cnt_index = I40E_FD_SB_STAT_IDX(pf->hw.pf_id);
input->flow_type = fsp->flow_type;
input->ip4_proto = fsp->h_u.usr_ip4_spec.proto;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c
index 1803afeef23e..c8b621e0e7cd 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c
@@ -118,7 +118,7 @@ static inline int i40e_fcoe_fc_eof(struct sk_buff *skb, u8 *eof)
*
* The FC EOF is converted to the value understood by HW for descriptor
* programming. Never call this w/o calling i40e_fcoe_eof_is_supported()
- * first.
+ * first and that already checks for all supported valid eof values.
**/
static inline u32 i40e_fcoe_ctxt_eof(u8 eof)
{
@@ -132,9 +132,12 @@ static inline u32 i40e_fcoe_ctxt_eof(u8 eof)
case FC_EOF_A:
return I40E_TX_DESC_CMD_L4T_EOFT_EOF_A;
default:
- /* FIXME: still returns 0 */
- pr_err("Unrecognized EOF %x\n", eof);
- return 0;
+ /* Supported valid eof shall be already checked by
+ * calling i40e_fcoe_eof_is_supported() first,
+ * therefore this default case shall never hit.
+ */
+ WARN_ON(1);
+ return -EINVAL;
}
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 5b5bea159bd5..48a52b35b614 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -39,7 +39,7 @@ static const char i40e_driver_string[] =
#define DRV_VERSION_MAJOR 1
#define DRV_VERSION_MINOR 3
-#define DRV_VERSION_BUILD 2
+#define DRV_VERSION_BUILD 4
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
__stringify(DRV_VERSION_MINOR) "." \
__stringify(DRV_VERSION_BUILD) DRV_KERN
@@ -772,9 +772,8 @@ static void i40e_update_prio_xoff_rx(struct i40e_pf *pf)
dcb_cfg = &hw->local_dcbx_config;
- /* See if DCB enabled with PFC TC */
- if (!(pf->flags & I40E_FLAG_DCB_ENABLED) ||
- !(dcb_cfg->pfc.pfcenable)) {
+ /* Collect Link XOFF stats when PFC is disabled */
+ if (!dcb_cfg->pfc.pfcenable) {
i40e_update_link_xoff_rx(pf);
return;
}
@@ -1097,12 +1096,18 @@ static void i40e_update_pf_stats(struct i40e_pf *pf)
&osd->rx_jabber, &nsd->rx_jabber);
/* FDIR stats */
- i40e_stat_update32(hw, I40E_GLQF_PCNT(pf->fd_atr_cnt_idx),
+ i40e_stat_update32(hw,
+ I40E_GLQF_PCNT(I40E_FD_ATR_STAT_IDX(pf->hw.pf_id)),
pf->stat_offsets_loaded,
&osd->fd_atr_match, &nsd->fd_atr_match);
- i40e_stat_update32(hw, I40E_GLQF_PCNT(pf->fd_sb_cnt_idx),
+ i40e_stat_update32(hw,
+ I40E_GLQF_PCNT(I40E_FD_SB_STAT_IDX(pf->hw.pf_id)),
pf->stat_offsets_loaded,
&osd->fd_sb_match, &nsd->fd_sb_match);
+ i40e_stat_update32(hw,
+ I40E_GLQF_PCNT(I40E_FD_ATR_TUNNEL_STAT_IDX(pf->hw.pf_id)),
+ pf->stat_offsets_loaded,
+ &osd->fd_atr_tunnel_match, &nsd->fd_atr_tunnel_match);
val = rd32(hw, I40E_PRTPM_EEE_STAT);
nsd->tx_lpi_status =
@@ -4739,7 +4744,8 @@ static int i40e_up_complete(struct i40e_vsi *vsi)
pf->fd_add_err = pf->fd_atr_cnt = 0;
if (pf->fd_tcp_rule > 0) {
pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
- dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 exist\n");
+ if (I40E_DEBUG_FD & pf->hw.debug_mask)
+ dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 exist\n");
pf->fd_tcp_rule = 0;
}
i40e_fdir_filter_restore(vsi);
@@ -5428,7 +5434,8 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
(pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) {
pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED;
- dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n");
+ if (I40E_DEBUG_FD & pf->hw.debug_mask)
+ dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n");
}
}
/* Wait for some more space to be available to turn on ATR */
@@ -5436,7 +5443,8 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
(pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) {
pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
- dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table now\n");
+ if (I40E_DEBUG_FD & pf->hw.debug_mask)
+ dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table now\n");
}
}
}
@@ -5469,7 +5477,8 @@ static void i40e_fdir_flush_and_replay(struct i40e_pf *pf)
if (!(time_after(jiffies, min_flush_time)) &&
(fd_room < I40E_FDIR_BUFFER_HEAD_ROOM_FOR_ATR)) {
- dev_info(&pf->pdev->dev, "ATR disabled, not enough FD filter space.\n");
+ if (I40E_DEBUG_FD & pf->hw.debug_mask)
+ dev_info(&pf->pdev->dev, "ATR disabled, not enough FD filter space.\n");
disable_atr = true;
}
@@ -5496,7 +5505,8 @@ static void i40e_fdir_flush_and_replay(struct i40e_pf *pf)
if (!disable_atr)
pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
clear_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state);
- dev_info(&pf->pdev->dev, "FD Filter table flushed and FD-SB replayed.\n");
+ if (I40E_DEBUG_FD & pf->hw.debug_mask)
+ dev_info(&pf->pdev->dev, "FD Filter table flushed and FD-SB replayed.\n");
}
}
}
@@ -7680,12 +7690,8 @@ static int i40e_sw_init(struct i40e_pf *pf)
(pf->hw.func_caps.fd_filters_best_effort > 0)) {
pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
pf->atr_sample_rate = I40E_DEFAULT_ATR_SAMPLE_RATE;
- /* Setup a counter for fd_atr per PF */
- pf->fd_atr_cnt_idx = I40E_FD_ATR_STAT_IDX(pf->hw.pf_id);
if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) {
pf->flags |= I40E_FLAG_FD_SB_ENABLED;
- /* Setup a counter for fd_sb per PF */
- pf->fd_sb_cnt_idx = I40E_FD_SB_STAT_IDX(pf->hw.pf_id);
} else {
dev_info(&pf->pdev->dev,
"Flow Director Sideband mode Disabled in MFP mode\n");
@@ -7775,7 +7781,8 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
pf->fd_add_err = pf->fd_atr_cnt = pf->fd_tcp_rule = 0;
pf->fdir_pf_active_filters = 0;
pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
- dev_info(&pf->pdev->dev, "ATR re-enabled.\n");
+ if (I40E_DEBUG_FD & pf->hw.debug_mask)
+ dev_info(&pf->pdev->dev, "ATR re-enabled.\n");
/* if ATR was auto disabled it can be re-enabled. */
if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
(pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED))
@@ -8062,7 +8069,7 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev,
#ifdef HAVE_BRIDGE_FILTER
static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
struct net_device *dev,
- u32 __always_unused filter_mask, int nlflags)
+ u32 filter_mask, int nlflags)
#else
static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
struct net_device *dev, int nlflags)
@@ -8088,7 +8095,7 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
return 0;
return ndo_dflt_bridge_getlink(skb, pid, seq, dev, veb->bridge_mode,
- nlflags);
+ nlflags, 0, 0, filter_mask, NULL);
}
#endif /* HAVE_BRIDGE_ATTRIBS */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index 9d95042d5a0f..9a4f2bc70cd2 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -165,9 +165,6 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet,
tx_desc->cmd_type_offset_bsz =
build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_SIZE, 0);
- /* set the timestamp */
- tx_buf->time_stamp = jiffies;
-
/* Force memory writes to complete before letting h/w
* know there are new descriptors to fetch.
*/
@@ -283,7 +280,8 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
if (add) {
pf->fd_tcp_rule++;
if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) {
- dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
+ if (I40E_DEBUG_FD & pf->hw.debug_mask)
+ dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
}
} else {
@@ -291,7 +289,8 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
(pf->fd_tcp_rule - 1) : 0;
if (pf->fd_tcp_rule == 0) {
pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
- dev_info(&pf->pdev->dev, "ATR re-enabled due to no sideband TCP/IPv4 rules\n");
+ if (I40E_DEBUG_FD & pf->hw.debug_mask)
+ dev_info(&pf->pdev->dev, "ATR re-enabled due to no sideband TCP/IPv4 rules\n");
}
}
@@ -501,7 +500,8 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
!(pf->auto_disable_flags &
I40E_FLAG_FD_SB_ENABLED)) {
- dev_warn(&pdev->dev, "FD filter space full, new ntuple rules will not be added\n");
+ if (I40E_DEBUG_FD & pf->hw.debug_mask)
+ dev_warn(&pdev->dev, "FD filter space full, new ntuple rules will not be added\n");
pf->auto_disable_flags |=
I40E_FLAG_FD_SB_ENABLED;
}
@@ -807,10 +807,6 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
tx_ring->vsi->seid,
tx_ring->queue_index,
tx_ring->next_to_use, i);
- dev_info(tx_ring->dev, "tx_bi[next_to_clean]\n"
- " time_stamp <%lx>\n"
- " jiffies <%lx>\n",
- tx_ring->tx_bi[i].time_stamp, jiffies);
netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
@@ -1653,9 +1649,6 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
/* ERR_MASK will only have valid bits if EOP set */
if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) {
dev_kfree_skb_any(skb);
- /* TODO: shouldn't we increment a counter indicating the
- * drop?
- */
continue;
}
@@ -1688,7 +1681,6 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
skb_mark_napi_id(skb, &rx_ring->q_vector->napi);
i40e_receive_skb(rx_ring, skb, vlan_tag);
- rx_ring->netdev->last_rx = jiffies;
rx_desc->wb.qword1.status_error_len = 0;
} while (likely(total_rx_packets < budget));
@@ -1821,7 +1813,6 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget)
#endif
i40e_receive_skb(rx_ring, skb, vlan_tag);
- rx_ring->netdev->last_rx = jiffies;
rx_desc->wb.qword1.status_error_len = 0;
} while (likely(total_rx_packets < budget));
@@ -1925,11 +1916,11 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
* i40e_atr - Add a Flow Director ATR filter
* @tx_ring: ring to add programming descriptor to
* @skb: send buffer
- * @flags: send flags
+ * @tx_flags: send tx flags
* @protocol: wire protocol
**/
static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
- u32 flags, __be16 protocol)
+ u32 tx_flags, __be16 protocol)
{
struct i40e_filter_program_desc *fdir_desc;
struct i40e_pf *pf = tx_ring->vsi->back;
@@ -1954,25 +1945,38 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
if (!tx_ring->atr_sample_rate)
return;
- /* snag network header to get L4 type and address */
- hdr.network = skb_network_header(skb);
+ if (!(tx_flags & (I40E_TX_FLAGS_IPV4 | I40E_TX_FLAGS_IPV6)))
+ return;
- /* Currently only IPv4/IPv6 with TCP is supported */
- if (protocol == htons(ETH_P_IP)) {
- if (hdr.ipv4->protocol != IPPROTO_TCP)
- return;
+ if (!(tx_flags & I40E_TX_FLAGS_VXLAN_TUNNEL)) {
+ /* snag network header to get L4 type and address */
+ hdr.network = skb_network_header(skb);
- /* access ihl as a u8 to avoid unaligned access on ia64 */
- hlen = (hdr.network[0] & 0x0F) << 2;
- } else if (protocol == htons(ETH_P_IPV6)) {
- if (hdr.ipv6->nexthdr != IPPROTO_TCP)
+ /* Currently only IPv4/IPv6 with TCP is supported
+ * access ihl as u8 to avoid unaligned access on ia64
+ */
+ if (tx_flags & I40E_TX_FLAGS_IPV4)
+ hlen = (hdr.network[0] & 0x0F) << 2;
+ else if (protocol == htons(ETH_P_IPV6))
+ hlen = sizeof(struct ipv6hdr);
+ else
return;
-
- hlen = sizeof(struct ipv6hdr);
} else {
- return;
+ hdr.network = skb_inner_network_header(skb);
+ hlen = skb_inner_network_header_len(skb);
}
+ /* Currently only IPv4/IPv6 with TCP is supported
+ * Note: tx_flags gets modified to reflect inner protocols in
+ * tx_enable_csum function if encap is enabled.
+ */
+ if ((tx_flags & I40E_TX_FLAGS_IPV4) &&
+ (hdr.ipv4->protocol != IPPROTO_TCP))
+ return;
+ else if ((tx_flags & I40E_TX_FLAGS_IPV6) &&
+ (hdr.ipv6->nexthdr != IPPROTO_TCP))
+ return;
+
th = (struct tcphdr *)(hdr.network + hlen);
/* Due to lack of space, no more new filters can be programmed */
@@ -2022,9 +2026,16 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT;
dtype_cmd |= I40E_TXD_FLTR_QW1_CNT_ENA_MASK;
- dtype_cmd |=
- ((u32)pf->fd_atr_cnt_idx << I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) &
- I40E_TXD_FLTR_QW1_CNTINDEX_MASK;
+ if (!(tx_flags & I40E_TX_FLAGS_VXLAN_TUNNEL))
+ dtype_cmd |=
+ ((u32)I40E_FD_ATR_STAT_IDX(pf->hw.pf_id) <<
+ I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) &
+ I40E_TXD_FLTR_QW1_CNTINDEX_MASK;
+ else
+ dtype_cmd |=
+ ((u32)I40E_FD_ATR_TUNNEL_STAT_IDX(pf->hw.pf_id) <<
+ I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) &
+ I40E_TXD_FLTR_QW1_CNTINDEX_MASK;
fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(flex_ptype);
fdir_desc->rsvd = cpu_to_le32(0);
@@ -2045,13 +2056,13 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
* otherwise returns 0 to indicate the flags has been set properly.
**/
#ifdef I40E_FCOE
-int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,
- struct i40e_ring *tx_ring,
- u32 *flags)
-#else
-static int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,
+inline int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,
struct i40e_ring *tx_ring,
u32 *flags)
+#else
+static inline int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,
+ struct i40e_ring *tx_ring,
+ u32 *flags)
#endif
{
__be16 protocol = skb->protocol;
@@ -2119,16 +2130,14 @@ out:
* i40e_tso - set up the tso context descriptor
* @tx_ring: ptr to the ring to send
* @skb: ptr to the skb we're sending
- * @tx_flags: the collected send information
- * @protocol: the send protocol
* @hdr_len: ptr to the size of the packet header
* @cd_tunneling: ptr to context descriptor bits
*
* Returns 0 if no TSO can happen, 1 if tso is going, or error
**/
static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
- u32 tx_flags, __be16 protocol, u8 *hdr_len,
- u64 *cd_type_cmd_tso_mss, u32 *cd_tunneling)
+ u8 *hdr_len, u64 *cd_type_cmd_tso_mss,
+ u32 *cd_tunneling)
{
u32 cd_cmd, cd_tso_len, cd_mss;
struct ipv6hdr *ipv6h;
@@ -2220,12 +2229,12 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb,
/**
* i40e_tx_enable_csum - Enable Tx checksum offloads
* @skb: send buffer
- * @tx_flags: Tx flags currently set
+ * @tx_flags: pointer to Tx flags currently set
* @td_cmd: Tx descriptor command bits to set
* @td_offset: Tx descriptor header offsets to set
* @cd_tunneling: ptr to context desc bits
**/
-static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
+static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
u32 *td_cmd, u32 *td_offset,
struct i40e_ring *tx_ring,
u32 *cd_tunneling)
@@ -2241,6 +2250,7 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
switch (ip_hdr(skb)->protocol) {
case IPPROTO_UDP:
l4_tunnel = I40E_TXD_CTX_UDP_TUNNELING;
+ *tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL;
break;
default:
return;
@@ -2250,18 +2260,17 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
this_ipv6_hdr = inner_ipv6_hdr(skb);
this_tcp_hdrlen = inner_tcp_hdrlen(skb);
- if (tx_flags & I40E_TX_FLAGS_IPV4) {
-
- if (tx_flags & I40E_TX_FLAGS_TSO) {
+ if (*tx_flags & I40E_TX_FLAGS_IPV4) {
+ if (*tx_flags & I40E_TX_FLAGS_TSO) {
*cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV4;
ip_hdr(skb)->check = 0;
} else {
*cd_tunneling |=
I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
}
- } else if (tx_flags & I40E_TX_FLAGS_IPV6) {
+ } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
*cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
- if (tx_flags & I40E_TX_FLAGS_TSO)
+ if (*tx_flags & I40E_TX_FLAGS_TSO)
ip_hdr(skb)->check = 0;
}
@@ -2273,8 +2282,8 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
skb_transport_offset(skb)) >> 1) <<
I40E_TXD_CTX_QW0_NATLEN_SHIFT;
if (this_ip_hdr->version == 6) {
- tx_flags &= ~I40E_TX_FLAGS_IPV4;
- tx_flags |= I40E_TX_FLAGS_IPV6;
+ *tx_flags &= ~I40E_TX_FLAGS_IPV4;
+ *tx_flags |= I40E_TX_FLAGS_IPV6;
}
} else {
network_hdr_len = skb_network_header_len(skb);
@@ -2284,12 +2293,12 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
}
/* Enable IP checksum offloads */
- if (tx_flags & I40E_TX_FLAGS_IPV4) {
+ if (*tx_flags & I40E_TX_FLAGS_IPV4) {
l4_hdr = this_ip_hdr->protocol;
/* the stack computes the IP header already, the only time we
* need the hardware to recompute it is in the case of TSO.
*/
- if (tx_flags & I40E_TX_FLAGS_TSO) {
+ if (*tx_flags & I40E_TX_FLAGS_TSO) {
*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM;
this_ip_hdr->check = 0;
} else {
@@ -2298,7 +2307,7 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
/* Now set the td_offset for IP header length */
*td_offset = (network_hdr_len >> 2) <<
I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
- } else if (tx_flags & I40E_TX_FLAGS_IPV6) {
+ } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
l4_hdr = this_ipv6_hdr->nexthdr;
*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
/* Now set the td_offset for IP header length */
@@ -2396,9 +2405,9 @@ static inline int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
* Returns 0 if stop is not needed
**/
#ifdef I40E_FCOE
-int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
#else
-static int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
#endif
{
if (likely(I40E_DESC_UNUSED(tx_ring) >= size))
@@ -2473,13 +2482,13 @@ linearize_chk_done:
* @td_offset: offset for checksum or crc
**/
#ifdef I40E_FCOE
-void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
- struct i40e_tx_buffer *first, u32 tx_flags,
- const u8 hdr_len, u32 td_cmd, u32 td_offset)
-#else
-static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
+inline void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
struct i40e_tx_buffer *first, u32 tx_flags,
const u8 hdr_len, u32 td_cmd, u32 td_offset)
+#else
+static inline void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
+ struct i40e_tx_buffer *first, u32 tx_flags,
+ const u8 hdr_len, u32 td_cmd, u32 td_offset)
#endif
{
unsigned int data_len = skb->data_len;
@@ -2585,9 +2594,6 @@ static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
tx_ring->queue_index),
first->bytecount);
- /* set the timestamp */
- first->time_stamp = jiffies;
-
/* Force memory writes to complete before letting h/w
* know there are new descriptors to fetch. (Only
* applicable for weak-ordered memory model archs,
@@ -2640,11 +2646,11 @@ dma_error:
* one descriptor.
**/
#ifdef I40E_FCOE
-int i40e_xmit_descriptor_count(struct sk_buff *skb,
- struct i40e_ring *tx_ring)
-#else
-static int i40e_xmit_descriptor_count(struct sk_buff *skb,
+inline int i40e_xmit_descriptor_count(struct sk_buff *skb,
struct i40e_ring *tx_ring)
+#else
+static inline int i40e_xmit_descriptor_count(struct sk_buff *skb,
+ struct i40e_ring *tx_ring)
#endif
{
unsigned int f;
@@ -2706,7 +2712,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
else if (protocol == htons(ETH_P_IPV6))
tx_flags |= I40E_TX_FLAGS_IPV6;
- tso = i40e_tso(tx_ring, skb, tx_flags, protocol, &hdr_len,
+ tso = i40e_tso(tx_ring, skb, &hdr_len,
&cd_type_cmd_tso_mss, &cd_tunneling);
if (tso < 0)
@@ -2732,7 +2738,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
if (skb->ip_summed == CHECKSUM_PARTIAL) {
tx_flags |= I40E_TX_FLAGS_CSUM;
- i40e_tx_enable_csum(skb, tx_flags, &td_cmd, &td_offset,
+ i40e_tx_enable_csum(skb, &tx_flags, &td_cmd, &td_offset,
tx_ring, &cd_tunneling);
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
index 4b0b8102cdc3..0dc48dc9ca61 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
@@ -139,6 +139,7 @@ enum i40e_dyn_idx_t {
#define I40E_TX_FLAGS_FSO (u32)(1 << 7)
#define I40E_TX_FLAGS_TSYN (u32)(1 << 8)
#define I40E_TX_FLAGS_FD_SB (u32)(1 << 9)
+#define I40E_TX_FLAGS_VXLAN_TUNNEL (u32)(1 << 10)
#define I40E_TX_FLAGS_VLAN_MASK 0xffff0000
#define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000
#define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29
@@ -146,7 +147,6 @@ enum i40e_dyn_idx_t {
struct i40e_tx_buffer {
struct i40e_tx_desc *next_to_watch;
- unsigned long time_stamp;
union {
struct sk_buff *skb;
void *raw_buf;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
index 568e855da0f3..9a5a75b1e2bc 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
@@ -1133,6 +1133,7 @@ struct i40e_hw_port_stats {
/* flow director stats */
u64 fd_atr_match;
u64 fd_sb_match;
+ u64 fd_atr_tunnel_match;
/* EEE LPI */
u32 tx_lpi_status;
u32 rx_lpi_status;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index 4e9376da0518..23f95cdbdfcc 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -980,6 +980,13 @@ static int i40e_pci_sriov_enable(struct pci_dev *pdev, int num_vfs)
int pre_existing_vfs = pci_num_vf(pdev);
int err = 0;
+ if (pf->state & __I40E_TESTING) {
+ dev_warn(&pdev->dev,
+ "Cannot enable SR-IOV virtual functions while the device is undergoing diagnostic testing\n");
+ err = -EPERM;
+ goto err_out;
+ }
+
dev_info(&pdev->dev, "Allocating %d VFs.\n", num_vfs);
if (pre_existing_vfs && pre_existing_vfs != num_vfs)
i40e_free_vfs(pf);
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
index 458fbb421090..f54996f19629 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
@@ -322,10 +322,6 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
tx_ring->vsi->seid,
tx_ring->queue_index,
tx_ring->next_to_use, i);
- dev_info(tx_ring->dev, "tx_bi[next_to_clean]\n"
- " time_stamp <%lx>\n"
- " jiffies <%lx>\n",
- tx_ring->tx_bi[i].time_stamp, jiffies);
netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
@@ -1128,9 +1124,6 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
/* ERR_MASK will only have valid bits if EOP set */
if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) {
dev_kfree_skb_any(skb);
- /* TODO: shouldn't we increment a counter indicating the
- * drop?
- */
continue;
}
@@ -1156,7 +1149,6 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
skb_mark_napi_id(skb, &rx_ring->q_vector->napi);
i40e_receive_skb(rx_ring, skb, vlan_tag);
- rx_ring->netdev->last_rx = jiffies;
rx_desc->wb.qword1.status_error_len = 0;
} while (likely(total_rx_packets < budget));
@@ -1271,7 +1263,6 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget)
: 0;
i40e_receive_skb(rx_ring, skb, vlan_tag);
- rx_ring->netdev->last_rx = jiffies;
rx_desc->wb.qword1.status_error_len = 0;
} while (likely(total_rx_packets < budget));
@@ -1352,7 +1343,7 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget)
}
/**
- * i40e_tx_prepare_vlan_flags - prepare generic TX VLAN tagging flags for HW
+ * i40evf_tx_prepare_vlan_flags - prepare generic TX VLAN tagging flags for HW
* @skb: send buffer
* @tx_ring: ring to send buffer on
* @flags: the tx flags to be set
@@ -1363,9 +1354,9 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget)
* Returns error code indicate the frame should be dropped upon error and the
* otherwise returns 0 to indicate the flags has been set properly.
**/
-static int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,
- struct i40e_ring *tx_ring,
- u32 *flags)
+static inline int i40evf_tx_prepare_vlan_flags(struct sk_buff *skb,
+ struct i40e_ring *tx_ring,
+ u32 *flags)
{
__be16 protocol = skb->protocol;
u32 tx_flags = 0;
@@ -1408,16 +1399,14 @@ out:
* i40e_tso - set up the tso context descriptor
* @tx_ring: ptr to the ring to send
* @skb: ptr to the skb we're sending
- * @tx_flags: the collected send information
- * @protocol: the send protocol
* @hdr_len: ptr to the size of the packet header
* @cd_tunneling: ptr to context descriptor bits
*
* Returns 0 if no TSO can happen, 1 if tso is going, or error
**/
static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
- u32 tx_flags, __be16 protocol, u8 *hdr_len,
- u64 *cd_type_cmd_tso_mss, u32 *cd_tunneling)
+ u8 *hdr_len, u64 *cd_type_cmd_tso_mss,
+ u32 *cd_tunneling)
{
u32 cd_cmd, cd_tso_len, cd_mss;
struct ipv6hdr *ipv6h;
@@ -1468,12 +1457,12 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
/**
* i40e_tx_enable_csum - Enable Tx checksum offloads
* @skb: send buffer
- * @tx_flags: Tx flags currently set
+ * @tx_flags: pointer to Tx flags currently set
* @td_cmd: Tx descriptor command bits to set
* @td_offset: Tx descriptor header offsets to set
* @cd_tunneling: ptr to context desc bits
**/
-static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
+static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
u32 *td_cmd, u32 *td_offset,
struct i40e_ring *tx_ring,
u32 *cd_tunneling)
@@ -1489,6 +1478,7 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
switch (ip_hdr(skb)->protocol) {
case IPPROTO_UDP:
l4_tunnel = I40E_TXD_CTX_UDP_TUNNELING;
+ *tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL;
break;
default:
return;
@@ -1498,18 +1488,17 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
this_ipv6_hdr = inner_ipv6_hdr(skb);
this_tcp_hdrlen = inner_tcp_hdrlen(skb);
- if (tx_flags & I40E_TX_FLAGS_IPV4) {
-
- if (tx_flags & I40E_TX_FLAGS_TSO) {
+ if (*tx_flags & I40E_TX_FLAGS_IPV4) {
+ if (*tx_flags & I40E_TX_FLAGS_TSO) {
*cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV4;
ip_hdr(skb)->check = 0;
} else {
*cd_tunneling |=
I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
}
- } else if (tx_flags & I40E_TX_FLAGS_IPV6) {
+ } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
*cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
- if (tx_flags & I40E_TX_FLAGS_TSO)
+ if (*tx_flags & I40E_TX_FLAGS_TSO)
ip_hdr(skb)->check = 0;
}
@@ -1521,8 +1510,8 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
skb_transport_offset(skb)) >> 1) <<
I40E_TXD_CTX_QW0_NATLEN_SHIFT;
if (this_ip_hdr->version == 6) {
- tx_flags &= ~I40E_TX_FLAGS_IPV4;
- tx_flags |= I40E_TX_FLAGS_IPV6;
+ *tx_flags &= ~I40E_TX_FLAGS_IPV4;
+ *tx_flags |= I40E_TX_FLAGS_IPV6;
}
@@ -1534,12 +1523,12 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
}
/* Enable IP checksum offloads */
- if (tx_flags & I40E_TX_FLAGS_IPV4) {
+ if (*tx_flags & I40E_TX_FLAGS_IPV4) {
l4_hdr = this_ip_hdr->protocol;
/* the stack computes the IP header already, the only time we
* need the hardware to recompute it is in the case of TSO.
*/
- if (tx_flags & I40E_TX_FLAGS_TSO) {
+ if (*tx_flags & I40E_TX_FLAGS_TSO) {
*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM;
this_ip_hdr->check = 0;
} else {
@@ -1548,7 +1537,7 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
/* Now set the td_offset for IP header length */
*td_offset = (network_hdr_len >> 2) <<
I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
- } else if (tx_flags & I40E_TX_FLAGS_IPV6) {
+ } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
l4_hdr = this_ipv6_hdr->nexthdr;
*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
/* Now set the td_offset for IP header length */
@@ -1672,7 +1661,44 @@ linearize_chk_done:
}
/**
- * i40e_tx_map - Build the Tx descriptor
+ * __i40evf_maybe_stop_tx - 2nd level check for tx stop conditions
+ * @tx_ring: the ring to be checked
+ * @size: the size buffer we want to assure is available
+ *
+ * Returns -EBUSY if a stop is needed, else 0
+ **/
+static inline int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+{
+ netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
+ /* Memory barrier before checking head and tail */
+ smp_mb();
+
+ /* Check again in a case another CPU has just made room available. */
+ if (likely(I40E_DESC_UNUSED(tx_ring) < size))
+ return -EBUSY;
+
+ /* A reprieve! - use start_queue because it doesn't call schedule */
+ netif_start_subqueue(tx_ring->netdev, tx_ring->queue_index);
+ ++tx_ring->tx_stats.restart_queue;
+ return 0;
+}
+
+/**
+ * i40evf_maybe_stop_tx - 1st level check for tx stop conditions
+ * @tx_ring: the ring to be checked
+ * @size: the size buffer we want to assure is available
+ *
+ * Returns 0 if stop is not needed
+ **/
+static inline int i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+{
+ if (likely(I40E_DESC_UNUSED(tx_ring) >= size))
+ return 0;
+ return __i40evf_maybe_stop_tx(tx_ring, size);
+}
+
+/**
+ * i40evf_tx_map - Build the Tx descriptor
* @tx_ring: ring to send buffer on
* @skb: send buffer
* @first: first buffer info buffer to use
@@ -1681,9 +1707,9 @@ linearize_chk_done:
* @td_cmd: the command field in the descriptor
* @td_offset: offset for checksum or crc
**/
-static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
- struct i40e_tx_buffer *first, u32 tx_flags,
- const u8 hdr_len, u32 td_cmd, u32 td_offset)
+static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
+ struct i40e_tx_buffer *first, u32 tx_flags,
+ const u8 hdr_len, u32 td_cmd, u32 td_offset)
{
unsigned int data_len = skb->data_len;
unsigned int size = skb_headlen(skb);
@@ -1789,9 +1815,6 @@ static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
tx_ring->queue_index),
first->bytecount);
- /* set the timestamp */
- first->time_stamp = jiffies;
-
/* Force memory writes to complete before letting h/w
* know there are new descriptors to fetch. (Only
* applicable for weak-ordered memory model archs,
@@ -1808,8 +1831,12 @@ static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
tx_ring->next_to_use = i;
+ i40evf_maybe_stop_tx(tx_ring, DESC_NEEDED);
/* notify HW of packet */
- writel(i, tx_ring->tail);
+ if (!skb->xmit_more ||
+ netif_xmit_stopped(netdev_get_tx_queue(tx_ring->netdev,
+ tx_ring->queue_index)))
+ writel(i, tx_ring->tail);
return;
@@ -1831,44 +1858,7 @@ dma_error:
}
/**
- * __i40e_maybe_stop_tx - 2nd level check for tx stop conditions
- * @tx_ring: the ring to be checked
- * @size: the size buffer we want to assure is available
- *
- * Returns -EBUSY if a stop is needed, else 0
- **/
-static inline int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
-{
- netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
- /* Memory barrier before checking head and tail */
- smp_mb();
-
- /* Check again in a case another CPU has just made room available. */
- if (likely(I40E_DESC_UNUSED(tx_ring) < size))
- return -EBUSY;
-
- /* A reprieve! - use start_queue because it doesn't call schedule */
- netif_start_subqueue(tx_ring->netdev, tx_ring->queue_index);
- ++tx_ring->tx_stats.restart_queue;
- return 0;
-}
-
-/**
- * i40e_maybe_stop_tx - 1st level check for tx stop conditions
- * @tx_ring: the ring to be checked
- * @size: the size buffer we want to assure is available
- *
- * Returns 0 if stop is not needed
- **/
-static int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
-{
- if (likely(I40E_DESC_UNUSED(tx_ring) >= size))
- return 0;
- return __i40e_maybe_stop_tx(tx_ring, size);
-}
-
-/**
- * i40e_xmit_descriptor_count - calculate number of tx descriptors needed
+ * i40evf_xmit_descriptor_count - calculate number of tx descriptors needed
* @skb: send buffer
* @tx_ring: ring to send buffer on
*
@@ -1876,8 +1866,8 @@ static int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
* there is not enough descriptors available in this ring since we need at least
* one descriptor.
**/
-static int i40e_xmit_descriptor_count(struct sk_buff *skb,
- struct i40e_ring *tx_ring)
+static inline int i40evf_xmit_descriptor_count(struct sk_buff *skb,
+ struct i40e_ring *tx_ring)
{
unsigned int f;
int count = 0;
@@ -1892,7 +1882,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb,
count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
count += TXD_USE_COUNT(skb_headlen(skb));
- if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
+ if (i40evf_maybe_stop_tx(tx_ring, count + 4 + 1)) {
tx_ring->tx_stats.tx_busy++;
return 0;
}
@@ -1918,11 +1908,11 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
u32 td_cmd = 0;
u8 hdr_len = 0;
int tso;
- if (0 == i40e_xmit_descriptor_count(skb, tx_ring))
+ if (0 == i40evf_xmit_descriptor_count(skb, tx_ring))
return NETDEV_TX_BUSY;
/* prepare the xmit flags */
- if (i40e_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags))
+ if (i40evf_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags))
goto out_drop;
/* obtain protocol of skb */
@@ -1937,7 +1927,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
else if (protocol == htons(ETH_P_IPV6))
tx_flags |= I40E_TX_FLAGS_IPV6;
- tso = i40e_tso(tx_ring, skb, tx_flags, protocol, &hdr_len,
+ tso = i40e_tso(tx_ring, skb, &hdr_len,
&cd_type_cmd_tso_mss, &cd_tunneling);
if (tso < 0)
@@ -1958,17 +1948,15 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
if (skb->ip_summed == CHECKSUM_PARTIAL) {
tx_flags |= I40E_TX_FLAGS_CSUM;
- i40e_tx_enable_csum(skb, tx_flags, &td_cmd, &td_offset,
+ i40e_tx_enable_csum(skb, &tx_flags, &td_cmd, &td_offset,
tx_ring, &cd_tunneling);
}
i40e_create_tx_ctx(tx_ring, cd_type_cmd_tso_mss,
cd_tunneling, cd_l2tag2);
- i40e_tx_map(tx_ring, skb, first, tx_flags, hdr_len,
- td_cmd, td_offset);
-
- i40e_maybe_stop_tx(tx_ring, DESC_NEEDED);
+ i40evf_tx_map(tx_ring, skb, first, tx_flags, hdr_len,
+ td_cmd, td_offset);
return NETDEV_TX_OK;
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h
index 1e49bb1fbac1..e7a34f899f2c 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h
@@ -138,6 +138,7 @@ enum i40e_dyn_idx_t {
#define I40E_TX_FLAGS_FCCRC (u32)(1 << 6)
#define I40E_TX_FLAGS_FSO (u32)(1 << 7)
#define I40E_TX_FLAGS_FD_SB (u32)(1 << 9)
+#define I40E_TX_FLAGS_VXLAN_TUNNEL (u32)(1 << 10)
#define I40E_TX_FLAGS_VLAN_MASK 0xffff0000
#define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000
#define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29
@@ -145,7 +146,6 @@ enum i40e_dyn_idx_t {
struct i40e_tx_buffer {
struct i40e_tx_desc *next_to_watch;
- unsigned long time_stamp;
union {
struct sk_buff *skb;
void *raw_buf;
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h
index ec9d83a93379..c463ec41579c 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h
@@ -1108,6 +1108,7 @@ struct i40e_hw_port_stats {
/* flow director stats */
u64 fd_atr_match;
u64 fd_sb_match;
+ u64 fd_atr_tunnel_match;
/* EEE LPI */
u32 tx_lpi_status;
u32 rx_lpi_status;
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index a0a9b1fcb5e8..f287186192bb 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -1836,31 +1836,19 @@ void igb_reinit_locked(struct igb_adapter *adapter)
*
* @adapter: adapter struct
**/
-static s32 igb_enable_mas(struct igb_adapter *adapter)
+static void igb_enable_mas(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
- u32 connsw;
- s32 ret_val = 0;
-
- connsw = rd32(E1000_CONNSW);
- if (!(hw->phy.media_type == e1000_media_type_copper))
- return ret_val;
+ u32 connsw = rd32(E1000_CONNSW);
/* configure for SerDes media detect */
- if (!(connsw & E1000_CONNSW_SERDESD)) {
+ if ((hw->phy.media_type == e1000_media_type_copper) &&
+ (!(connsw & E1000_CONNSW_SERDESD))) {
connsw |= E1000_CONNSW_ENRGSRC;
connsw |= E1000_CONNSW_AUTOSENSE_EN;
wr32(E1000_CONNSW, connsw);
wrfl();
- } else if (connsw & E1000_CONNSW_SERDESD) {
- /* already SerDes, no need to enable anything */
- return ret_val;
- } else {
- netdev_info(adapter->netdev,
- "MAS: Unable to configure feature, disabling..\n");
- adapter->flags &= ~IGB_FLAG_MAS_ENABLE;
}
- return ret_val;
}
void igb_reset(struct igb_adapter *adapter)
@@ -1980,10 +1968,9 @@ void igb_reset(struct igb_adapter *adapter)
adapter->ei.get_invariants(hw);
adapter->flags &= ~IGB_FLAG_MEDIA_RESET;
}
- if (adapter->flags & IGB_FLAG_MAS_ENABLE) {
- if (igb_enable_mas(adapter))
- dev_err(&pdev->dev,
- "Error enabling Media Auto Sense\n");
+ if ((mac->type == e1000_82575) &&
+ (adapter->flags & IGB_FLAG_MAS_ENABLE)) {
+ igb_enable_mas(adapter);
}
if (hw->mac.ops.init_hw(hw))
dev_err(&pdev->dev, "Hardware Error\n");
@@ -4989,6 +4976,7 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
struct igb_tx_buffer *first;
int tso;
u32 tx_flags = 0;
+ unsigned short f;
u16 count = TXD_USE_COUNT(skb_headlen(skb));
__be16 protocol = vlan_get_protocol(skb);
u8 hdr_len = 0;
@@ -4999,14 +4987,8 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
* + 1 desc for context descriptor,
* otherwise try next time
*/
- if (NETDEV_FRAG_PAGE_MAX_SIZE > IGB_MAX_DATA_PER_TXD) {
- unsigned short f;
-
- for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
- count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
- } else {
- count += skb_shinfo(skb)->nr_frags;
- }
+ for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+ count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
if (igb_maybe_stop_tx(tx_ring, count + 3)) {
/* this is a hard error */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 636f9e350162..ac3ac2a20386 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -643,6 +643,7 @@ struct ixgbe_adapter {
#define IXGBE_FLAG2_RSS_FIELD_IPV4_UDP (u32)(1 << 8)
#define IXGBE_FLAG2_RSS_FIELD_IPV6_UDP (u32)(1 << 9)
#define IXGBE_FLAG2_PTP_PPS_ENABLED (u32)(1 << 10)
+#define IXGBE_FLAG2_PHY_INTERRUPT (u32)(1 << 11)
/* Tx fast path data */
int num_tx_queues;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
index 824a7ab79ab6..65db69b862fb 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
@@ -1225,7 +1225,7 @@ static struct ixgbe_phy_operations phy_ops_82598 = {
.setup_link_speed = &ixgbe_setup_phy_link_speed_generic,
.read_i2c_sff8472 = &ixgbe_read_i2c_sff8472_82598,
.read_i2c_eeprom = &ixgbe_read_i2c_eeprom_82598,
- .check_overtemp = &ixgbe_tn_check_overtemp,
+ .check_overtemp = &ixgbe_tn_check_overtemp,
};
struct ixgbe_info ixgbe_82598_info = {
@@ -1234,4 +1234,5 @@ struct ixgbe_info ixgbe_82598_info = {
.mac_ops = &mac_ops_82598,
.eeprom_ops = &eeprom_ops_82598,
.phy_ops = &phy_ops_82598,
+ .mvals = ixgbe_mvals_8259X,
};
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
index e0c363948bf4..6b87d9634614 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
@@ -71,7 +71,7 @@ bool ixgbe_mng_enabled(struct ixgbe_hw *hw)
{
u32 fwsm, manc, factps;
- fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM);
+ fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM(hw));
if ((fwsm & IXGBE_FWSM_MODE_MASK) != IXGBE_FWSM_FW_MODE_PT)
return false;
@@ -79,7 +79,7 @@ bool ixgbe_mng_enabled(struct ixgbe_hw *hw)
if (!(manc & IXGBE_MANC_RCV_TCO_EN))
return false;
- factps = IXGBE_READ_REG(hw, IXGBE_FACTPS);
+ factps = IXGBE_READ_REG(hw, IXGBE_FACTPS(hw));
if (factps & IXGBE_FACTPS_MNGCG)
return false;
@@ -510,7 +510,7 @@ static void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw)
hw->eeprom.ops.read(hw, IXGBE_EEPROM_CTRL_2, &ee_ctrl_2);
/* Check to see if MNG FW could be enabled */
- fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM);
+ fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM(hw));
if (((fwsm & IXGBE_FWSM_MODE_MASK) != IXGBE_FWSM_FW_MODE_PT) &&
!hw->wol_enabled &&
@@ -2378,4 +2378,5 @@ struct ixgbe_info ixgbe_82599_info = {
.eeprom_ops = &eeprom_ops_82599,
.phy_ops = &phy_ops_82599,
.mbx_ops = &mbx_ops_generic,
+ .mvals = ixgbe_mvals_8259X,
};
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
index 06d8f3cfa099..4c1c26732b67 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -57,6 +57,11 @@ static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw,
u16 offset);
static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw);
+/* Base table for registers values that change by MAC */
+const u32 ixgbe_mvals_8259X[IXGBE_MVALS_IDX_LIMIT] = {
+ IXGBE_MVALS_INIT(8259X)
+};
+
/**
* ixgbe_device_supports_autoneg_fc - Check if phy supports autoneg flow
* control
@@ -91,6 +96,8 @@ bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw)
case IXGBE_DEV_ID_82599_T3_LOM:
case IXGBE_DEV_ID_X540T:
case IXGBE_DEV_ID_X540T1:
+ case IXGBE_DEV_ID_X550T:
+ case IXGBE_DEV_ID_X550EM_X_10G_T:
supported = true;
break;
default:
@@ -463,7 +470,7 @@ s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw)
}
}
- if (hw->mac.type == ixgbe_mac_X540) {
+ if (hw->mac.type == ixgbe_mac_X550 || hw->mac.type == ixgbe_mac_X540) {
if (hw->phy.id == 0)
hw->phy.ops.identify(hw);
hw->phy.ops.read_reg(hw, IXGBE_PCRC8ECL, MDIO_MMD_PCS, &i);
@@ -681,7 +688,7 @@ void ixgbe_set_lan_id_multi_port_pcie(struct ixgbe_hw *hw)
bus->lan_id = bus->func;
/* check for a port swap */
- reg = IXGBE_READ_REG(hw, IXGBE_FACTPS);
+ reg = IXGBE_READ_REG(hw, IXGBE_FACTPS(hw));
if (reg & IXGBE_FACTPS_LFS)
bus->func ^= 0x1;
}
@@ -799,7 +806,7 @@ s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw)
* Check for EEPROM present first.
* If not present leave as none
*/
- eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
if (eec & IXGBE_EEC_PRES) {
eeprom->type = ixgbe_eeprom_spi;
@@ -1283,14 +1290,14 @@ static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw)
if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) != 0)
return IXGBE_ERR_SWFW_SYNC;
- eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
/* Request EEPROM Access */
eec |= IXGBE_EEC_REQ;
- IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+ IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec);
for (i = 0; i < IXGBE_EEPROM_GRANT_ATTEMPTS; i++) {
- eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
if (eec & IXGBE_EEC_GNT)
break;
udelay(5);
@@ -1299,7 +1306,7 @@ static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw)
/* Release if grant not acquired */
if (!(eec & IXGBE_EEC_GNT)) {
eec &= ~IXGBE_EEC_REQ;
- IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+ IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec);
hw_dbg(hw, "Could not acquire EEPROM grant\n");
hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
@@ -1309,7 +1316,7 @@ static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw)
/* Setup EEPROM for Read/Write */
/* Clear CS and SK */
eec &= ~(IXGBE_EEC_CS | IXGBE_EEC_SK);
- IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+ IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec);
IXGBE_WRITE_FLUSH(hw);
udelay(1);
return 0;
@@ -1333,7 +1340,7 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw)
* If the SMBI bit is 0 when we read it, then the bit will be
* set and we have the semaphore
*/
- swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM(hw));
if (!(swsm & IXGBE_SWSM_SMBI))
break;
usleep_range(50, 100);
@@ -1353,7 +1360,7 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw)
* If the SMBI bit is 0 when we read it, then the bit will be
* set and we have the semaphore
*/
- swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM(hw));
if (swsm & IXGBE_SWSM_SMBI) {
hw_dbg(hw, "Software semaphore SMBI between device drivers not granted.\n");
return IXGBE_ERR_EEPROM;
@@ -1362,16 +1369,16 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw)
/* Now get the semaphore between SW/FW through the SWESMBI bit */
for (i = 0; i < timeout; i++) {
- swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM(hw));
/* Set the SW EEPROM semaphore bit to request access */
swsm |= IXGBE_SWSM_SWESMBI;
- IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm);
+ IXGBE_WRITE_REG(hw, IXGBE_SWSM(hw), swsm);
/* If we set the bit successfully then we got the
* semaphore.
*/
- swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM(hw));
if (swsm & IXGBE_SWSM_SWESMBI)
break;
@@ -1400,11 +1407,11 @@ static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw)
{
u32 swsm;
- swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM(hw));
/* Release both semaphores by writing 0 to the bits SWESMBI and SMBI */
swsm &= ~(IXGBE_SWSM_SWESMBI | IXGBE_SWSM_SMBI);
- IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm);
+ IXGBE_WRITE_REG(hw, IXGBE_SWSM(hw), swsm);
IXGBE_WRITE_FLUSH(hw);
}
@@ -1454,15 +1461,15 @@ static void ixgbe_standby_eeprom(struct ixgbe_hw *hw)
{
u32 eec;
- eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
/* Toggle CS to flush commands */
eec |= IXGBE_EEC_CS;
- IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+ IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec);
IXGBE_WRITE_FLUSH(hw);
udelay(1);
eec &= ~IXGBE_EEC_CS;
- IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+ IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec);
IXGBE_WRITE_FLUSH(hw);
udelay(1);
}
@@ -1480,7 +1487,7 @@ static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data,
u32 mask;
u32 i;
- eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
/*
* Mask is used to shift "count" bits of "data" out to the EEPROM
@@ -1501,7 +1508,7 @@ static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data,
else
eec &= ~IXGBE_EEC_DI;
- IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+ IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec);
IXGBE_WRITE_FLUSH(hw);
udelay(1);
@@ -1518,7 +1525,7 @@ static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data,
/* We leave the "DI" bit set to "0" when we leave this routine. */
eec &= ~IXGBE_EEC_DI;
- IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+ IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec);
IXGBE_WRITE_FLUSH(hw);
}
@@ -1539,7 +1546,7 @@ static u16 ixgbe_shift_in_eeprom_bits(struct ixgbe_hw *hw, u16 count)
* the value of the "DO" bit. During this "shifting in" process the
* "DI" bit should always be clear.
*/
- eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
eec &= ~(IXGBE_EEC_DO | IXGBE_EEC_DI);
@@ -1547,7 +1554,7 @@ static u16 ixgbe_shift_in_eeprom_bits(struct ixgbe_hw *hw, u16 count)
data = data << 1;
ixgbe_raise_eeprom_clk(hw, &eec);
- eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
eec &= ~(IXGBE_EEC_DI);
if (eec & IXGBE_EEC_DO)
@@ -1571,7 +1578,7 @@ static void ixgbe_raise_eeprom_clk(struct ixgbe_hw *hw, u32 *eec)
* (setting the SK bit), then delay
*/
*eec = *eec | IXGBE_EEC_SK;
- IXGBE_WRITE_REG(hw, IXGBE_EEC, *eec);
+ IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), *eec);
IXGBE_WRITE_FLUSH(hw);
udelay(1);
}
@@ -1588,7 +1595,7 @@ static void ixgbe_lower_eeprom_clk(struct ixgbe_hw *hw, u32 *eec)
* delay
*/
*eec = *eec & ~IXGBE_EEC_SK;
- IXGBE_WRITE_REG(hw, IXGBE_EEC, *eec);
+ IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), *eec);
IXGBE_WRITE_FLUSH(hw);
udelay(1);
}
@@ -1601,19 +1608,19 @@ static void ixgbe_release_eeprom(struct ixgbe_hw *hw)
{
u32 eec;
- eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
eec |= IXGBE_EEC_CS; /* Pull CS high */
eec &= ~IXGBE_EEC_SK; /* Lower SCK */
- IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+ IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec);
IXGBE_WRITE_FLUSH(hw);
udelay(1);
/* Stop requesting EEPROM access */
eec &= ~IXGBE_EEC_REQ;
- IXGBE_WRITE_REG(hw, IXGBE_EEC, eec);
+ IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec);
hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
index f21f8a165ec4..ec015fed8fa7 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
@@ -118,6 +118,8 @@ bool ixgbe_mng_enabled(struct ixgbe_hw *hw);
void ixgbe_set_rxpba_generic(struct ixgbe_hw *hw, int num_pb,
u32 headroom, int strategy);
+extern const u32 ixgbe_mvals_8259X[IXGBE_MVALS_IDX_LIMIT];
+
#define IXGBE_I2C_THERMAL_SENSOR_ADDR 0xF8
#define IXGBE_EMC_INTERNAL_DATA 0x00
#define IXGBE_EMC_INTERNAL_THERM_LIMIT 0x20
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index eafa9ec802ba..ec7b2324b77b 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -207,6 +207,7 @@ static int ixgbe_get_settings(struct net_device *netdev,
switch (adapter->hw.phy.type) {
case ixgbe_phy_tn:
case ixgbe_phy_aq:
+ case ixgbe_phy_x550em_ext_t:
case ixgbe_phy_cu_unknown:
ecmd->supported |= SUPPORTED_TP;
ecmd->advertising |= ADVERTISED_TP;
@@ -470,16 +471,16 @@ static void ixgbe_get_regs(struct net_device *netdev,
regs_buff[7] = IXGBE_READ_REG(hw, IXGBE_TCPTIMER);
/* NVM Register */
- regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_EEC);
+ regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
regs_buff[9] = IXGBE_READ_REG(hw, IXGBE_EERD);
- regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_FLA);
+ regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_FLA(hw));
regs_buff[11] = IXGBE_READ_REG(hw, IXGBE_EEMNGCTL);
regs_buff[12] = IXGBE_READ_REG(hw, IXGBE_EEMNGDATA);
regs_buff[13] = IXGBE_READ_REG(hw, IXGBE_FLMNGCTL);
regs_buff[14] = IXGBE_READ_REG(hw, IXGBE_FLMNGDATA);
regs_buff[15] = IXGBE_READ_REG(hw, IXGBE_FLMNGCNT);
regs_buff[16] = IXGBE_READ_REG(hw, IXGBE_FLOP);
- regs_buff[17] = IXGBE_READ_REG(hw, IXGBE_GRC);
+ regs_buff[17] = IXGBE_READ_REG(hw, IXGBE_GRC(hw));
/* Interrupt */
/* don't read EICR because it can clear interrupt causes, instead
@@ -2594,18 +2595,35 @@ static int ixgbe_add_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
struct ixgbe_hw *hw = &adapter->hw;
struct ixgbe_fdir_filter *input;
union ixgbe_atr_input mask;
+ u8 queue;
int err;
if (!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
return -EOPNOTSUPP;
- /*
- * Don't allow programming if the action is a queue greater than
- * the number of online Rx queues.
+ /* ring_cookie is a masked into a set of queues and ixgbe pools or
+ * we use the drop index.
*/
- if ((fsp->ring_cookie != RX_CLS_FLOW_DISC) &&
- (fsp->ring_cookie >= adapter->num_rx_queues))
- return -EINVAL;
+ if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {
+ queue = IXGBE_FDIR_DROP_QUEUE;
+ } else {
+ u32 ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
+ u8 vf = ethtool_get_flow_spec_ring_vf(fsp->ring_cookie);
+
+ if (!vf && (ring >= adapter->num_rx_queues))
+ return -EINVAL;
+ else if (vf &&
+ ((vf > adapter->num_vfs) ||
+ ring >= adapter->num_rx_queues_per_pool))
+ return -EINVAL;
+
+ /* Map the ring onto the absolute queue index */
+ if (!vf)
+ queue = adapter->rx_ring[ring]->reg_idx;
+ else
+ queue = ((vf - 1) *
+ adapter->num_rx_queues_per_pool) + ring;
+ }
/* Don't allow indexes to exist outside of available space */
if (fsp->location >= ((1024 << adapter->fdir_pballoc) - 2)) {
@@ -2683,10 +2701,7 @@ static int ixgbe_add_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
/* program filters to filter memory */
err = ixgbe_fdir_write_perfect_filter_82599(hw,
- &input->filter, input->sw_idx,
- (input->action == IXGBE_FDIR_DROP_QUEUE) ?
- IXGBE_FDIR_DROP_QUEUE :
- adapter->rx_ring[input->action]->reg_idx);
+ &input->filter, input->sw_idx, queue);
if (err)
goto err_out_w_lock;
@@ -3053,7 +3068,7 @@ static int ixgbe_get_module_info(struct net_device *dev,
{
struct ixgbe_adapter *adapter = netdev_priv(dev);
struct ixgbe_hw *hw = &adapter->hw;
- u32 status;
+ s32 status;
u8 sff8472_rev, addr_mode;
bool page_swap = false;
@@ -3061,14 +3076,14 @@ static int ixgbe_get_module_info(struct net_device *dev,
status = hw->phy.ops.read_i2c_eeprom(hw,
IXGBE_SFF_SFF_8472_COMP,
&sff8472_rev);
- if (status != 0)
+ if (status)
return -EIO;
/* addressing mode is not supported */
status = hw->phy.ops.read_i2c_eeprom(hw,
IXGBE_SFF_SFF_8472_SWAP,
&addr_mode);
- if (status != 0)
+ if (status)
return -EIO;
if (addr_mode & IXGBE_SFF_ADDRESSING_MODE) {
@@ -3095,7 +3110,7 @@ static int ixgbe_get_module_eeprom(struct net_device *dev,
{
struct ixgbe_adapter *adapter = netdev_priv(dev);
struct ixgbe_hw *hw = &adapter->hw;
- u32 status = IXGBE_ERR_PHY_ADDR_INVALID;
+ s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
u8 databyte = 0xFF;
int i = 0;
@@ -3112,7 +3127,7 @@ static int ixgbe_get_module_eeprom(struct net_device *dev,
else
status = hw->phy.ops.read_i2c_sff8472(hw, i, &databyte);
- if (status != 0)
+ if (status)
return -EIO;
data[i - ee->offset] = databyte;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 5be12a00e1f4..9aa6104e34ea 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -81,6 +81,8 @@ const char ixgbe_driver_version[] = DRV_VERSION;
static const char ixgbe_copyright[] =
"Copyright (c) 1999-2014 Intel Corporation.";
+static const char ixgbe_overheat_msg[] = "Network adapter has been stopped because it has over heated. Restart the computer. If the problem persists, power off the system and replace the adapter";
+
static const struct ixgbe_info *ixgbe_info_tbl[] = {
[board_82598] = &ixgbe_82598_info,
[board_82599] = &ixgbe_82599_info,
@@ -131,6 +133,7 @@ static const struct pci_device_id ixgbe_pci_tbl[] = {
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550T), board_X550},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_KX4), board_X550EM_x},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_KR), board_X550EM_x},
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_10G_T), board_X550EM_x},
/* required last entry */
{0, }
};
@@ -2366,7 +2369,7 @@ static void ixgbe_check_overtemp_subtask(struct ixgbe_adapter *adapter)
* - We may have missed the interrupt so always have to
* check if we got a LSC
*/
- if (!(eicr & IXGBE_EICR_GPI_SDP0) &&
+ if (!(eicr & IXGBE_EICR_GPI_SDP0_8259X) &&
!(eicr & IXGBE_EICR_LSC))
return;
@@ -2386,14 +2389,13 @@ static void ixgbe_check_overtemp_subtask(struct ixgbe_adapter *adapter)
break;
default:
- if (!(eicr & IXGBE_EICR_GPI_SDP0))
+ if (adapter->hw.mac.type >= ixgbe_mac_X540)
+ return;
+ if (!(eicr & IXGBE_EICR_GPI_SDP0(hw)))
return;
break;
}
- e_crit(drv,
- "Network adapter has been stopped because it has over heated. "
- "Restart the computer. If the problem persists, "
- "power off the system and replace the adapter\n");
+ e_crit(drv, "%s\n", ixgbe_overheat_msg);
adapter->interrupt_event = 0;
}
@@ -2403,15 +2405,17 @@ static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr)
struct ixgbe_hw *hw = &adapter->hw;
if ((adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) &&
- (eicr & IXGBE_EICR_GPI_SDP1)) {
+ (eicr & IXGBE_EICR_GPI_SDP1(hw))) {
e_crit(probe, "Fan has stopped, replace the adapter\n");
/* write to clear the interrupt */
- IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
+ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1(hw));
}
}
static void ixgbe_check_overtemp_event(struct ixgbe_adapter *adapter, u32 eicr)
{
+ struct ixgbe_hw *hw = &adapter->hw;
+
if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE))
return;
@@ -2421,7 +2425,8 @@ static void ixgbe_check_overtemp_event(struct ixgbe_adapter *adapter, u32 eicr)
* Need to check link state so complete overtemp check
* on service task
*/
- if (((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC)) &&
+ if (((eicr & IXGBE_EICR_GPI_SDP0(hw)) ||
+ (eicr & IXGBE_EICR_LSC)) &&
(!test_bit(__IXGBE_DOWN, &adapter->state))) {
adapter->interrupt_event = eicr;
adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT;
@@ -2437,28 +2442,46 @@ static void ixgbe_check_overtemp_event(struct ixgbe_adapter *adapter, u32 eicr)
return;
}
- e_crit(drv,
- "Network adapter has been stopped because it has over heated. "
- "Restart the computer. If the problem persists, "
- "power off the system and replace the adapter\n");
+ e_crit(drv, "%s\n", ixgbe_overheat_msg);
+}
+
+static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw)
+{
+ switch (hw->mac.type) {
+ case ixgbe_mac_82598EB:
+ if (hw->phy.type == ixgbe_phy_nl)
+ return true;
+ return false;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X550EM_x:
+ switch (hw->mac.ops.get_media_type(hw)) {
+ case ixgbe_media_type_fiber:
+ case ixgbe_media_type_fiber_qsfp:
+ return true;
+ default:
+ return false;
+ }
+ default:
+ return false;
+ }
}
static void ixgbe_check_sfp_event(struct ixgbe_adapter *adapter, u32 eicr)
{
struct ixgbe_hw *hw = &adapter->hw;
- if (eicr & IXGBE_EICR_GPI_SDP2) {
+ if (eicr & IXGBE_EICR_GPI_SDP2(hw)) {
/* Clear the interrupt */
- IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
+ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2(hw));
if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET;
ixgbe_service_event_schedule(adapter);
}
}
- if (eicr & IXGBE_EICR_GPI_SDP1) {
+ if (eicr & IXGBE_EICR_GPI_SDP1(hw)) {
/* Clear the interrupt */
- IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
+ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1(hw));
if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG;
ixgbe_service_event_schedule(adapter);
@@ -2543,6 +2566,7 @@ static inline void ixgbe_irq_disable_queues(struct ixgbe_adapter *adapter,
static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter, bool queues,
bool flush)
{
+ struct ixgbe_hw *hw = &adapter->hw;
u32 mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
/* don't reenable LSC while waiting for link */
@@ -2552,7 +2576,7 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter, bool queues,
if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
switch (adapter->hw.mac.type) {
case ixgbe_mac_82599EB:
- mask |= IXGBE_EIMS_GPI_SDP0;
+ mask |= IXGBE_EIMS_GPI_SDP0(hw);
break;
case ixgbe_mac_X540:
case ixgbe_mac_X550:
@@ -2563,15 +2587,17 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter, bool queues,
break;
}
if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
- mask |= IXGBE_EIMS_GPI_SDP1;
+ mask |= IXGBE_EIMS_GPI_SDP1(hw);
switch (adapter->hw.mac.type) {
case ixgbe_mac_82599EB:
- mask |= IXGBE_EIMS_GPI_SDP1;
- mask |= IXGBE_EIMS_GPI_SDP2;
+ mask |= IXGBE_EIMS_GPI_SDP1(hw);
+ mask |= IXGBE_EIMS_GPI_SDP2(hw);
/* fall through */
case ixgbe_mac_X540:
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
+ if (adapter->hw.phy.type == ixgbe_phy_x550em_ext_t)
+ mask |= IXGBE_EICR_GPI_SDP0_X540;
mask |= IXGBE_EIMS_ECC;
mask |= IXGBE_EIMS_MAILBOX;
break;
@@ -2626,6 +2652,13 @@ static irqreturn_t ixgbe_msix_other(int irq, void *data)
case ixgbe_mac_X540:
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
+ if (hw->phy.type == ixgbe_phy_x550em_ext_t &&
+ (eicr & IXGBE_EICR_GPI_SDP0_X540)) {
+ adapter->flags2 |= IXGBE_FLAG2_PHY_INTERRUPT;
+ ixgbe_service_event_schedule(adapter);
+ IXGBE_WRITE_REG(hw, IXGBE_EICR,
+ IXGBE_EICR_GPI_SDP0_X540);
+ }
if (eicr & IXGBE_EICR_ECC) {
e_info(link, "Received ECC Err, initiating reset\n");
adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
@@ -4703,32 +4736,6 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
ixgbe_configure_dfwd(adapter);
}
-static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw)
-{
- switch (hw->phy.type) {
- case ixgbe_phy_sfp_avago:
- case ixgbe_phy_sfp_ftl:
- case ixgbe_phy_sfp_intel:
- case ixgbe_phy_sfp_unknown:
- case ixgbe_phy_sfp_passive_tyco:
- case ixgbe_phy_sfp_passive_unknown:
- case ixgbe_phy_sfp_active_unknown:
- case ixgbe_phy_sfp_ftl_active:
- case ixgbe_phy_qsfp_passive_unknown:
- case ixgbe_phy_qsfp_active_unknown:
- case ixgbe_phy_qsfp_intel:
- case ixgbe_phy_qsfp_unknown:
- /* ixgbe_phy_none is set when no SFP module is present */
- case ixgbe_phy_none:
- return true;
- case ixgbe_phy_nl:
- if (hw->mac.type == ixgbe_mac_82598EB)
- return true;
- default:
- return false;
- }
-}
-
/**
* ixgbe_sfp_link_config - set up SFP+ link
* @adapter: pointer to private adapter struct
@@ -4757,7 +4764,7 @@ static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw)
{
u32 speed;
bool autoneg, link_up = false;
- u32 ret = IXGBE_ERR_LINK_SETUP;
+ int ret = IXGBE_ERR_LINK_SETUP;
if (hw->mac.ops.check_link)
ret = hw->mac.ops.check_link(hw, &speed, &link_up, false);
@@ -4833,7 +4840,7 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) {
switch (adapter->hw.mac.type) {
case ixgbe_mac_82599EB:
- gpie |= IXGBE_SDP0_GPIEN;
+ gpie |= IXGBE_SDP0_GPIEN_8259X;
break;
case ixgbe_mac_X540:
gpie |= IXGBE_EIMS_TS;
@@ -4845,11 +4852,11 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
/* Enable fan failure interrupt */
if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
- gpie |= IXGBE_SDP1_GPIEN;
+ gpie |= IXGBE_SDP1_GPIEN(hw);
if (hw->mac.type == ixgbe_mac_82599EB) {
- gpie |= IXGBE_SDP1_GPIEN;
- gpie |= IXGBE_SDP2_GPIEN;
+ gpie |= IXGBE_SDP1_GPIEN_8259X;
+ gpie |= IXGBE_SDP2_GPIEN_8259X;
}
IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
@@ -4873,6 +4880,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
if (hw->mac.ops.enable_tx_laser)
hw->mac.ops.enable_tx_laser(hw);
+ if (hw->phy.ops.set_phy_power)
+ hw->phy.ops.set_phy_power(hw, true);
+
smp_mb__before_atomic();
clear_bit(__IXGBE_DOWN, &adapter->state);
ixgbe_napi_enable_all(adapter);
@@ -4992,6 +5002,13 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
if (test_bit(__IXGBE_PTP_RUNNING, &adapter->state))
ixgbe_ptp_reset(adapter);
+
+ if (hw->phy.ops.set_phy_power) {
+ if (!netif_running(adapter->netdev) && !adapter->wol)
+ hw->phy.ops.set_phy_power(hw, false);
+ else
+ hw->phy.ops.set_phy_power(hw, true);
+ }
}
/**
@@ -5260,7 +5277,7 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter)
adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
break;
case ixgbe_mac_X540:
- fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM);
+ fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM(hw));
if (fwsm & IXGBE_FWSM_TS_ENABLED)
adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
break;
@@ -5672,6 +5689,7 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu)
static int ixgbe_open(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
int err, queues;
/* disallow open during test */
@@ -5729,6 +5747,8 @@ err_set_queues:
ixgbe_free_irq(adapter);
err_req_irq:
ixgbe_free_all_rx_resources(adapter);
+ if (hw->phy.ops.set_phy_power && !adapter->wol)
+ hw->phy.ops.set_phy_power(&adapter->hw, false);
err_setup_rx:
ixgbe_free_all_tx_resources(adapter);
err_setup_tx:
@@ -5889,6 +5909,8 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake)
}
*enable_wake = !!wufc;
+ if (hw->phy.ops.set_phy_power && !*enable_wake)
+ hw->phy.ops.set_phy_power(hw, false);
ixgbe_release_hw_control(adapter);
@@ -6718,6 +6740,26 @@ static void ixgbe_service_timer(unsigned long data)
ixgbe_service_event_schedule(adapter);
}
+static void ixgbe_phy_interrupt_subtask(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 status;
+
+ if (!(adapter->flags2 & IXGBE_FLAG2_PHY_INTERRUPT))
+ return;
+
+ adapter->flags2 &= ~IXGBE_FLAG2_PHY_INTERRUPT;
+
+ if (!hw->phy.ops.handle_lasi)
+ return;
+
+ status = hw->phy.ops.handle_lasi(&adapter->hw);
+ if (status != IXGBE_ERR_OVERTEMP)
+ return;
+
+ e_crit(drv, "%s\n", ixgbe_overheat_msg);
+}
+
static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter)
{
if (!(adapter->flags2 & IXGBE_FLAG2_RESET_REQUESTED))
@@ -6759,6 +6801,7 @@ static void ixgbe_service_task(struct work_struct *work)
return;
}
ixgbe_reset_subtask(adapter);
+ ixgbe_phy_interrupt_subtask(adapter);
ixgbe_sfp_detection_subtask(adapter);
ixgbe_sfp_link_config_subtask(adapter);
ixgbe_check_overtemp_subtask(adapter);
@@ -8022,7 +8065,7 @@ static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
return -EINVAL;
nla_for_each_nested(attr, br_spec, rem) {
- u32 status;
+ int status;
__u16 mode;
if (nla_type(attr) != IFLA_BRIDGE_MODE)
@@ -8052,7 +8095,8 @@ static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
return 0;
return ndo_dflt_bridge_getlink(skb, pid, seq, dev,
- adapter->bridge_mode, 0, 0, nlflags);
+ adapter->bridge_mode, 0, 0, nlflags,
+ filter_mask, NULL);
}
static void *ixgbe_fwd_add(struct net_device *pdev, struct net_device *vdev)
@@ -8291,6 +8335,10 @@ int ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id,
break;
case IXGBE_DEV_ID_X540T:
case IXGBE_DEV_ID_X540T1:
+ case IXGBE_DEV_ID_X550T:
+ case IXGBE_DEV_ID_X550EM_X_KX4:
+ case IXGBE_DEV_ID_X550EM_X_KR:
+ case IXGBE_DEV_ID_X550EM_X_10G_T:
/* check eeprom to see if enabled wol */
if ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0_1) ||
((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0) &&
@@ -8431,10 +8479,11 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Setup hw api */
memcpy(&hw->mac.ops, ii->mac_ops, sizeof(hw->mac.ops));
hw->mac.type = ii->mac;
+ hw->mvals = ii->mvals;
/* EEPROM */
memcpy(&hw->eeprom.ops, ii->eeprom_ops, sizeof(hw->eeprom.ops));
- eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
if (ixgbe_removed(hw->hw_addr)) {
err = -EIO;
goto err_ioremap;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
index 8a2be444113d..526a20bf7488 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
@@ -317,14 +317,14 @@ bool ixgbe_check_reset_blocked(struct ixgbe_hw *hw)
**/
static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw)
{
- u32 status;
+ s32 status;
u16 phy_id_high = 0;
u16 phy_id_low = 0;
status = hw->phy.ops.read_reg(hw, MDIO_DEVID1, MDIO_MMD_PMAPMD,
&phy_id_high);
- if (status == 0) {
+ if (!status) {
hw->phy.id = (u32)(phy_id_high << 16);
status = hw->phy.ops.read_reg(hw, MDIO_DEVID2, MDIO_MMD_PMAPMD,
&phy_id_low);
@@ -347,6 +347,7 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
case TN1010_PHY_ID:
phy_type = ixgbe_phy_tn;
break;
+ case X550_PHY_ID:
case X540_PHY_ID:
phy_type = ixgbe_phy_aq;
break;
@@ -356,6 +357,9 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
case ATH_PHY_ID:
phy_type = ixgbe_phy_nl;
break;
+ case X557_PHY_ID:
+ phy_type = ixgbe_phy_x550em_ext_t;
+ break;
default:
phy_type = ixgbe_phy_unknown;
break;
@@ -1348,6 +1352,9 @@ static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw)
return IXGBE_ERR_SFP_NOT_PRESENT;
}
+ /* LAN ID is needed for sfp_type determination */
+ hw->mac.ops.set_lan_id(hw);
+
status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER,
&identifier);
@@ -1361,9 +1368,6 @@ static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw)
hw->phy.id = identifier;
- /* LAN ID is needed for sfp_type determination */
- hw->mac.ops.set_lan_id(hw);
-
status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_10GBE_COMP,
&comp_codes_10g);
@@ -1793,7 +1797,7 @@ fail:
**/
static void ixgbe_i2c_start(struct ixgbe_hw *hw)
{
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+ u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
/* Start condition must begin with data and clock high */
ixgbe_set_i2c_data(hw, &i2cctl, 1);
@@ -1822,7 +1826,7 @@ static void ixgbe_i2c_start(struct ixgbe_hw *hw)
**/
static void ixgbe_i2c_stop(struct ixgbe_hw *hw)
{
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+ u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
/* Stop condition must begin with data low and clock high */
ixgbe_set_i2c_data(hw, &i2cctl, 0);
@@ -1880,9 +1884,9 @@ static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data)
}
/* Release SDA line (set high) */
- i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
- i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw);
- IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl);
+ i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
+ i2cctl |= IXGBE_I2C_DATA_OUT(hw);
+ IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl);
IXGBE_WRITE_FLUSH(hw);
return status;
@@ -1898,7 +1902,7 @@ static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
{
s32 status = 0;
u32 i = 0;
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+ u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
u32 timeout = 10;
bool ack = true;
@@ -1911,7 +1915,7 @@ static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
/* Poll for ACK. Note that ACK in I2C spec is
* transition from 1 to 0 */
for (i = 0; i < timeout; i++) {
- i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+ i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
ack = ixgbe_get_i2c_data(hw, &i2cctl);
udelay(1);
@@ -1941,14 +1945,14 @@ static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
**/
static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data)
{
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+ u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
ixgbe_raise_i2c_clk(hw, &i2cctl);
/* Minimum high period of clock is 4us */
udelay(IXGBE_I2C_T_HIGH);
- i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+ i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
*data = ixgbe_get_i2c_data(hw, &i2cctl);
ixgbe_lower_i2c_clk(hw, &i2cctl);
@@ -1969,7 +1973,7 @@ static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data)
static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data)
{
s32 status;
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+ u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
status = ixgbe_set_i2c_data(hw, &i2cctl, data);
if (status == 0) {
@@ -2005,14 +2009,14 @@ static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
u32 i2cctl_r = 0;
for (i = 0; i < timeout; i++) {
- *i2cctl |= IXGBE_I2C_CLK_OUT_BY_MAC(hw);
- IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
+ *i2cctl |= IXGBE_I2C_CLK_OUT(hw);
+ IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl);
IXGBE_WRITE_FLUSH(hw);
/* SCL rise time (1000ns) */
udelay(IXGBE_I2C_T_RISE);
- i2cctl_r = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
- if (i2cctl_r & IXGBE_I2C_CLK_IN_BY_MAC(hw))
+ i2cctl_r = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
+ if (i2cctl_r & IXGBE_I2C_CLK_IN(hw))
break;
}
}
@@ -2027,9 +2031,9 @@ static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
{
- *i2cctl &= ~IXGBE_I2C_CLK_OUT_BY_MAC(hw);
+ *i2cctl &= ~IXGBE_I2C_CLK_OUT(hw);
- IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
+ IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl);
IXGBE_WRITE_FLUSH(hw);
/* SCL fall time (300ns) */
@@ -2047,18 +2051,18 @@ static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
{
if (data)
- *i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw);
+ *i2cctl |= IXGBE_I2C_DATA_OUT(hw);
else
- *i2cctl &= ~IXGBE_I2C_DATA_OUT_BY_MAC(hw);
+ *i2cctl &= ~IXGBE_I2C_DATA_OUT(hw);
- IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
+ IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl);
IXGBE_WRITE_FLUSH(hw);
/* Data rise/fall (1000ns/300ns) and set-up time (250ns) */
udelay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA);
/* Verify data was set correctly */
- *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+ *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
if (data != ixgbe_get_i2c_data(hw, i2cctl)) {
hw_dbg(hw, "Error - I2C data was not set to %X.\n", data);
return IXGBE_ERR_I2C;
@@ -2076,7 +2080,7 @@ static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
**/
static bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl)
{
- if (*i2cctl & IXGBE_I2C_DATA_IN_BY_MAC(hw))
+ if (*i2cctl & IXGBE_I2C_DATA_IN(hw))
return true;
return false;
}
@@ -2090,7 +2094,7 @@ static bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl)
**/
static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw)
{
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+ u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
u32 i;
ixgbe_i2c_start(hw);
@@ -2137,3 +2141,36 @@ s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw)
return IXGBE_ERR_OVERTEMP;
}
+
+/** ixgbe_set_copper_phy_power - Control power for copper phy
+ * @hw: pointer to hardware structure
+ * @on: true for on, false for off
+ **/
+s32 ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on)
+{
+ u32 status;
+ u16 reg;
+
+ /* Bail if we don't have copper phy */
+ if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
+ return 0;
+
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg);
+ if (status)
+ return status;
+
+ if (on) {
+ reg &= ~IXGBE_MDIO_PHY_SET_LOW_POWER_MODE;
+ } else {
+ if (ixgbe_check_reset_blocked(hw))
+ return 0;
+ reg |= IXGBE_MDIO_PHY_SET_LOW_POWER_MODE;
+ }
+
+ status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ reg);
+ return status;
+}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
index 434643881287..e45988c4dad5 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
@@ -145,6 +145,7 @@ s32 ixgbe_get_phy_firmware_version_generic(struct ixgbe_hw *hw,
u16 *firmware_version);
s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw);
+s32 ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on);
s32 ixgbe_identify_module_generic(struct ixgbe_hw *hw);
s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw);
s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index dd6ba5916dfe..b6f424f3b1a8 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -91,14 +91,24 @@
#define IXGBE_DEV_ID_X550_VF 0x1565
#define IXGBE_DEV_ID_X550EM_X_VF 0x15A8
+#define IXGBE_CAT(r, m) IXGBE_##r##_##m
+
+#define IXGBE_BY_MAC(_hw, r) ((_hw)->mvals[IXGBE_CAT(r, IDX)])
+
/* General Registers */
#define IXGBE_CTRL 0x00000
#define IXGBE_STATUS 0x00008
#define IXGBE_CTRL_EXT 0x00018
#define IXGBE_ESDP 0x00020
#define IXGBE_EODSDP 0x00028
-#define IXGBE_I2CCTL_BY_MAC(_hw)((((_hw)->mac.type >= ixgbe_mac_X550) ? \
- 0x15F5C : 0x00028))
+
+#define IXGBE_I2CCTL_8259X 0x00028
+#define IXGBE_I2CCTL_X540 IXGBE_I2CCTL_8259X
+#define IXGBE_I2CCTL_X550 0x15F5C
+#define IXGBE_I2CCTL_X550EM_x IXGBE_I2CCTL_X550
+#define IXGBE_I2CCTL_X550EM_a IXGBE_I2CCTL_X550
+#define IXGBE_I2CCTL(_hw) IXGBE_BY_MAC((_hw), I2CCTL)
+
#define IXGBE_LEDCTL 0x00200
#define IXGBE_FRTIMER 0x00048
#define IXGBE_TCPTIMER 0x0004C
@@ -106,17 +116,39 @@
#define IXGBE_EXVET 0x05078
/* NVM Registers */
-#define IXGBE_EEC 0x10010
+#define IXGBE_EEC_8259X 0x10010
+#define IXGBE_EEC_X540 IXGBE_EEC_8259X
+#define IXGBE_EEC_X550 IXGBE_EEC_8259X
+#define IXGBE_EEC_X550EM_x IXGBE_EEC_8259X
+#define IXGBE_EEC_X550EM_a 0x15FF8
+#define IXGBE_EEC(_hw) IXGBE_BY_MAC((_hw), EEC)
#define IXGBE_EERD 0x10014
#define IXGBE_EEWR 0x10018
-#define IXGBE_FLA 0x1001C
+#define IXGBE_FLA_8259X 0x1001C
+#define IXGBE_FLA_X540 IXGBE_FLA_8259X
+#define IXGBE_FLA_X550 IXGBE_FLA_8259X
+#define IXGBE_FLA_X550EM_x IXGBE_FLA_8259X
+#define IXGBE_FLA_X550EM_a 0x15F6C
+#define IXGBE_FLA(_hw) IXGBE_BY_MAC((_hw), FLA)
#define IXGBE_EEMNGCTL 0x10110
#define IXGBE_EEMNGDATA 0x10114
#define IXGBE_FLMNGCTL 0x10118
#define IXGBE_FLMNGDATA 0x1011C
#define IXGBE_FLMNGCNT 0x10120
#define IXGBE_FLOP 0x1013C
-#define IXGBE_GRC 0x10200
+#define IXGBE_GRC_8259X 0x10200
+#define IXGBE_GRC_X540 IXGBE_GRC_8259X
+#define IXGBE_GRC_X550 IXGBE_GRC_8259X
+#define IXGBE_GRC_X550EM_x IXGBE_GRC_8259X
+#define IXGBE_GRC_X550EM_a 0x15F64
+#define IXGBE_GRC(_hw) IXGBE_BY_MAC((_hw), GRC)
+
+#define IXGBE_SRAMREL_8259X 0x10210
+#define IXGBE_SRAMREL_X540 IXGBE_SRAMREL_8259X
+#define IXGBE_SRAMREL_X550 IXGBE_SRAMREL_8259X
+#define IXGBE_SRAMREL_X550EM_x IXGBE_SRAMREL_8259X
+#define IXGBE_SRAMREL_X550EM_a 0x15F6C
+#define IXGBE_SRAMREL(_hw) IXGBE_BY_MAC((_hw), SRAMREL)
/* General Receive Control */
#define IXGBE_GRC_MNG 0x00000001 /* Manageability Enable */
@@ -126,14 +158,55 @@
#define IXGBE_VPDDIAG1 0x10208
/* I2CCTL Bit Masks */
-#define IXGBE_I2C_CLK_IN_BY_MAC(_hw)(((_hw)->mac.type) >= ixgbe_mac_X550 ? \
- 0x00004000 : 0x00000001)
-#define IXGBE_I2C_CLK_OUT_BY_MAC(_hw)(((_hw)->mac.type) >= ixgbe_mac_X550 ? \
- 0x00000200 : 0x00000002)
-#define IXGBE_I2C_DATA_IN_BY_MAC(_hw)(((_hw)->mac.type) >= ixgbe_mac_X550 ? \
- 0x00001000 : 0x00000004)
-#define IXGBE_I2C_DATA_OUT_BY_MAC(_hw)(((_hw)->mac.type) >= ixgbe_mac_X550 ? \
- 0x00000400 : 0x00000008)
+#define IXGBE_I2C_CLK_IN_8259X 0x00000001
+#define IXGBE_I2C_CLK_IN_X540 IXGBE_I2C_CLK_IN_8259X
+#define IXGBE_I2C_CLK_IN_X550 0x00004000
+#define IXGBE_I2C_CLK_IN_X550EM_x IXGBE_I2C_CLK_IN_X550
+#define IXGBE_I2C_CLK_IN_X550EM_a IXGBE_I2C_CLK_IN_X550
+#define IXGBE_I2C_CLK_IN(_hw) IXGBE_BY_MAC((_hw), I2C_CLK_IN)
+
+#define IXGBE_I2C_CLK_OUT_8259X 0x00000002
+#define IXGBE_I2C_CLK_OUT_X540 IXGBE_I2C_CLK_OUT_8259X
+#define IXGBE_I2C_CLK_OUT_X550 0x00000200
+#define IXGBE_I2C_CLK_OUT_X550EM_x IXGBE_I2C_CLK_OUT_X550
+#define IXGBE_I2C_CLK_OUT_X550EM_a IXGBE_I2C_CLK_OUT_X550
+#define IXGBE_I2C_CLK_OUT(_hw) IXGBE_BY_MAC((_hw), I2C_CLK_OUT)
+
+#define IXGBE_I2C_DATA_IN_8259X 0x00000004
+#define IXGBE_I2C_DATA_IN_X540 IXGBE_I2C_DATA_IN_8259X
+#define IXGBE_I2C_DATA_IN_X550 0x00001000
+#define IXGBE_I2C_DATA_IN_X550EM_x IXGBE_I2C_DATA_IN_X550
+#define IXGBE_I2C_DATA_IN_X550EM_a IXGBE_I2C_DATA_IN_X550
+#define IXGBE_I2C_DATA_IN(_hw) IXGBE_BY_MAC((_hw), I2C_DATA_IN)
+
+#define IXGBE_I2C_DATA_OUT_8259X 0x00000008
+#define IXGBE_I2C_DATA_OUT_X540 IXGBE_I2C_DATA_OUT_8259X
+#define IXGBE_I2C_DATA_OUT_X550 0x00000400
+#define IXGBE_I2C_DATA_OUT_X550EM_x IXGBE_I2C_DATA_OUT_X550
+#define IXGBE_I2C_DATA_OUT_X550EM_a IXGBE_I2C_DATA_OUT_X550
+#define IXGBE_I2C_DATA_OUT(_hw) IXGBE_BY_MAC((_hw), I2C_DATA_OUT)
+
+#define IXGBE_I2C_DATA_OE_N_EN_8259X 0
+#define IXGBE_I2C_DATA_OE_N_EN_X540 IXGBE_I2C_DATA_OE_N_EN_8259X
+#define IXGBE_I2C_DATA_OE_N_EN_X550 0x00000800
+#define IXGBE_I2C_DATA_OE_N_EN_X550EM_x IXGBE_I2C_DATA_OE_N_EN_X550
+#define IXGBE_I2C_DATA_OE_N_EN_X550EM_a IXGBE_I2C_DATA_OE_N_EN_X550
+#define IXGBE_I2C_DATA_OE_N_EN(_hw) IXGBE_BY_MAC((_hw), I2C_DATA_OE_N_EN)
+
+#define IXGBE_I2C_BB_EN_8259X 0
+#define IXGBE_I2C_BB_EN_X540 IXGBE_I2C_BB_EN_8259X
+#define IXGBE_I2C_BB_EN_X550 0x00000100
+#define IXGBE_I2C_BB_EN_X550EM_x IXGBE_I2C_BB_EN_X550
+#define IXGBE_I2C_BB_EN_X550EM_a IXGBE_I2C_BB_EN_X550
+#define IXGBE_I2C_BB_EN(_hw) IXGBE_BY_MAC((_hw), I2C_BB_EN)
+
+#define IXGBE_I2C_CLK_OE_N_EN_8259X 0
+#define IXGBE_I2C_CLK_OE_N_EN_X540 IXGBE_I2C_CLK_OE_N_EN_8259X
+#define IXGBE_I2C_CLK_OE_N_EN_X550 0x00002000
+#define IXGBE_I2C_CLK_OE_N_EN_X550EM_x IXGBE_I2C_CLK_OE_N_EN_X550
+#define IXGBE_I2C_CLK_OE_N_EN_X550EM_a IXGBE_I2C_CLK_OE_N_EN_X550
+#define IXGBE_I2C_CLK_OE_N_EN(_hw) IXGBE_BY_MAC((_hw), I2C_CLK_OE_N_EN)
+
#define IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT 500
#define IXGBE_I2C_THERMAL_SENSOR_ADDR 0xF8
@@ -835,15 +908,36 @@ struct ixgbe_thermal_sensor_data {
#define IXGBE_GSCN_1 0x11024
#define IXGBE_GSCN_2 0x11028
#define IXGBE_GSCN_3 0x1102C
-#define IXGBE_FACTPS 0x10150
+#define IXGBE_FACTPS_8259X 0x10150
+#define IXGBE_FACTPS_X540 IXGBE_FACTPS_8259X
+#define IXGBE_FACTPS_X550 IXGBE_FACTPS_8259X
+#define IXGBE_FACTPS_X550EM_x IXGBE_FACTPS_8259X
+#define IXGBE_FACTPS_X550EM_a 0x15FEC
+#define IXGBE_FACTPS(_hw) IXGBE_BY_MAC((_hw), FACTPS)
+
#define IXGBE_PCIEANACTL 0x11040
-#define IXGBE_SWSM 0x10140
-#define IXGBE_FWSM 0x10148
+#define IXGBE_SWSM_8259X 0x10140
+#define IXGBE_SWSM_X540 IXGBE_SWSM_8259X
+#define IXGBE_SWSM_X550 IXGBE_SWSM_8259X
+#define IXGBE_SWSM_X550EM_x IXGBE_SWSM_8259X
+#define IXGBE_SWSM_X550EM_a 0x15F70
+#define IXGBE_SWSM(_hw) IXGBE_BY_MAC((_hw), SWSM)
+#define IXGBE_FWSM_8259X 0x10148
+#define IXGBE_FWSM_X540 IXGBE_FWSM_8259X
+#define IXGBE_FWSM_X550 IXGBE_FWSM_8259X
+#define IXGBE_FWSM_X550EM_x IXGBE_FWSM_8259X
+#define IXGBE_FWSM_X550EM_a 0x15F74
+#define IXGBE_FWSM(_hw) IXGBE_BY_MAC((_hw), FWSM)
#define IXGBE_GSSR 0x10160
#define IXGBE_MREVID 0x11064
#define IXGBE_DCA_ID 0x11070
#define IXGBE_DCA_CTRL 0x11074
-#define IXGBE_SWFW_SYNC IXGBE_GSSR
+#define IXGBE_SWFW_SYNC_8259X IXGBE_GSSR
+#define IXGBE_SWFW_SYNC_X540 IXGBE_SWFW_SYNC_8259X
+#define IXGBE_SWFW_SYNC_X550 IXGBE_SWFW_SYNC_8259X
+#define IXGBE_SWFW_SYNC_X550EM_x IXGBE_SWFW_SYNC_8259X
+#define IXGBE_SWFW_SYNC_X550EM_a 0x15F78
+#define IXGBE_SWFW_SYNC(_hw) IXGBE_BY_MAC((_hw), SWFW_SYNC)
/* PCIe registers 82599-specific */
#define IXGBE_GCR_EXT 0x11050
@@ -855,14 +949,21 @@ struct ixgbe_thermal_sensor_data {
#define IXGBE_PHYDAT_82599 0x11044
#define IXGBE_PHYCTL_82599 0x11048
#define IXGBE_PBACLR_82599 0x11068
-#define IXGBE_CIAA_82599 0x11088
-#define IXGBE_CIAD_82599 0x1108C
-#define IXGBE_CIAA_X550 0x11508
-#define IXGBE_CIAD_X550 0x11510
-#define IXGBE_CIAA_BY_MAC(_hw) ((((_hw)->mac.type >= ixgbe_mac_X550) ? \
- IXGBE_CIAA_X550 : IXGBE_CIAA_82599))
-#define IXGBE_CIAD_BY_MAC(_hw) ((((_hw)->mac.type >= ixgbe_mac_X550) ? \
- IXGBE_CIAD_X550 : IXGBE_CIAD_82599))
+
+#define IXGBE_CIAA_8259X 0x11088
+#define IXGBE_CIAA_X540 IXGBE_CIAA_8259X
+#define IXGBE_CIAA_X550 0x11508
+#define IXGBE_CIAA_X550EM_x IXGBE_CIAA_X550
+#define IXGBE_CIAA_X550EM_a IXGBE_CIAA_X550
+#define IXGBE_CIAA(_hw) IXGBE_BY_MAC((_hw), CIAA)
+
+#define IXGBE_CIAD_8259X 0x1108C
+#define IXGBE_CIAD_X540 IXGBE_CIAD_8259X
+#define IXGBE_CIAD_X550 0x11510
+#define IXGBE_CIAD_X550EM_x IXGBE_CIAD_X550
+#define IXGBE_CIAD_X550EM_a IXGBE_CIAD_X550
+#define IXGBE_CIAD(_hw) IXGBE_BY_MAC((_hw), CIAD)
+
#define IXGBE_PICAUSE 0x110B0
#define IXGBE_PIENA 0x110B8
#define IXGBE_CDQ_MBR_82599 0x110B4
@@ -1204,18 +1305,37 @@ struct ixgbe_thermal_sensor_data {
#define IXGBE_MDIO_AUTO_NEG_CONTROL 0x0 /* AUTO_NEG Control Reg */
#define IXGBE_MDIO_AUTO_NEG_STATUS 0x1 /* AUTO_NEG Status Reg */
#define IXGBE_MDIO_AUTO_NEG_VENDOR_STAT 0xC800 /* AUTO_NEG Vendor Status Reg */
+#define IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM2 0xCC01 /* AUTO_NEG Vendor Tx Reg */
+#define IXGBE_MDIO_AUTO_NEG_VEN_LSC 0x1 /* AUTO_NEG Vendor Tx LSC */
#define IXGBE_MDIO_AUTO_NEG_ADVT 0x10 /* AUTO_NEG Advt Reg */
#define IXGBE_MDIO_AUTO_NEG_LP 0x13 /* AUTO_NEG LP Status Reg */
#define IXGBE_MDIO_AUTO_NEG_EEE_ADVT 0x3C /* AUTO_NEG EEE Advt Reg */
+#define IXGBE_MDIO_PHY_SET_LOW_POWER_MODE 0x0800 /* Set low power mode */
+
#define IXGBE_MDIO_TX_VENDOR_ALARMS_3 0xCC02 /* Vendor Alarms 3 Reg */
#define IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK 0x3 /* PHY Reset Complete Mask */
#define IXGBE_MDIO_GLOBAL_RES_PR_10 0xC479 /* Global Resv Provisioning 10 Reg */
#define IXGBE_MDIO_POWER_UP_STALL 0x8000 /* Power Up Stall */
+#define IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK 0xFF00 /* int std mask */
+#define IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG 0xFC00 /* chip std int flag */
+#define IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK 0xFF01 /* int chip-wide mask */
+#define IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_FLAG 0xFC01 /* int chip-wide mask */
+#define IXGBE_MDIO_GLOBAL_ALARM_1 0xCC00 /* Global alarm 1 */
+#define IXGBE_MDIO_GLOBAL_ALM_1_HI_TMP_FAIL 0x4000 /* high temp failure */
+#define IXGBE_MDIO_GLOBAL_INT_MASK 0xD400 /* Global int mask */
+/* autoneg vendor alarm int enable */
+#define IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN 0x1000
+#define IXGBE_MDIO_GLOBAL_ALARM_1_INT 0x4 /* int in Global alarm 1 */
+#define IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN 0x1 /* vendor alarm int enable */
+#define IXGBE_MDIO_GLOBAL_STD_ALM2_INT 0x200 /* vendor alarm2 int mask */
+#define IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN 0x4000 /* int high temp enable */
#define IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR 0xC30A /* PHY_XS SDA/SCL Addr Reg */
#define IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA 0xC30B /* PHY_XS SDA/SCL Data Reg */
#define IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT 0xC30C /* PHY_XS SDA/SCL Stat Reg */
+#define IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK 0xD401 /* PHY TX Vendor LASI */
+#define IXGBE_MDIO_PMA_TX_VEN_LASI_INT_EN 0x1 /* PHY TX Vendor LASI enable */
#define IXGBE_MDIO_PMD_STD_TX_DISABLE_CNTR 0x9 /* Standard Tx Dis Reg */
#define IXGBE_MDIO_PMD_GLOBAL_TX_DISABLE 0x0001 /* PMD Global Tx Dis */
@@ -1233,6 +1353,8 @@ struct ixgbe_thermal_sensor_data {
#define TN1010_PHY_ID 0x00A19410
#define TNX_FW_REV 0xB
#define X540_PHY_ID 0x01540200
+#define X550_PHY_ID 0x01540220
+#define X557_PHY_ID 0x01540240
#define QT2022_PHY_ID 0x0043A400
#define ATH_PHY_ID 0x03429050
#define AQ_FW_REV 0x20
@@ -1253,9 +1375,25 @@ struct ixgbe_thermal_sensor_data {
#define IXGBE_CONTROL_SOL_NL 0x0000
/* General purpose Interrupt Enable */
-#define IXGBE_SDP0_GPIEN 0x00000001 /* SDP0 */
-#define IXGBE_SDP1_GPIEN 0x00000002 /* SDP1 */
-#define IXGBE_SDP2_GPIEN 0x00000004 /* SDP2 */
+#define IXGBE_SDP0_GPIEN_8259X 0x00000001 /* SDP0 */
+#define IXGBE_SDP1_GPIEN_8259X 0x00000002 /* SDP1 */
+#define IXGBE_SDP2_GPIEN_8259X 0x00000004 /* SDP2 */
+#define IXGBE_SDP0_GPIEN_X540 0x00000002 /* SDP0 on X540 and X550 */
+#define IXGBE_SDP1_GPIEN_X540 0x00000004 /* SDP1 on X540 and X550 */
+#define IXGBE_SDP2_GPIEN_X540 0x00000008 /* SDP2 on X540 and X550 */
+#define IXGBE_SDP0_GPIEN_X550 IXGBE_SDP0_GPIEN_X540
+#define IXGBE_SDP1_GPIEN_X550 IXGBE_SDP1_GPIEN_X540
+#define IXGBE_SDP2_GPIEN_X550 IXGBE_SDP2_GPIEN_X540
+#define IXGBE_SDP0_GPIEN_X550EM_x IXGBE_SDP0_GPIEN_X540
+#define IXGBE_SDP1_GPIEN_X550EM_x IXGBE_SDP1_GPIEN_X540
+#define IXGBE_SDP2_GPIEN_X550EM_x IXGBE_SDP2_GPIEN_X540
+#define IXGBE_SDP0_GPIEN_X550EM_a IXGBE_SDP0_GPIEN_X540
+#define IXGBE_SDP1_GPIEN_X550EM_a IXGBE_SDP1_GPIEN_X540
+#define IXGBE_SDP2_GPIEN_X550EM_a IXGBE_SDP2_GPIEN_X540
+#define IXGBE_SDP0_GPIEN(_hw) IXGBE_BY_MAC((_hw), SDP0_GPIEN)
+#define IXGBE_SDP1_GPIEN(_hw) IXGBE_BY_MAC((_hw), SDP1_GPIEN)
+#define IXGBE_SDP2_GPIEN(_hw) IXGBE_BY_MAC((_hw), SDP2_GPIEN)
+
#define IXGBE_GPIE_MSIX_MODE 0x00000010 /* MSI-X mode */
#define IXGBE_GPIE_OCD 0x00000020 /* Other Clear Disable */
#define IXGBE_GPIE_EIMEN 0x00000040 /* Immediate Interrupt Enable */
@@ -1417,9 +1555,25 @@ enum {
#define IXGBE_EICR_MNG 0x00400000 /* Manageability Event Interrupt */
#define IXGBE_EICR_TS 0x00800000 /* Thermal Sensor Event */
#define IXGBE_EICR_TIMESYNC 0x01000000 /* Timesync Event */
-#define IXGBE_EICR_GPI_SDP0 0x01000000 /* Gen Purpose Interrupt on SDP0 */
-#define IXGBE_EICR_GPI_SDP1 0x02000000 /* Gen Purpose Interrupt on SDP1 */
-#define IXGBE_EICR_GPI_SDP2 0x04000000 /* Gen Purpose Interrupt on SDP2 */
+#define IXGBE_EICR_GPI_SDP0_8259X 0x01000000 /* Gen Purpose INT on SDP0 */
+#define IXGBE_EICR_GPI_SDP1_8259X 0x02000000 /* Gen Purpose INT on SDP1 */
+#define IXGBE_EICR_GPI_SDP2_8259X 0x04000000 /* Gen Purpose INT on SDP2 */
+#define IXGBE_EICR_GPI_SDP0_X540 0x02000000
+#define IXGBE_EICR_GPI_SDP1_X540 0x04000000
+#define IXGBE_EICR_GPI_SDP2_X540 0x08000000
+#define IXGBE_EICR_GPI_SDP0_X550 IXGBE_EICR_GPI_SDP0_X540
+#define IXGBE_EICR_GPI_SDP1_X550 IXGBE_EICR_GPI_SDP1_X540
+#define IXGBE_EICR_GPI_SDP2_X550 IXGBE_EICR_GPI_SDP2_X540
+#define IXGBE_EICR_GPI_SDP0_X550EM_x IXGBE_EICR_GPI_SDP0_X540
+#define IXGBE_EICR_GPI_SDP1_X550EM_x IXGBE_EICR_GPI_SDP1_X540
+#define IXGBE_EICR_GPI_SDP2_X550EM_x IXGBE_EICR_GPI_SDP2_X540
+#define IXGBE_EICR_GPI_SDP0_X550EM_a IXGBE_EICR_GPI_SDP0_X540
+#define IXGBE_EICR_GPI_SDP1_X550EM_a IXGBE_EICR_GPI_SDP1_X540
+#define IXGBE_EICR_GPI_SDP2_X550EM_a IXGBE_EICR_GPI_SDP2_X540
+#define IXGBE_EICR_GPI_SDP0(_hw) IXGBE_BY_MAC((_hw), EICR_GPI_SDP0)
+#define IXGBE_EICR_GPI_SDP1(_hw) IXGBE_BY_MAC((_hw), EICR_GPI_SDP1)
+#define IXGBE_EICR_GPI_SDP2(_hw) IXGBE_BY_MAC((_hw), EICR_GPI_SDP2)
+
#define IXGBE_EICR_ECC 0x10000000 /* ECC Error */
#define IXGBE_EICR_PBUR 0x10000000 /* Packet Buffer Handler Error */
#define IXGBE_EICR_DHER 0x20000000 /* Descriptor Handler Error */
@@ -1435,9 +1589,9 @@ enum {
#define IXGBE_EICS_LSC IXGBE_EICR_LSC /* Link Status Change */
#define IXGBE_EICS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */
#define IXGBE_EICS_TIMESYNC IXGBE_EICR_TIMESYNC /* Timesync Event */
-#define IXGBE_EICS_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* SDP0 Gen Purpose Int */
-#define IXGBE_EICS_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* SDP1 Gen Purpose Int */
-#define IXGBE_EICS_GPI_SDP2 IXGBE_EICR_GPI_SDP2 /* SDP2 Gen Purpose Int */
+#define IXGBE_EICS_GPI_SDP0(_hw) IXGBE_EICR_GPI_SDP0(_hw)
+#define IXGBE_EICS_GPI_SDP1(_hw) IXGBE_EICR_GPI_SDP1(_hw)
+#define IXGBE_EICS_GPI_SDP2(_hw) IXGBE_EICR_GPI_SDP2(_hw)
#define IXGBE_EICS_ECC IXGBE_EICR_ECC /* ECC Error */
#define IXGBE_EICS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Err */
#define IXGBE_EICS_DHER IXGBE_EICR_DHER /* Desc Handler Error */
@@ -1454,9 +1608,9 @@ enum {
#define IXGBE_EIMS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */
#define IXGBE_EIMS_TS IXGBE_EICR_TS /* Thermel Sensor Event */
#define IXGBE_EIMS_TIMESYNC IXGBE_EICR_TIMESYNC /* Timesync Event */
-#define IXGBE_EIMS_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* SDP0 Gen Purpose Int */
-#define IXGBE_EIMS_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* SDP1 Gen Purpose Int */
-#define IXGBE_EIMS_GPI_SDP2 IXGBE_EICR_GPI_SDP2 /* SDP2 Gen Purpose Int */
+#define IXGBE_EIMS_GPI_SDP0(_hw) IXGBE_EICR_GPI_SDP0(_hw)
+#define IXGBE_EIMS_GPI_SDP1(_hw) IXGBE_EICR_GPI_SDP1(_hw)
+#define IXGBE_EIMS_GPI_SDP2(_hw) IXGBE_EICR_GPI_SDP2(_hw)
#define IXGBE_EIMS_ECC IXGBE_EICR_ECC /* ECC Error */
#define IXGBE_EIMS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Err */
#define IXGBE_EIMS_DHER IXGBE_EICR_DHER /* Descr Handler Error */
@@ -1472,9 +1626,9 @@ enum {
#define IXGBE_EIMC_LSC IXGBE_EICR_LSC /* Link Status Change */
#define IXGBE_EIMC_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */
#define IXGBE_EIMC_TIMESYNC IXGBE_EICR_TIMESYNC /* Timesync Event */
-#define IXGBE_EIMC_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* SDP0 Gen Purpose Int */
-#define IXGBE_EIMC_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* SDP1 Gen Purpose Int */
-#define IXGBE_EIMC_GPI_SDP2 IXGBE_EICR_GPI_SDP2 /* SDP2 Gen Purpose Int */
+#define IXGBE_EIMC_GPI_SDP0(_hw) IXGBE_EICR_GPI_SDP0(_hw)
+#define IXGBE_EIMC_GPI_SDP1(_hw) IXGBE_EICR_GPI_SDP1(_hw)
+#define IXGBE_EIMC_GPI_SDP2(_hw) IXGBE_EICR_GPI_SDP2(_hw)
#define IXGBE_EIMC_ECC IXGBE_EICR_ECC /* ECC Error */
#define IXGBE_EIMC_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Err */
#define IXGBE_EIMC_DHER IXGBE_EICR_DHER /* Desc Handler Err */
@@ -2741,6 +2895,37 @@ union ixgbe_atr_hash_dword {
__be32 dword;
};
+#define IXGBE_MVALS_INIT(m) \
+ IXGBE_CAT(EEC, m), \
+ IXGBE_CAT(FLA, m), \
+ IXGBE_CAT(GRC, m), \
+ IXGBE_CAT(SRAMREL, m), \
+ IXGBE_CAT(FACTPS, m), \
+ IXGBE_CAT(SWSM, m), \
+ IXGBE_CAT(SWFW_SYNC, m), \
+ IXGBE_CAT(FWSM, m), \
+ IXGBE_CAT(SDP0_GPIEN, m), \
+ IXGBE_CAT(SDP1_GPIEN, m), \
+ IXGBE_CAT(SDP2_GPIEN, m), \
+ IXGBE_CAT(EICR_GPI_SDP0, m), \
+ IXGBE_CAT(EICR_GPI_SDP1, m), \
+ IXGBE_CAT(EICR_GPI_SDP2, m), \
+ IXGBE_CAT(CIAA, m), \
+ IXGBE_CAT(CIAD, m), \
+ IXGBE_CAT(I2C_CLK_IN, m), \
+ IXGBE_CAT(I2C_CLK_OUT, m), \
+ IXGBE_CAT(I2C_DATA_IN, m), \
+ IXGBE_CAT(I2C_DATA_OUT, m), \
+ IXGBE_CAT(I2C_DATA_OE_N_EN, m), \
+ IXGBE_CAT(I2C_BB_EN, m), \
+ IXGBE_CAT(I2C_CLK_OE_N_EN, m), \
+ IXGBE_CAT(I2CCTL, m)
+
+enum ixgbe_mvals {
+ IXGBE_MVALS_INIT(IDX),
+ IXGBE_MVALS_IDX_LIMIT
+};
+
enum ixgbe_eeprom_type {
ixgbe_eeprom_uninitialized = 0,
ixgbe_eeprom_spi,
@@ -3112,6 +3297,8 @@ struct ixgbe_phy_operations {
s32 (*read_i2c_combined)(struct ixgbe_hw *, u8 addr, u16 reg, u16 *val);
s32 (*write_i2c_combined)(struct ixgbe_hw *, u8 addr, u16 reg, u16 val);
s32 (*check_overtemp)(struct ixgbe_hw *);
+ s32 (*set_phy_power)(struct ixgbe_hw *, bool on);
+ s32 (*handle_lasi)(struct ixgbe_hw *hw);
};
struct ixgbe_eeprom_info {
@@ -3173,6 +3360,7 @@ struct ixgbe_phy_info {
bool multispeed_fiber;
bool reset_if_overtemp;
bool qsfp_shared_i2c_bus;
+ u32 nw_mng_if_sel;
};
#include "ixgbe_mbx.h"
@@ -3216,6 +3404,7 @@ struct ixgbe_hw {
struct ixgbe_eeprom_info eeprom;
struct ixgbe_bus_info bus;
struct ixgbe_mbx_info mbx;
+ const u32 *mvals;
u16 device_id;
u16 vendor_id;
u16 subsystem_device_id;
@@ -3234,6 +3423,7 @@ struct ixgbe_info {
struct ixgbe_eeprom_operations *eeprom_ops;
struct ixgbe_phy_operations *phy_ops;
struct ixgbe_mbx_operations *mbx_ops;
+ const u32 *mvals;
};
@@ -3339,4 +3529,6 @@ struct ixgbe_info {
#define IXGBE_SB_IOSF_TARGET_KX4_PCS0 2
#define IXGBE_SB_IOSF_TARGET_KX4_PCS1 3
+#define IXGBE_NW_MNG_IF_SEL 0x00011178
+#define IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE BIT(24)
#endif /* _IXGBE_TYPE_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
index f5f948d08b43..032a5870abd1 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
@@ -202,7 +202,7 @@ s32 ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw)
eeprom->semaphore_delay = 10;
eeprom->type = ixgbe_flash;
- eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >>
IXGBE_EEC_SIZE_SHIFT);
eeprom->word_size = 1 << (eeprom_size +
@@ -504,8 +504,8 @@ static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw)
return status;
}
- flup = IXGBE_READ_REG(hw, IXGBE_EEC) | IXGBE_EEC_FLUP;
- IXGBE_WRITE_REG(hw, IXGBE_EEC, flup);
+ flup = IXGBE_READ_REG(hw, IXGBE_EEC(hw)) | IXGBE_EEC_FLUP;
+ IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), flup);
status = ixgbe_poll_flash_update_done_X540(hw);
if (status == 0)
@@ -514,11 +514,11 @@ static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw)
hw_dbg(hw, "Flash update time out\n");
if (hw->revision_id == 0) {
- flup = IXGBE_READ_REG(hw, IXGBE_EEC);
+ flup = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
if (flup & IXGBE_EEC_SEC1VAL) {
flup |= IXGBE_EEC_FLUP;
- IXGBE_WRITE_REG(hw, IXGBE_EEC, flup);
+ IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), flup);
}
status = ixgbe_poll_flash_update_done_X540(hw);
@@ -544,7 +544,7 @@ static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw)
u32 reg;
for (i = 0; i < IXGBE_FLUDONE_ATTEMPTS; i++) {
- reg = IXGBE_READ_REG(hw, IXGBE_EEC);
+ reg = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
if (reg & IXGBE_EEC_FLUDONE)
return 0;
udelay(5);
@@ -580,10 +580,10 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
if (ixgbe_get_swfw_sync_semaphore(hw))
return IXGBE_ERR_SWFW_SYNC;
- swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC);
+ swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC(hw));
if (!(swfw_sync & (fwmask | swmask | hwmask))) {
swfw_sync |= swmask;
- IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swfw_sync);
+ IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC(hw), swfw_sync);
ixgbe_release_swfw_sync_semaphore(hw);
break;
} else {
@@ -605,13 +605,13 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
* corresponding FW/HW bits in the SW_FW_SYNC register.
*/
if (i >= timeout) {
- swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC);
+ swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC(hw));
if (swfw_sync & (fwmask | hwmask)) {
if (ixgbe_get_swfw_sync_semaphore(hw))
return IXGBE_ERR_SWFW_SYNC;
swfw_sync |= swmask;
- IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swfw_sync);
+ IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC(hw), swfw_sync);
ixgbe_release_swfw_sync_semaphore(hw);
}
}
@@ -635,9 +635,9 @@ void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
ixgbe_get_swfw_sync_semaphore(hw);
- swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC);
+ swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC(hw));
swfw_sync &= ~swmask;
- IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swfw_sync);
+ IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC(hw), swfw_sync);
ixgbe_release_swfw_sync_semaphore(hw);
usleep_range(5000, 10000);
@@ -660,7 +660,7 @@ static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw)
/* If the SMBI bit is 0 when we read it, then the bit will be
* set and we have the semaphore
*/
- swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM(hw));
if (!(swsm & IXGBE_SWSM_SMBI))
break;
usleep_range(50, 100);
@@ -674,7 +674,7 @@ static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw)
/* Now get the semaphore between SW/FW through the REGSMP bit */
for (i = 0; i < timeout; i++) {
- swsm = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC);
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC(hw));
if (!(swsm & IXGBE_SWFW_REGSMP))
return 0;
@@ -696,13 +696,13 @@ static void ixgbe_release_swfw_sync_semaphore(struct ixgbe_hw *hw)
/* Release both semaphores by writing 0 to the bits REGSMP and SMBI */
- swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
- swsm &= ~IXGBE_SWSM_SMBI;
- IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm);
-
- swsm = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC);
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC(hw));
swsm &= ~IXGBE_SWFW_REGSMP;
- IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swsm);
+ IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC(hw), swsm);
+
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM(hw));
+ swsm &= ~IXGBE_SWSM_SMBI;
+ IXGBE_WRITE_REG(hw, IXGBE_SWSM(hw), swsm);
IXGBE_WRITE_FLUSH(hw);
}
@@ -850,9 +850,14 @@ static struct ixgbe_phy_operations phy_ops_X540 = {
.read_i2c_eeprom = &ixgbe_read_i2c_eeprom_generic,
.write_i2c_eeprom = &ixgbe_write_i2c_eeprom_generic,
.check_overtemp = &ixgbe_tn_check_overtemp,
+ .set_phy_power = &ixgbe_set_copper_phy_power,
.get_firmware_version = &ixgbe_get_phy_firmware_version_generic,
};
+static const u32 ixgbe_mvals_X540[IXGBE_MVALS_IDX_LIMIT] = {
+ IXGBE_MVALS_INIT(X540)
+};
+
struct ixgbe_info ixgbe_X540_info = {
.mac = ixgbe_mac_X540,
.get_invariants = &ixgbe_get_invariants_X540,
@@ -860,4 +865,5 @@ struct ixgbe_info ixgbe_X540_info = {
.eeprom_ops = &eeprom_ops_X540,
.phy_ops = &phy_ops_X540,
.mbx_ops = &mbx_ops_generic,
+ .mvals = ixgbe_mvals_X540,
};
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
index cf5cf819a6b8..7581da13e92a 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
@@ -1,7 +1,7 @@
/*******************************************************************************
*
* Intel 10 Gigabit PCI Express Linux driver
- * Copyright(c) 1999 - 2014 Intel Corporation.
+ * Copyright(c) 1999 - 2015 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -26,6 +26,22 @@
#include "ixgbe_common.h"
#include "ixgbe_phy.h"
+/** ixgbe_setup_mux_ctl - Setup ESDP register for I2C mux control
+ * @hw: pointer to hardware structure
+ **/
+static void ixgbe_setup_mux_ctl(struct ixgbe_hw *hw)
+{
+ u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
+
+ if (hw->bus.lan_id) {
+ esdp &= ~(IXGBE_ESDP_SDP1_NATIVE | IXGBE_ESDP_SDP1);
+ esdp |= IXGBE_ESDP_SDP1_DIR;
+ }
+ esdp &= ~(IXGBE_ESDP_SDP0_NATIVE | IXGBE_ESDP_SDP0_DIR);
+ IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
+ IXGBE_WRITE_FLUSH(hw);
+}
+
/** ixgbe_identify_phy_x550em - Get PHY type based on device id
* @hw: pointer to hardware structure
*
@@ -33,18 +49,11 @@
*/
static s32 ixgbe_identify_phy_x550em(struct ixgbe_hw *hw)
{
- u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
-
switch (hw->device_id) {
case IXGBE_DEV_ID_X550EM_X_SFP:
/* set up for CS4227 usage */
hw->phy.phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
- if (hw->bus.lan_id) {
- esdp &= ~(IXGBE_ESDP_SDP1_NATIVE | IXGBE_ESDP_SDP1);
- esdp |= IXGBE_ESDP_SDP1_DIR;
- }
- esdp &= ~(IXGBE_ESDP_SDP0_NATIVE | IXGBE_ESDP_SDP0_DIR);
- IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
+ ixgbe_setup_mux_ctl(hw);
return ixgbe_identify_module_generic(hw);
case IXGBE_DEV_ID_X550EM_X_KX4:
@@ -90,7 +99,7 @@ static s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw)
eeprom->semaphore_delay = 10;
eeprom->type = ixgbe_flash;
- eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >>
IXGBE_EEC_SIZE_SHIFT);
eeprom->word_size = 1 << (eeprom_size +
@@ -103,6 +112,39 @@ static s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw)
return 0;
}
+/**
+ * ixgbe_iosf_wait - Wait for IOSF command completion
+ * @hw: pointer to hardware structure
+ * @ctrl: pointer to location to receive final IOSF control value
+ *
+ * Return: failing status on timeout
+ *
+ * Note: ctrl can be NULL if the IOSF control register value is not needed
+ */
+static s32 ixgbe_iosf_wait(struct ixgbe_hw *hw, u32 *ctrl)
+{
+ u32 i, command;
+
+ /* Check every 10 usec to see if the address cycle completed.
+ * The SB IOSF BUSY bit will clear when the operation is
+ * complete.
+ */
+ for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
+ command = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL);
+ if (!(command & IXGBE_SB_IOSF_CTRL_BUSY))
+ break;
+ usleep_range(10, 20);
+ }
+ if (ctrl)
+ *ctrl = command;
+ if (i == IXGBE_MDIO_COMMAND_TIMEOUT) {
+ hw_dbg(hw, "IOSF wait timed out\n");
+ return IXGBE_ERR_PHY;
+ }
+
+ return 0;
+}
+
/** ixgbe_read_iosf_sb_reg_x550 - Writes a value to specified register of the
* IOSF device
* @hw: pointer to hardware structure
@@ -113,7 +155,17 @@ static s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw)
static s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
u32 device_type, u32 *data)
{
- u32 i, command, error;
+ u32 gssr = IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_PHY0_SM;
+ u32 command, error;
+ s32 ret;
+
+ ret = hw->mac.ops.acquire_swfw_sync(hw, gssr);
+ if (ret)
+ return ret;
+
+ ret = ixgbe_iosf_wait(hw, NULL);
+ if (ret)
+ goto out;
command = ((reg_addr << IXGBE_SB_IOSF_CTRL_ADDR_SHIFT) |
(device_type << IXGBE_SB_IOSF_CTRL_TARGET_SELECT_SHIFT));
@@ -121,17 +173,7 @@ static s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
/* Write IOSF control register */
IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL, command);
- /* Check every 10 usec to see if the address cycle completed.
- * The SB IOSF BUSY bit will clear when the operation is
- * complete
- */
- for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
- usleep_range(10, 20);
-
- command = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL);
- if ((command & IXGBE_SB_IOSF_CTRL_BUSY) == 0)
- break;
- }
+ ret = ixgbe_iosf_wait(hw, &command);
if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
@@ -140,14 +182,12 @@ static s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
return IXGBE_ERR_PHY;
}
- if (i == IXGBE_MDIO_COMMAND_TIMEOUT) {
- hw_dbg(hw, "Read timed out\n");
- return IXGBE_ERR_PHY;
- }
-
- *data = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_DATA);
+ if (!ret)
+ *data = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_DATA);
- return 0;
+out:
+ hw->mac.ops.release_swfw_sync(hw, gssr);
+ return ret;
}
/** ixgbe_read_ee_hostif_data_X550 - Read EEPROM word using a host interface
@@ -673,6 +713,249 @@ static s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
return status;
}
+/** ixgbe_write_iosf_sb_reg_x550 - Writes a value to specified register of the
+ * IOSF device
+ *
+ * @hw: pointer to hardware structure
+ * @reg_addr: 32 bit PHY register to write
+ * @device_type: 3 bit device type
+ * @data: Data to write to the register
+ **/
+static s32 ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u32 data)
+{
+ u32 gssr = IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_PHY0_SM;
+ u32 command, error;
+ s32 ret;
+
+ ret = hw->mac.ops.acquire_swfw_sync(hw, gssr);
+ if (ret)
+ return ret;
+
+ ret = ixgbe_iosf_wait(hw, NULL);
+ if (ret)
+ goto out;
+
+ command = ((reg_addr << IXGBE_SB_IOSF_CTRL_ADDR_SHIFT) |
+ (device_type << IXGBE_SB_IOSF_CTRL_TARGET_SELECT_SHIFT));
+
+ /* Write IOSF control register */
+ IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL, command);
+
+ /* Write IOSF data register */
+ IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_DATA, data);
+
+ ret = ixgbe_iosf_wait(hw, &command);
+
+ if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
+ error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
+ IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
+ hw_dbg(hw, "Failed to write, error %x\n", error);
+ return IXGBE_ERR_PHY;
+ }
+
+out:
+ hw->mac.ops.release_swfw_sync(hw, gssr);
+ return ret;
+}
+
+/** ixgbe_setup_ixfi_x550em - Configure the KR PHY for iXFI mode.
+ * @hw: pointer to hardware structure
+ * @speed: the link speed to force
+ *
+ * Configures the integrated KR PHY to use iXFI mode. Used to connect an
+ * internal and external PHY at a specific speed, without autonegotiation.
+ **/
+static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
+{
+ s32 status;
+ u32 reg_val;
+
+ /* Disable AN and force speed to 10G Serial. */
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status)
+ return status;
+
+ reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
+ reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK;
+
+ /* Select forced link speed for internal PHY. */
+ switch (*speed) {
+ case IXGBE_LINK_SPEED_10GB_FULL:
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G;
+ break;
+ case IXGBE_LINK_SPEED_1GB_FULL:
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G;
+ break;
+ default:
+ /* Other link speeds are not supported by internal KR PHY. */
+ return IXGBE_ERR_LINK_SETUP;
+ }
+
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ if (status)
+ return status;
+
+ /* Disable training protocol FSM. */
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status)
+ return status;
+
+ reg_val |= IXGBE_KRM_RX_TRN_LINKUP_CTRL_CONV_WO_PROTOCOL;
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ if (status)
+ return status;
+
+ /* Disable Flex from training TXFFE. */
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status)
+ return status;
+
+ reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN;
+ reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN;
+ reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN;
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ if (status)
+ return status;
+
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status)
+ return status;
+
+ reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN;
+ reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN;
+ reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN;
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ if (status)
+ return status;
+
+ /* Enable override for coefficients. */
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status)
+ return status;
+
+ reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_OVRRD_EN;
+ reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CZERO_EN;
+ reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CPLUS1_OVRRD_EN;
+ reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CMINUS1_OVRRD_EN;
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ if (status)
+ return status;
+
+ /* Toggle port SW reset by AN reset. */
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status)
+ return status;
+
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART;
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+
+ return status;
+}
+
+/**
+ * ixgbe_setup_mac_link_t_X550em - Sets the auto advertised link speed
+ * @hw: pointer to hardware structure
+ * @speed: new link speed
+ * @autoneg_wait_to_complete: true when waiting for completion is needed
+ *
+ * Setup internal/external PHY link speed based on link speed, then set
+ * external PHY auto advertised link speed.
+ *
+ * Returns error status for any failure
+ **/
+static s32 ixgbe_setup_mac_link_t_X550em(struct ixgbe_hw *hw,
+ ixgbe_link_speed speed,
+ bool autoneg_wait)
+{
+ s32 status;
+ ixgbe_link_speed force_speed;
+
+ /* Setup internal/external PHY link speed to iXFI (10G), unless
+ * only 1G is auto advertised then setup KX link.
+ */
+ if (speed & IXGBE_LINK_SPEED_10GB_FULL)
+ force_speed = IXGBE_LINK_SPEED_10GB_FULL;
+ else
+ force_speed = IXGBE_LINK_SPEED_1GB_FULL;
+
+ /* If internal link mode is XFI, then setup XFI internal link. */
+ if (!(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
+ status = ixgbe_setup_ixfi_x550em(hw, &force_speed);
+
+ if (status)
+ return status;
+ }
+
+ return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait);
+}
+
+/** ixgbe_check_link_t_X550em - Determine link and speed status
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @link_up: true when link is up
+ * @link_up_wait_to_complete: bool used to wait for link up or not
+ *
+ * Check that both the MAC and X557 external PHY have link.
+ **/
+static s32 ixgbe_check_link_t_X550em(struct ixgbe_hw *hw,
+ ixgbe_link_speed *speed,
+ bool *link_up,
+ bool link_up_wait_to_complete)
+{
+ u32 status;
+ u16 autoneg_status;
+
+ if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
+ return IXGBE_ERR_CONFIG;
+
+ status = ixgbe_check_mac_link_generic(hw, speed, link_up,
+ link_up_wait_to_complete);
+
+ /* If check link fails or MAC link is not up, then return */
+ if (status || !(*link_up))
+ return status;
+
+ /* MAC link is up, so check external PHY link.
+ * Read this twice back to back to indicate current status.
+ */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_status);
+ if (status)
+ return status;
+
+ /* If external PHY link is not up, then indicate link not up */
+ if (!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS))
+ *link_up = false;
+
+ return 0;
+}
+
/** ixgbe_init_mac_link_ops_X550em - init mac link function pointers
* @hw: pointer to hardware structure
**/
@@ -680,13 +963,21 @@ static void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw)
{
struct ixgbe_mac_info *mac = &hw->mac;
- /* CS4227 does not support autoneg, so disable the laser control
- * functions for SFP+ fiber
- */
- if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) {
+ switch (mac->ops.get_media_type(hw)) {
+ case ixgbe_media_type_fiber:
+ /* CS4227 does not support autoneg, so disable the laser control
+ * functions for SFP+ fiber
+ */
mac->ops.disable_tx_laser = NULL;
mac->ops.enable_tx_laser = NULL;
mac->ops.flap_tx_laser = NULL;
+ break;
+ case ixgbe_media_type_copper:
+ mac->ops.setup_link = ixgbe_setup_mac_link_t_X550em;
+ mac->ops.check_link = ixgbe_check_link_t_X550em;
+ break;
+ default:
+ break;
}
}
@@ -778,169 +1069,221 @@ static s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
return 0;
}
-/** ixgbe_write_iosf_sb_reg_x550 - Writes a value to specified register of the
- * IOSF device
+/**
+ * ixgbe_get_lasi_ext_t_x550em - Determime external Base T PHY interrupt cause
+ * @hw: pointer to hardware structure
+ * @lsc: pointer to boolean flag which indicates whether external Base T
+ * PHY interrupt is lsc
*
- * @hw: pointer to hardware structure
- * @reg_addr: 32 bit PHY register to write
- * @device_type: 3 bit device type
- * @data: Data to write to the register
+ * Determime if external Base T PHY interrupt cause is high temperature
+ * failure alarm or link status change.
+ *
+ * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
+ * failure alarm, else return PHY access status.
**/
-static s32 ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
- u32 device_type, u32 data)
+static s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc)
{
- u32 i, command, error;
+ u32 status;
+ u16 reg;
- command = ((reg_addr << IXGBE_SB_IOSF_CTRL_ADDR_SHIFT) |
- (device_type << IXGBE_SB_IOSF_CTRL_TARGET_SELECT_SHIFT));
+ *lsc = false;
- /* Write IOSF control register */
- IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL, command);
+ /* Vendor alarm triggered */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg);
- /* Write IOSF data register */
- IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_DATA, data);
+ if (status || !(reg & IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN))
+ return status;
- /* Check every 10 usec to see if the address cycle completed.
- * The SB IOSF BUSY bit will clear when the operation is
- * complete
- */
- for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
- usleep_range(10, 20);
+ /* Vendor Auto-Neg alarm triggered or Global alarm 1 triggered */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_FLAG,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg);
- command = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL);
- if ((command & IXGBE_SB_IOSF_CTRL_BUSY) == 0)
- break;
- }
+ if (status || !(reg & (IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN |
+ IXGBE_MDIO_GLOBAL_ALARM_1_INT)))
+ return status;
- if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
- error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
- IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
- hw_dbg(hw, "Failed to write, error %x\n", error);
- return IXGBE_ERR_PHY;
- }
+ /* High temperature failure alarm triggered */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_ALARM_1,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg);
- if (i == IXGBE_MDIO_COMMAND_TIMEOUT) {
- hw_dbg(hw, "Write timed out\n");
- return IXGBE_ERR_PHY;
+ if (status)
+ return status;
+
+ /* If high temperature failure, then return over temp error and exit */
+ if (reg & IXGBE_MDIO_GLOBAL_ALM_1_HI_TMP_FAIL) {
+ /* power down the PHY in case the PHY FW didn't already */
+ ixgbe_set_copper_phy_power(hw, false);
+ return IXGBE_ERR_OVERTEMP;
}
+ /* Vendor alarm 2 triggered */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &reg);
+
+ if (status || !(reg & IXGBE_MDIO_GLOBAL_STD_ALM2_INT))
+ return status;
+
+ /* link connect/disconnect event occurred */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM2,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &reg);
+
+ if (status)
+ return status;
+
+ /* Indicate LSC */
+ if (reg & IXGBE_MDIO_AUTO_NEG_VEN_LSC)
+ *lsc = true;
+
return 0;
}
-/** ixgbe_setup_ixfi_x550em - Configure the KR PHY for iXFI mode.
- * @hw: pointer to hardware structure
- * @speed: the link speed to force
+/**
+ * ixgbe_enable_lasi_ext_t_x550em - Enable external Base T PHY interrupts
+ * @hw: pointer to hardware structure
*
- * Configures the integrated KR PHY to use iXFI mode. Used to connect an
- * internal and external PHY at a specific speed, without autonegotiation.
+ * Enable link status change and temperature failure alarm for the external
+ * Base T PHY
+ *
+ * Returns PHY access status
**/
-static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
+static s32 ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw)
{
- s32 status;
- u32 reg_val;
+ u32 status;
+ u16 reg;
+ bool lsc;
- /* Disable AN and force speed to 10G Serial. */
- status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
- IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ /* Clear interrupt flags */
+ status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
+
+ /* Enable link status change alarm */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &reg);
if (status)
return status;
- reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
- reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK;
+ reg |= IXGBE_MDIO_PMA_TX_VEN_LASI_INT_EN;
- /* Select forced link speed for internal PHY. */
- switch (*speed) {
- case IXGBE_LINK_SPEED_10GB_FULL:
- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G;
- break;
- case IXGBE_LINK_SPEED_1GB_FULL:
- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G;
- break;
- default:
- /* Other link speeds are not supported by internal KR PHY. */
- return IXGBE_ERR_LINK_SETUP;
- }
-
- status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
- IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, reg);
if (status)
return status;
- /* Disable training protocol FSM. */
- status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
- IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ /* Enables high temperature failure alarm */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg);
if (status)
return status;
- reg_val |= IXGBE_KRM_RX_TRN_LINKUP_CTRL_CONV_WO_PROTOCOL;
- status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
- IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
- if (status)
- return status;
+ reg |= IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN;
- /* Disable Flex from training TXFFE. */
- status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id),
- IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ reg);
if (status)
return status;
- reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN;
- reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN;
- reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN;
- status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id),
- IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ /* Enable vendor Auto-Neg alarm and Global Interrupt Mask 1 alarm */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg);
if (status)
return status;
- status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id),
- IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
- if (status)
- return status;
+ reg |= (IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN |
+ IXGBE_MDIO_GLOBAL_ALARM_1_INT);
- reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN;
- reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN;
- reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN;
- status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id),
- IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ reg);
if (status)
return status;
- /* Enable override for coefficients. */
- status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id),
- IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ /* Enable chip-wide vendor alarm */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg);
if (status)
return status;
- reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_OVRRD_EN;
- reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CZERO_EN;
- reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CPLUS1_OVRRD_EN;
- reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CMINUS1_OVRRD_EN;
- status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id),
- IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ reg |= IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN;
+
+ status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ reg);
+
+ return status;
+}
+
+/**
+ * ixgbe_handle_lasi_ext_t_x550em - Handle external Base T PHY interrupt
+ * @hw: pointer to hardware structure
+ *
+ * Handle external Base T PHY interrupt. If high temperature
+ * failure alarm then return error, else if link status change
+ * then setup internal/external PHY link
+ *
+ * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
+ * failure alarm, else return PHY access status.
+ **/
+static s32 ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw)
+{
+ struct ixgbe_phy_info *phy = &hw->phy;
+ bool lsc;
+ u32 status;
+
+ status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
if (status)
return status;
- /* Toggle port SW reset by AN reset. */
+ if (lsc)
+ return phy->ops.setup_internal_link(hw);
+
+ return 0;
+}
+
+/**
+ * ixgbe_setup_kr_speed_x550em - Configure the KR PHY for link speed.
+ * @hw: pointer to hardware structure
+ * @speed: link speed
+ *
+ * Configures the integrated KR PHY.
+ **/
+static s32 ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *hw,
+ ixgbe_link_speed speed)
+{
+ s32 status;
+ u32 reg_val;
+
status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
- IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
if (status)
return status;
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
+ reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_FEC_REQ |
+ IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_FEC);
+ reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR |
+ IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX);
+
+ /* Advertise 10G support. */
+ if (speed & IXGBE_LINK_SPEED_10GB_FULL)
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR;
+
+ /* Advertise 1G support. */
+ if (speed & IXGBE_LINK_SPEED_1GB_FULL)
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX;
+
+ /* Restart auto-negotiation. */
reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART;
status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
- IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
return status;
}
@@ -990,85 +1333,82 @@ static s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw)
**/
static s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw)
{
- s32 status;
- u32 reg_val;
+ return ixgbe_setup_kr_speed_x550em(hw, hw->phy.autoneg_advertised);
+}
- status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
- IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
- if (status)
- return status;
+/** ixgbe_ext_phy_t_x550em_get_link - Get ext phy link status
+ * @hw: address of hardware structure
+ * @link_up: address of boolean to indicate link status
+ *
+ * Returns error code if unable to get link status.
+ **/
+static s32 ixgbe_ext_phy_t_x550em_get_link(struct ixgbe_hw *hw, bool *link_up)
+{
+ u32 ret;
+ u16 autoneg_status;
- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_FEC_REQ;
- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_FEC;
- reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR |
- IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX);
+ *link_up = false;
- /* Advertise 10G support. */
- if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR;
+ /* read this twice back to back to indicate current status */
+ ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_status);
+ if (ret)
+ return ret;
- /* Advertise 1G support. */
- if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX;
+ ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_status);
+ if (ret)
+ return ret;
- /* Restart auto-negotiation. */
- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART;
- status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
- IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ *link_up = !!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS);
- return status;
+ return 0;
}
-/** ixgbe_setup_internal_phy_x550em - Configure integrated KR PHY
+/** ixgbe_setup_internal_phy_t_x550em - Configure KR PHY to X557 link
* @hw: point to hardware structure
*
- * Configures the integrated KR PHY to talk to the external PHY. The base
- * driver will call this function when it gets notification via interrupt from
- * the external PHY. This function forces the internal PHY into iXFI mode at
- * the correct speed.
+ * Configures the link between the integrated KR PHY and the external X557 PHY
+ * The driver will call this function when it gets a link status change
+ * interrupt from the X557 PHY. This function configures the link speed
+ * between the PHYs to match the link speed of the BASE-T link.
*
- * A return of a non-zero value indicates an error, and the base driver should
- * not report link up.
+ * A return of a non-zero value indicates an error, and the base driver should
+ * not report link up.
**/
-static s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw)
+static s32 ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw)
{
- u32 status;
- u16 lasi, autoneg_status, speed;
ixgbe_link_speed force_speed;
+ bool link_up;
+ u32 status;
+ u16 speed;
+
+ if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
+ return IXGBE_ERR_CONFIG;
- /* Verify that the external link status has changed */
- status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_XENPAK_LASI_STATUS,
- IXGBE_MDIO_PMA_PMD_DEV_TYPE, &lasi);
+ /* If link is not up, then there is no setup necessary so return */
+ status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
if (status)
return status;
- /* If there was no change in link status, we can just exit */
- if (!(lasi & IXGBE_XENPAK_LASI_LINK_STATUS_ALARM))
+ if (!link_up)
return 0;
- /* we read this twice back to back to indicate current status */
- status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT,
IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
- &autoneg_status);
+ &speed);
if (status)
return status;
- status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
- IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
- &autoneg_status);
+ /* If link is not still up, then no setup is necessary so return */
+ status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
if (status)
return status;
- /* If link is not up return an error indicating treat link as down */
- if (!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS))
- return IXGBE_ERR_INVALID_LINK_SETTINGS;
-
- status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT,
- IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
- &speed);
+ if (!link_up)
+ return 0;
/* clear everything but the speed and duplex bits */
speed &= IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_MASK;
@@ -1088,6 +1428,22 @@ static s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw)
return ixgbe_setup_ixfi_x550em(hw, &force_speed);
}
+/** ixgbe_reset_phy_t_X550em - Performs X557 PHY reset and enables LASI
+ * @hw: pointer to hardware structure
+ **/
+static s32 ixgbe_reset_phy_t_X550em(struct ixgbe_hw *hw)
+{
+ s32 status;
+
+ status = ixgbe_reset_phy_generic(hw);
+
+ if (status)
+ return status;
+
+ /* Configure Link Status Alarm and Temperature Threshold interrupts */
+ return ixgbe_enable_lasi_ext_t_x550em(hw);
+}
+
/** ixgbe_init_phy_ops_X550em - PHY/SFP specific init
* @hw: pointer to hardware structure
*
@@ -1098,25 +1454,32 @@ static s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw)
static s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
{
struct ixgbe_phy_info *phy = &hw->phy;
+ ixgbe_link_speed speed;
s32 ret_val;
- u32 esdp;
- if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) {
- esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
- phy->phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
+ hw->mac.ops.set_lan_id(hw);
- if (hw->bus.lan_id) {
- esdp &= ~(IXGBE_ESDP_SDP1_NATIVE | IXGBE_ESDP_SDP1);
- esdp |= IXGBE_ESDP_SDP1_DIR;
+ if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) {
+ phy->phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
+ ixgbe_setup_mux_ctl(hw);
+
+ /* Save NW management interface connected on board. This is used
+ * to determine internal PHY mode.
+ */
+ phy->nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL);
+
+ /* If internal PHY mode is KR, then initialize KR link */
+ if (phy->nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE) {
+ speed = IXGBE_LINK_SPEED_10GB_FULL |
+ IXGBE_LINK_SPEED_1GB_FULL;
+ ret_val = ixgbe_setup_kr_speed_x550em(hw, speed);
}
- esdp &= ~(IXGBE_ESDP_SDP0_NATIVE | IXGBE_ESDP_SDP0_DIR);
- IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
}
/* Identify the PHY or SFP module */
ret_val = phy->ops.identify(hw);
- /* Setup function pointers based on detected SFP module and speeds */
+ /* Setup function pointers based on detected hardware */
ixgbe_init_mac_link_ops_X550em(hw);
if (phy->sfp_type != ixgbe_sfp_type_unknown)
phy->ops.reset = NULL;
@@ -1134,11 +1497,30 @@ static s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
phy->ops.write_reg = ixgbe_write_phy_reg_x550em;
break;
case ixgbe_phy_x550em_ext_t:
- phy->ops.setup_internal_link = ixgbe_setup_internal_phy_x550em;
+ /* Save NW management interface connected on board. This is used
+ * to determine internal PHY mode
+ */
+ phy->nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL);
+
+ /* If internal link mode is XFI, then setup iXFI internal link,
+ * else setup KR now.
+ */
+ if (!(phy->nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
+ phy->ops.setup_internal_link =
+ ixgbe_setup_internal_phy_t_x550em;
+ } else {
+ speed = IXGBE_LINK_SPEED_10GB_FULL |
+ IXGBE_LINK_SPEED_1GB_FULL;
+ ret_val = ixgbe_setup_kr_speed_x550em(hw, speed);
+ }
+
+ phy->ops.handle_lasi = ixgbe_handle_lasi_ext_t_x550em;
+ phy->ops.reset = ixgbe_reset_phy_t_X550em;
break;
default:
break;
}
+
return ret_val;
}
@@ -1177,67 +1559,37 @@ static enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw)
**/
static s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw)
{
- u32 status;
+ s32 status;
u16 reg;
- u32 retries = 2;
-
- do {
- /* decrement retries counter and exit if we hit 0 */
- if (retries < 1) {
- hw_dbg(hw, "External PHY not yet finished resetting.");
- return IXGBE_ERR_PHY;
- }
- retries--;
-
- status = hw->phy.ops.read_reg(hw,
- IXGBE_MDIO_TX_VENDOR_ALARMS_3,
- IXGBE_MDIO_PMA_PMD_DEV_TYPE,
- &reg);
- if (status)
- return status;
- /* Verify PHY FW reset has completed */
- } while ((reg & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) != 1);
-
- /* Set port to low power mode */
status = hw->phy.ops.read_reg(hw,
- IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL,
- IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
- &reg);
- if (status)
- return status;
-
- /* Enable the transmitter */
- status = hw->phy.ops.read_reg(hw,
- IXGBE_MDIO_PMD_STD_TX_DISABLE_CNTR,
+ IXGBE_MDIO_TX_VENDOR_ALARMS_3,
IXGBE_MDIO_PMA_PMD_DEV_TYPE,
&reg);
if (status)
return status;
- reg &= ~IXGBE_MDIO_PMD_GLOBAL_TX_DISABLE;
+ /* If PHY FW reset completed bit is set then this is the first
+ * SW instance after a power on so the PHY FW must be un-stalled.
+ */
+ if (reg & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) {
+ status = hw->phy.ops.read_reg(hw,
+ IXGBE_MDIO_GLOBAL_RES_PR_10,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg);
+ if (status)
+ return status;
- status = hw->phy.ops.write_reg(hw,
- IXGBE_MDIO_PMD_STD_TX_DISABLE_CNTR,
- IXGBE_MDIO_PMA_PMD_DEV_TYPE,
- reg);
- if (status)
- return status;
+ reg &= ~IXGBE_MDIO_POWER_UP_STALL;
- /* Un-stall the PHY FW */
- status = hw->phy.ops.read_reg(hw,
- IXGBE_MDIO_GLOBAL_RES_PR_10,
- IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
- &reg);
- if (status)
- return status;
-
- reg &= ~IXGBE_MDIO_POWER_UP_STALL;
+ status = hw->phy.ops.write_reg(hw,
+ IXGBE_MDIO_GLOBAL_RES_PR_10,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ reg);
+ if (status)
+ return status;
+ }
- status = hw->phy.ops.write_reg(hw,
- IXGBE_MDIO_GLOBAL_RES_PR_10,
- IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
- reg);
return status;
}
@@ -1254,6 +1606,7 @@ static s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
s32 status;
u32 ctrl = 0;
u32 i;
+ u32 hlreg0;
bool link_up = false;
/* Call adapter stop to disable Tx/Rx and clear interrupts */
@@ -1338,6 +1691,15 @@ mac_reset_top:
hw->mac.num_rar_entries = 128;
hw->mac.ops.init_rx_addrs(hw);
+ if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
+ hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
+ hlreg0 &= ~IXGBE_HLREG0_MDCSPD;
+ IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
+ }
+
+ if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP)
+ ixgbe_setup_mux_ctl(hw);
+
return status;
}
@@ -1490,6 +1852,10 @@ static struct ixgbe_eeprom_operations eeprom_ops_X550EM_x = {
.read_i2c_sff8472 = &ixgbe_read_i2c_sff8472_generic, \
.read_i2c_eeprom = &ixgbe_read_i2c_eeprom_generic, \
.write_i2c_eeprom = &ixgbe_write_i2c_eeprom_generic, \
+ .read_reg = &ixgbe_read_phy_reg_generic, \
+ .write_reg = &ixgbe_write_phy_reg_generic, \
+ .setup_link = &ixgbe_setup_phy_link_generic, \
+ .set_phy_power = &ixgbe_set_copper_phy_power, \
.check_overtemp = &ixgbe_tn_check_overtemp, \
.get_firmware_version = &ixgbe_get_phy_firmware_version_generic,
@@ -1497,9 +1863,6 @@ static struct ixgbe_phy_operations phy_ops_X550 = {
X550_COMMON_PHY
.init = NULL,
.identify = &ixgbe_identify_phy_generic,
- .read_reg = &ixgbe_read_phy_reg_generic,
- .write_reg = &ixgbe_write_phy_reg_generic,
- .setup_link = &ixgbe_setup_phy_link_generic,
.read_i2c_combined = &ixgbe_read_i2c_combined_generic,
.write_i2c_combined = &ixgbe_write_i2c_combined_generic,
};
@@ -1508,9 +1871,14 @@ static struct ixgbe_phy_operations phy_ops_X550EM_x = {
X550_COMMON_PHY
.init = &ixgbe_init_phy_ops_X550em,
.identify = &ixgbe_identify_phy_x550em,
- .read_reg = NULL, /* defined later */
- .write_reg = NULL, /* defined later */
- .setup_link = NULL, /* defined later */
+};
+
+static const u32 ixgbe_mvals_X550[IXGBE_MVALS_IDX_LIMIT] = {
+ IXGBE_MVALS_INIT(X550)
+};
+
+static const u32 ixgbe_mvals_X550EM_x[IXGBE_MVALS_IDX_LIMIT] = {
+ IXGBE_MVALS_INIT(X550EM_x)
};
struct ixgbe_info ixgbe_X550_info = {
@@ -1520,6 +1888,7 @@ struct ixgbe_info ixgbe_X550_info = {
.eeprom_ops = &eeprom_ops_X550,
.phy_ops = &phy_ops_X550,
.mbx_ops = &mbx_ops_generic,
+ .mvals = ixgbe_mvals_X550,
};
struct ixgbe_info ixgbe_X550EM_x_info = {
@@ -1529,4 +1898,5 @@ struct ixgbe_info ixgbe_X550EM_x_info = {
.eeprom_ops = &eeprom_ops_X550EM_x,
.phy_ops = &phy_ops_X550EM_x,
.mbx_ops = &mbx_ops_generic,
+ .mvals = ixgbe_mvals_X550EM_x,
};
diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig
index d323a695dfbc..80af9ffce5ea 100644
--- a/drivers/net/ethernet/marvell/Kconfig
+++ b/drivers/net/ethernet/marvell/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_MARVELL
default y
depends on PCI || CPU_PXA168 || MV64X60 || PPC32 || PLAT_ORION || INET
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 1c75829eb166..d52639bc491f 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -3125,9 +3125,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
mib_counters_clear(mp);
- init_timer(&mp->mib_counters_timer);
- mp->mib_counters_timer.data = (unsigned long)mp;
- mp->mib_counters_timer.function = mib_counters_timer_wrapper;
+ setup_timer(&mp->mib_counters_timer, mib_counters_timer_wrapper,
+ (unsigned long)mp);
mp->mib_counters_timer.expires = jiffies + 30 * HZ;
spin_lock_init(&mp->mib_counters_lock);
@@ -3136,9 +3135,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
netif_napi_add(dev, &mp->napi, mv643xx_eth_poll, NAPI_POLL_WEIGHT);
- init_timer(&mp->rx_oom);
- mp->rx_oom.data = (unsigned long)mp;
- mp->rx_oom.function = oom_timer_wrapper;
+ setup_timer(&mp->rx_oom, oom_timer_wrapper, (unsigned long)mp);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index ce5f7f9cff06..5bdf78231a4e 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -1013,6 +1013,12 @@ static void mvneta_defaults_set(struct mvneta_port *pp)
val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
val |= MVNETA_GMAC_1MS_CLOCK_ENABLE;
mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val);
+ } else {
+ val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
+ val &= ~(MVNETA_GMAC_INBAND_AN_ENABLE |
+ MVNETA_GMAC_AN_SPEED_EN |
+ MVNETA_GMAC_AN_DUPLEX_EN);
+ mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
}
mvneta_set_ucast_table(pp, -1);
@@ -1359,7 +1365,7 @@ static void *mvneta_frag_alloc(const struct mvneta_port *pp)
static void mvneta_frag_free(const struct mvneta_port *pp, void *data)
{
if (likely(pp->frag_size <= PAGE_SIZE))
- put_page(virt_to_head_page(data));
+ skb_free_frag(data);
else
kfree(data);
}
diff --git a/drivers/net/ethernet/mellanox/Kconfig b/drivers/net/ethernet/mellanox/Kconfig
index 8cf7563a8d92..52a6665b7abf 100644
--- a/drivers/net/ethernet/mellanox/Kconfig
+++ b/drivers/net/ethernet/mellanox/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_MELLANOX
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
index 529ef0594b90..82040137d7d9 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
@@ -49,6 +49,7 @@
#include "mlx4.h"
#include "fw.h"
#include "fw_qos.h"
+#include "mlx4_stats.h"
#define CMD_POLL_TOKEN 0xffff
#define INBOX_MASK 0xffffffffffffff00ULL
@@ -882,7 +883,7 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
{
struct ib_smp *smp = inbox->buf;
u32 index;
- u8 port;
+ u8 port, slave_port;
u8 opcode_modifier;
u16 *table;
int err;
@@ -894,7 +895,8 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
__be32 slave_cap_mask;
__be64 slave_node_guid;
- port = vhcr->in_modifier;
+ slave_port = vhcr->in_modifier;
+ port = mlx4_slave_convert_port(dev, slave, slave_port);
/* network-view bit is for driver use only, and should not be passed to FW */
opcode_modifier = vhcr->op_modifier & ~0x8; /* clear netw view bit */
@@ -930,8 +932,9 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
if (smp->attr_id == IB_SMP_ATTR_PORT_INFO) {
/*get the slave specific caps:*/
/*do the command */
+ smp->attr_mod = cpu_to_be32(port);
err = mlx4_cmd_box(dev, inbox->dma, outbox->dma,
- vhcr->in_modifier, opcode_modifier,
+ port, opcode_modifier,
vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
/* modify the response for slaves */
if (!err && slave != mlx4_master_func_num(dev)) {
@@ -975,7 +978,7 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
}
if (smp->attr_id == IB_SMP_ATTR_NODE_INFO) {
err = mlx4_cmd_box(dev, inbox->dma, outbox->dma,
- vhcr->in_modifier, opcode_modifier,
+ port, opcode_modifier,
vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
if (!err) {
slave_node_guid = mlx4_get_slave_node_guid(dev, slave);
@@ -2915,7 +2918,7 @@ int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac)
port = mlx4_slaves_closest_port(dev, slave, port);
s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
s_info->mac = mac;
- mlx4_info(dev, "default mac on vf %d port %d to %llX will take afect only after vf restart\n",
+ mlx4_info(dev, "default mac on vf %d port %d to %llX will take effect only after vf restart\n",
vf, port, s_info->mac);
return 0;
}
@@ -3164,6 +3167,92 @@ int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_stat
}
EXPORT_SYMBOL_GPL(mlx4_set_vf_link_state);
+int mlx4_get_counter_stats(struct mlx4_dev *dev, int counter_index,
+ struct mlx4_counter *counter_stats, int reset)
+{
+ struct mlx4_cmd_mailbox *mailbox = NULL;
+ struct mlx4_counter *tmp_counter;
+ int err;
+ u32 if_stat_in_mod;
+
+ if (!counter_stats)
+ return -EINVAL;
+
+ if (counter_index == MLX4_SINK_COUNTER_INDEX(dev))
+ return 0;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+
+ memset(mailbox->buf, 0, sizeof(struct mlx4_counter));
+ if_stat_in_mod = counter_index;
+ if (reset)
+ if_stat_in_mod |= MLX4_QUERY_IF_STAT_RESET;
+ err = mlx4_cmd_box(dev, 0, mailbox->dma,
+ if_stat_in_mod, 0,
+ MLX4_CMD_QUERY_IF_STAT,
+ MLX4_CMD_TIME_CLASS_C,
+ MLX4_CMD_NATIVE);
+ if (err) {
+ mlx4_dbg(dev, "%s: failed to read statistics for counter index %d\n",
+ __func__, counter_index);
+ goto if_stat_out;
+ }
+ tmp_counter = (struct mlx4_counter *)mailbox->buf;
+ counter_stats->counter_mode = tmp_counter->counter_mode;
+ if (counter_stats->counter_mode == 0) {
+ counter_stats->rx_frames =
+ cpu_to_be64(be64_to_cpu(counter_stats->rx_frames) +
+ be64_to_cpu(tmp_counter->rx_frames));
+ counter_stats->tx_frames =
+ cpu_to_be64(be64_to_cpu(counter_stats->tx_frames) +
+ be64_to_cpu(tmp_counter->tx_frames));
+ counter_stats->rx_bytes =
+ cpu_to_be64(be64_to_cpu(counter_stats->rx_bytes) +
+ be64_to_cpu(tmp_counter->rx_bytes));
+ counter_stats->tx_bytes =
+ cpu_to_be64(be64_to_cpu(counter_stats->tx_bytes) +
+ be64_to_cpu(tmp_counter->tx_bytes));
+ }
+
+if_stat_out:
+ mlx4_free_cmd_mailbox(dev, mailbox);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_get_counter_stats);
+
+int mlx4_get_vf_stats(struct mlx4_dev *dev, int port, int vf_idx,
+ struct ifla_vf_stats *vf_stats)
+{
+ struct mlx4_counter tmp_vf_stats;
+ int slave;
+ int err = 0;
+
+ if (!vf_stats)
+ return -EINVAL;
+
+ if (!mlx4_is_master(dev))
+ return -EPROTONOSUPPORT;
+
+ slave = mlx4_get_slave_indx(dev, vf_idx);
+ if (slave < 0)
+ return -EINVAL;
+
+ port = mlx4_slaves_closest_port(dev, slave, port);
+ err = mlx4_calc_vf_counters(dev, slave, port, &tmp_vf_stats);
+ if (!err && tmp_vf_stats.counter_mode == 0) {
+ vf_stats->rx_packets = be64_to_cpu(tmp_vf_stats.rx_frames);
+ vf_stats->tx_packets = be64_to_cpu(tmp_vf_stats.tx_frames);
+ vf_stats->rx_bytes = be64_to_cpu(tmp_vf_stats.rx_bytes);
+ vf_stats->tx_bytes = be64_to_cpu(tmp_vf_stats.tx_bytes);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_get_vf_stats);
+
int mlx4_vf_smi_enabled(struct mlx4_dev *dev, int slave, int port)
{
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -3197,6 +3286,12 @@ int mlx4_vf_set_enable_smi_admin(struct mlx4_dev *dev, int slave, int port,
int enabled)
{
struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_active_ports actv_ports = mlx4_get_active_ports(
+ &priv->dev, slave);
+ int min_port = find_first_bit(actv_ports.ports,
+ priv->dev.caps.num_ports) + 1;
+ int max_port = min_port - 1 +
+ bitmap_weight(actv_ports.ports, priv->dev.caps.num_ports);
if (slave == mlx4_master_func_num(dev))
return 0;
@@ -3206,6 +3301,11 @@ int mlx4_vf_set_enable_smi_admin(struct mlx4_dev *dev, int slave, int port,
enabled < 0 || enabled > 1)
return -EINVAL;
+ if (min_port == max_port && dev->caps.num_ports > 1) {
+ mlx4_info(dev, "SMI access disallowed for single ported VFs\n");
+ return -EPROTONOSUPPORT;
+ }
+
priv->mfunc.master.vf_admin[slave].enable_smi[port] = enabled;
return 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c
index e71f31387ac6..3348e646db70 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cq.c
@@ -292,7 +292,7 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
u64 mtt_addr;
int err;
- if (vector > dev->caps.num_comp_vectors + dev->caps.comp_pool)
+ if (vector >= dev->caps.num_comp_vectors)
return -EINVAL;
cq->vector = vector;
@@ -319,7 +319,7 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
cq_context->flags |= cpu_to_be32(1 << 19);
cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index);
- cq_context->comp_eqn = priv->eq_table.eq[vector].eqn;
+ cq_context->comp_eqn = priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(vector)].eqn;
cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
mtt_addr = mlx4_mtt_addr(dev, mtt);
@@ -339,11 +339,11 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
init_completion(&cq->free);
cq->comp = mlx4_add_cq_to_tasklet;
cq->tasklet_ctx.priv =
- &priv->eq_table.eq[cq->vector].tasklet_ctx;
+ &priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(vector)].tasklet_ctx;
INIT_LIST_HEAD(&cq->tasklet_ctx.list);
- cq->irq = priv->eq_table.eq[cq->vector].irq;
+ cq->irq = priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(vector)].irq;
return 0;
err_radix:
@@ -368,7 +368,10 @@ void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq)
if (err)
mlx4_warn(dev, "HW2SW_CQ failed (%d) for CQN %06x\n", err, cq->cqn);
- synchronize_irq(priv->eq_table.eq[cq->vector].irq);
+ synchronize_irq(priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(cq->vector)].irq);
+ if (priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(cq->vector)].irq !=
+ priv->eq_table.eq[MLX4_EQ_ASYNC].irq)
+ synchronize_irq(priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
spin_lock_irq(&cq_table->lock);
radix_tree_delete(&cq_table->tree, cq->cqn);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
index 22da4d0d0f05..63769df872a4 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
@@ -66,6 +66,7 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv,
cq->ring = ring;
cq->is_tx = mode;
+ cq->vector = mdev->dev->caps.num_comp_vectors;
/* Allocate HW buffers on provided NUMA node.
* dev->numa_node is used in mtt range allocation flow.
@@ -101,12 +102,7 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
int err = 0;
char name[25];
int timestamp_en = 0;
- struct cpu_rmap *rmap =
-#ifdef CONFIG_RFS_ACCEL
- priv->dev->rx_cpu_rmap;
-#else
- NULL;
-#endif
+ bool assigned_eq = false;
cq->dev = mdev->pndev[priv->port];
cq->mcq.set_ci_db = cq->wqres.db.db;
@@ -116,23 +112,19 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
memset(cq->buf, 0, cq->buf_size);
if (cq->is_tx == RX) {
- if (mdev->dev->caps.comp_pool) {
- if (!cq->vector) {
- sprintf(name, "%s-%d", priv->dev->name,
- cq->ring);
- /* Set IRQ for specific name (per ring) */
- if (mlx4_assign_eq(mdev->dev, name, rmap,
- &cq->vector)) {
- cq->vector = (cq->ring + 1 + priv->port)
- % mdev->dev->caps.num_comp_vectors;
- mlx4_warn(mdev, "Failed assigning an EQ to %s, falling back to legacy EQ's\n",
- name);
- }
-
+ if (!mlx4_is_eq_vector_valid(mdev->dev, priv->port,
+ cq->vector)) {
+ cq->vector = cpumask_first(priv->rx_ring[cq->ring]->affinity_mask);
+
+ err = mlx4_assign_eq(mdev->dev, priv->port,
+ &cq->vector);
+ if (err) {
+ mlx4_err(mdev, "Failed assigning an EQ to %s\n",
+ name);
+ goto free_eq;
}
- } else {
- cq->vector = (cq->ring + 1 + priv->port) %
- mdev->dev->caps.num_comp_vectors;
+
+ assigned_eq = true;
}
cq->irq_desc =
@@ -159,7 +151,7 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
&mdev->priv_uar, cq->wqres.db.dma, &cq->mcq,
cq->vector, 0, timestamp_en);
if (err)
- return err;
+ goto free_eq;
cq->mcq.comp = cq->is_tx ? mlx4_en_tx_irq : mlx4_en_rx_irq;
cq->mcq.event = mlx4_en_cq_event;
@@ -168,13 +160,6 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_tx_cq,
NAPI_POLL_WEIGHT);
} else {
- struct mlx4_en_rx_ring *ring = priv->rx_ring[cq->ring];
-
- err = irq_set_affinity_hint(cq->mcq.irq,
- ring->affinity_mask);
- if (err)
- mlx4_warn(mdev, "Failed setting affinity hint\n");
-
netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_rx_cq, 64);
napi_hash_add(&cq->napi);
}
@@ -182,6 +167,12 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
napi_enable(&cq->napi);
return 0;
+
+free_eq:
+ if (assigned_eq)
+ mlx4_release_eq(mdev->dev, cq->vector);
+ cq->vector = mdev->dev->caps.num_comp_vectors;
+ return err;
}
void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq)
@@ -191,9 +182,9 @@ void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq)
mlx4_en_unmap_buffer(&cq->wqres.buf);
mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size);
- if (priv->mdev->dev->caps.comp_pool && cq->vector) {
+ if (mlx4_is_eq_vector_valid(mdev->dev, priv->port, cq->vector) &&
+ cq->is_tx == RX)
mlx4_release_eq(priv->mdev->dev, cq->vector);
- }
cq->vector = 0;
cq->buf_size = 0;
cq->buf = NULL;
@@ -207,7 +198,6 @@ void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
if (!cq->is_tx) {
napi_hash_del(&cq->napi);
synchronize_rcu();
- irq_set_affinity_hint(cq->mcq.irq, NULL);
}
netif_napi_del(&cq->napi);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index a2ddf3d75ff8..99ba1c50e585 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -119,6 +119,12 @@ static const char main_strings[][ETH_GSTRING_LEN] = {
"queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed",
"rx_csum_good", "rx_csum_none", "rx_csum_complete", "tx_chksum_offload",
+ /* pf statistics */
+ "pf_rx_packets",
+ "pf_rx_bytes",
+ "pf_tx_packets",
+ "pf_tx_bytes",
+
/* priority flow control statistics rx */
"rx_pause_prio_0", "rx_pause_duration_prio_0",
"rx_pause_transition_prio_0",
@@ -368,6 +374,11 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,
if (bitmap_iterator_test(&it))
data[index++] = ((unsigned long *)&priv->port_stats)[i];
+ for (i = 0; i < NUM_PF_STATS; i++, bitmap_iterator_inc(&it))
+ if (bitmap_iterator_test(&it))
+ data[index++] =
+ ((unsigned long *)&priv->pf_stats)[i];
+
for (i = 0; i < NUM_FLOW_PRIORITY_STATS_RX;
i++, bitmap_iterator_inc(&it))
if (bitmap_iterator_test(&it))
@@ -448,6 +459,12 @@ static void mlx4_en_get_strings(struct net_device *dev,
strcpy(data + (index++) * ETH_GSTRING_LEN,
main_strings[strings]);
+ for (i = 0; i < NUM_PF_STATS; i++, strings++,
+ bitmap_iterator_inc(&it))
+ if (bitmap_iterator_test(&it))
+ strcpy(data + (index++) * ETH_GSTRING_LEN,
+ main_strings[strings]);
+
for (i = 0; i < NUM_FLOW_STATS; i++, strings++,
bitmap_iterator_inc(&it))
if (bitmap_iterator_test(&it))
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index cf467a9f6cc7..77179d7ae4cc 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -1597,6 +1597,9 @@ int mlx4_en_start_port(struct net_device *dev)
}
mdev->mac_removed[priv->port] = 0;
+ priv->counter_index =
+ mlx4_get_default_counter_index(mdev->dev, priv->port);
+
err = mlx4_en_config_rss_steer(priv);
if (err) {
en_err(priv, "Failed configuring rss steering\n");
@@ -1755,6 +1758,7 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
/* Set port as not active */
priv->port_up = false;
+ priv->counter_index = MLX4_SINK_COUNTER_INDEX(mdev->dev);
/* Promsicuous mode */
if (mdev->dev->caps.steering_mode ==
@@ -1891,6 +1895,7 @@ static void mlx4_en_clear_stats(struct net_device *dev)
sizeof(priv->rx_priority_flowstats));
memset(&priv->tx_priority_flowstats, 0,
sizeof(priv->tx_priority_flowstats));
+ memset(&priv->pf_stats, 0, sizeof(priv->pf_stats));
for (i = 0; i < priv->tx_ring_num; i++) {
priv->tx_ring[i]->bytes = 0;
@@ -1954,7 +1959,6 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv)
int i;
#ifdef CONFIG_RFS_ACCEL
- free_irq_cpu_rmap(priv->dev->rx_cpu_rmap);
priv->dev->rx_cpu_rmap = NULL;
#endif
@@ -2012,11 +2016,7 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
}
#ifdef CONFIG_RFS_ACCEL
- if (priv->mdev->dev->caps.comp_pool) {
- priv->dev->rx_cpu_rmap = alloc_irq_cpu_rmap(priv->mdev->dev->caps.comp_pool);
- if (!priv->dev->rx_cpu_rmap)
- goto err;
- }
+ priv->dev->rx_cpu_rmap = mlx4_get_cpu_rmap(priv->mdev->dev, priv->port);
#endif
return 0;
@@ -2292,6 +2292,15 @@ static int mlx4_en_set_vf_link_state(struct net_device *dev, int vf, int link_st
return mlx4_set_vf_link_state(mdev->dev, en_priv->port, vf, link_state);
}
+static int mlx4_en_get_vf_stats(struct net_device *dev, int vf,
+ struct ifla_vf_stats *vf_stats)
+{
+ struct mlx4_en_priv *en_priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = en_priv->mdev;
+
+ return mlx4_get_vf_stats(mdev->dev, en_priv->port, vf, vf_stats);
+}
+
#define PORT_ID_BYTE_LEN 8
static int mlx4_en_get_phys_port_id(struct net_device *dev,
struct netdev_phys_item_id *ppid)
@@ -2489,6 +2498,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = {
.ndo_set_vf_rate = mlx4_en_set_vf_rate,
.ndo_set_vf_spoofchk = mlx4_en_set_vf_spoofchk,
.ndo_set_vf_link_state = mlx4_en_set_vf_link_state,
+ .ndo_get_vf_stats = mlx4_en_get_vf_stats,
.ndo_get_vf_config = mlx4_en_get_vf_config,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = mlx4_en_netpoll,
@@ -2686,7 +2696,7 @@ void mlx4_en_update_pfc_stats_bitmap(struct mlx4_dev *dev,
u8 rx_ppp, u8 rx_pause,
u8 tx_ppp, u8 tx_pause)
{
- int last_i = NUM_MAIN_STATS + NUM_PORT_STATS;
+ int last_i = NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PF_STATS;
if (!mlx4_is_slave(dev) &&
(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN)) {
@@ -2748,6 +2758,11 @@ void mlx4_en_set_stats_bitmap(struct mlx4_dev *dev,
bitmap_set(stats_bitmap->bitmap, last_i, NUM_PORT_STATS);
last_i += NUM_PORT_STATS;
+ if (mlx4_is_master(dev))
+ bitmap_set(stats_bitmap->bitmap, last_i,
+ NUM_PF_STATS);
+ last_i += NUM_PF_STATS;
+
mlx4_en_update_pfc_stats_bitmap(dev, stats_bitmap,
rx_ppp, rx_pause,
tx_ppp, tx_pause);
@@ -2783,6 +2798,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
priv = netdev_priv(dev);
memset(priv, 0, sizeof(struct mlx4_en_priv));
+ priv->counter_index = MLX4_SINK_COUNTER_INDEX(mdev->dev);
spin_lock_init(&priv->stats_lock);
INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode);
INIT_WORK(&priv->watchdog_task, mlx4_en_restart);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c
index 0a56f010c846..ee99e67187f5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c
@@ -149,6 +149,7 @@ static unsigned long en_stats_adder(__be64 *start, __be64 *next, int num)
int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
{
+ struct mlx4_counter tmp_counter_stats;
struct mlx4_en_stat_out_mbox *mlx4_en_stats;
struct mlx4_en_stat_out_flow_control_mbox *flowstats;
struct mlx4_en_priv *priv = netdev_priv(mdev->pndev[port]);
@@ -156,7 +157,7 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
struct mlx4_cmd_mailbox *mailbox;
u64 in_mod = reset << 8 | port;
int err;
- int i;
+ int i, counter_index;
mailbox = mlx4_alloc_cmd_mailbox(mdev->dev);
if (IS_ERR(mailbox))
@@ -202,6 +203,20 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
priv->port_stats.tso_packets += ring->tso_packets;
priv->port_stats.xmit_more += ring->xmit_more;
}
+ if (mlx4_is_master(mdev->dev)) {
+ stats->rx_packets = en_stats_adder(&mlx4_en_stats->RTOT_prio_0,
+ &mlx4_en_stats->RTOT_prio_1,
+ NUM_PRIORITIES);
+ stats->tx_packets = en_stats_adder(&mlx4_en_stats->TTOT_prio_0,
+ &mlx4_en_stats->TTOT_prio_1,
+ NUM_PRIORITIES);
+ stats->rx_bytes = en_stats_adder(&mlx4_en_stats->ROCT_prio_0,
+ &mlx4_en_stats->ROCT_prio_1,
+ NUM_PRIORITIES);
+ stats->tx_bytes = en_stats_adder(&mlx4_en_stats->TOCT_prio_0,
+ &mlx4_en_stats->TOCT_prio_1,
+ NUM_PRIORITIES);
+ }
/* net device stats */
stats->rx_errors = be64_to_cpu(mlx4_en_stats->PCS) +
@@ -296,6 +311,11 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
spin_unlock_bh(&priv->stats_lock);
+ memset(&tmp_counter_stats, 0, sizeof(tmp_counter_stats));
+ counter_index = mlx4_get_default_counter_index(mdev->dev, port);
+ err = mlx4_get_counter_stats(mdev->dev, counter_index,
+ &tmp_counter_stats, reset);
+
/* 0xffs indicates invalid value */
memset(mailbox->buf, 0xff, sizeof(*flowstats) * MLX4_NUM_PRIORITIES);
@@ -314,6 +334,13 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
spin_lock_bh(&priv->stats_lock);
+ if (tmp_counter_stats.counter_mode == 0) {
+ priv->pf_stats.rx_bytes = be64_to_cpu(tmp_counter_stats.rx_bytes);
+ priv->pf_stats.tx_bytes = be64_to_cpu(tmp_counter_stats.tx_bytes);
+ priv->pf_stats.rx_packets = be64_to_cpu(tmp_counter_stats.rx_frames);
+ priv->pf_stats.tx_packets = be64_to_cpu(tmp_counter_stats.tx_frames);
+ }
+
for (i = 0; i < MLX4_NUM_PRIORITIES; i++) {
priv->rx_priority_flowstats[i].rx_pause =
be64_to_cpu(flowstats[i].rx_pause);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_resources.c b/drivers/net/ethernet/mellanox/mlx4/en_resources.c
index 34f2fdf4fe5d..e482fa1bb741 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_resources.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_resources.c
@@ -66,7 +66,7 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
context->pri_path.sched_queue |= user_prio << 3;
context->pri_path.feup = MLX4_FEUP_FORCE_ETH_UP;
}
- context->pri_path.counter_index = 0xff;
+ context->pri_path.counter_index = priv->counter_index;
context->cqn_send = cpu_to_be32(cqn);
context->cqn_recv = cpu_to_be32(cqn);
context->db_rec_addr = cpu_to_be64(priv->res.db.dma << 2);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 2a77a6b19121..35f726c17e48 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -337,15 +337,10 @@ void mlx4_en_set_num_rx_rings(struct mlx4_en_dev *mdev)
struct mlx4_dev *dev = mdev->dev;
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
- if (!dev->caps.comp_pool)
- num_of_eqs = max_t(int, MIN_RX_RINGS,
- min_t(int,
- dev->caps.num_comp_vectors,
- DEF_RX_RINGS));
- else
- num_of_eqs = min_t(int, MAX_MSIX_P_PORT,
- dev->caps.comp_pool/
- dev->caps.num_ports) - 1;
+ num_of_eqs = max_t(int, MIN_RX_RINGS,
+ min_t(int,
+ mlx4_get_eqs_per_port(mdev->dev, i),
+ DEF_RX_RINGS));
num_rx_rings = mlx4_low_memory_profile() ? MIN_RX_RINGS :
min_t(int, num_of_eqs,
diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c
index 2619c9fbf42d..aae13adfb492 100644
--- a/drivers/net/ethernet/mellanox/mlx4/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/eq.c
@@ -145,7 +145,7 @@ void mlx4_gen_slave_eqe(struct work_struct *work)
struct mlx4_slave_event_eq *slave_eq = &mfunc->master.slave_eq;
struct mlx4_eqe *eqe;
u8 slave;
- int i;
+ int i, phys_port, slave_port;
for (eqe = next_slave_event_eqe(slave_eq); eqe;
eqe = next_slave_event_eqe(slave_eq)) {
@@ -154,9 +154,20 @@ void mlx4_gen_slave_eqe(struct work_struct *work)
/* All active slaves need to receive the event */
if (slave == ALL_SLAVES) {
for (i = 0; i <= dev->persist->num_vfs; i++) {
+ phys_port = 0;
+ if (eqe->type == MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT &&
+ eqe->subtype == MLX4_DEV_PMC_SUBTYPE_PORT_INFO) {
+ phys_port = eqe->event.port_mgmt_change.port;
+ slave_port = mlx4_phys_to_slave_port(dev, i, phys_port);
+ if (slave_port < 0) /* VF doesn't have this port */
+ continue;
+ eqe->event.port_mgmt_change.port = slave_port;
+ }
if (mlx4_GEN_EQE(dev, i, eqe))
mlx4_warn(dev, "Failed to generate event for slave %d\n",
i);
+ if (phys_port)
+ eqe->event.port_mgmt_change.port = phys_port;
}
} else {
if (mlx4_GEN_EQE(dev, slave, eqe))
@@ -210,6 +221,22 @@ static void mlx4_slave_event(struct mlx4_dev *dev, int slave,
slave_event(dev, slave, eqe);
}
+#if defined(CONFIG_SMP)
+static void mlx4_set_eq_affinity_hint(struct mlx4_priv *priv, int vec)
+{
+ int hint_err;
+ struct mlx4_dev *dev = &priv->dev;
+ struct mlx4_eq *eq = &priv->eq_table.eq[vec];
+
+ if (!eq->affinity_mask || cpumask_empty(eq->affinity_mask))
+ return;
+
+ hint_err = irq_set_affinity_hint(eq->irq, eq->affinity_mask);
+ if (hint_err)
+ mlx4_warn(dev, "irq_set_affinity_hint failed, err %d\n", hint_err);
+}
+#endif
+
int mlx4_gen_pkey_eqe(struct mlx4_dev *dev, int slave, u8 port)
{
struct mlx4_eqe eqe;
@@ -224,7 +251,7 @@ int mlx4_gen_pkey_eqe(struct mlx4_dev *dev, int slave, u8 port)
eqe.type = MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT;
eqe.subtype = MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE;
- eqe.event.port_mgmt_change.port = port;
+ eqe.event.port_mgmt_change.port = mlx4_phys_to_slave_port(dev, slave, port);
return mlx4_GEN_EQE(dev, slave, &eqe);
}
@@ -241,7 +268,7 @@ int mlx4_gen_guid_change_eqe(struct mlx4_dev *dev, int slave, u8 port)
eqe.type = MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT;
eqe.subtype = MLX4_DEV_PMC_SUBTYPE_GUID_INFO;
- eqe.event.port_mgmt_change.port = port;
+ eqe.event.port_mgmt_change.port = mlx4_phys_to_slave_port(dev, slave, port);
return mlx4_GEN_EQE(dev, slave, &eqe);
}
@@ -251,6 +278,7 @@ int mlx4_gen_port_state_change_eqe(struct mlx4_dev *dev, int slave, u8 port,
u8 port_subtype_change)
{
struct mlx4_eqe eqe;
+ u8 slave_port = mlx4_phys_to_slave_port(dev, slave, port);
/*don't send if we don't have the that slave */
if (dev->persist->num_vfs < slave)
@@ -259,7 +287,7 @@ int mlx4_gen_port_state_change_eqe(struct mlx4_dev *dev, int slave, u8 port,
eqe.type = MLX4_EVENT_TYPE_PORT_CHANGE;
eqe.subtype = port_subtype_change;
- eqe.event.port_change.port = cpu_to_be32(port << 28);
+ eqe.event.port_change.port = cpu_to_be32(slave_port << 28);
mlx4_dbg(dev, "%s: sending: %d to slave: %d on port: %d\n", __func__,
port_subtype_change, slave, port);
@@ -589,6 +617,10 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
if (SLAVE_PORT_GEN_EVENT_DOWN == gen_event) {
if (i == mlx4_master_func_num(dev))
continue;
+ eqe->event.port_change.port =
+ cpu_to_be32(
+ (be32_to_cpu(eqe->event.port_change.port) & 0xFFFFFFF)
+ | (mlx4_phys_to_slave_port(dev, i, port) << 28));
mlx4_slave_event(dev, i, eqe);
}
}
@@ -879,8 +911,8 @@ static int mlx4_num_eq_uar(struct mlx4_dev *dev)
* we need to map, take the difference of highest index and
* the lowest index we'll use and add 1.
*/
- return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs +
- dev->caps.comp_pool)/4 - dev->caps.reserved_eqs/4 + 1;
+ return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs) / 4 -
+ dev->caps.reserved_eqs / 4 + 1;
}
static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq)
@@ -1069,32 +1101,21 @@ static void mlx4_free_eq(struct mlx4_dev *dev,
static void mlx4_free_irqs(struct mlx4_dev *dev)
{
struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table;
- struct mlx4_priv *priv = mlx4_priv(dev);
- int i, vec;
+ int i;
if (eq_table->have_irq)
free_irq(dev->persist->pdev->irq, dev);
for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i)
if (eq_table->eq[i].have_irq) {
+ free_cpumask_var(eq_table->eq[i].affinity_mask);
+#if defined(CONFIG_SMP)
+ irq_set_affinity_hint(eq_table->eq[i].irq, NULL);
+#endif
free_irq(eq_table->eq[i].irq, eq_table->eq + i);
eq_table->eq[i].have_irq = 0;
}
- for (i = 0; i < dev->caps.comp_pool; i++) {
- /*
- * Freeing the assigned irq's
- * all bits should be 0, but we need to validate
- */
- if (priv->msix_ctl.pool_bm & 1ULL << i) {
- /* NO need protecting*/
- vec = dev->caps.num_comp_vectors + 1 + i;
- free_irq(priv->eq_table.eq[vec].irq,
- &priv->eq_table.eq[vec]);
- }
- }
-
-
kfree(eq_table->irq_names);
}
@@ -1175,76 +1196,73 @@ int mlx4_init_eq_table(struct mlx4_dev *dev)
}
priv->eq_table.irq_names =
- kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1 +
- dev->caps.comp_pool),
+ kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1),
GFP_KERNEL);
if (!priv->eq_table.irq_names) {
err = -ENOMEM;
- goto err_out_bitmap;
+ goto err_out_clr_int;
}
- for (i = 0; i < dev->caps.num_comp_vectors; ++i) {
- err = mlx4_create_eq(dev, dev->caps.num_cqs -
- dev->caps.reserved_cqs +
- MLX4_NUM_SPARE_EQE,
- (dev->flags & MLX4_FLAG_MSI_X) ? i : 0,
- &priv->eq_table.eq[i]);
- if (err) {
- --i;
- goto err_out_unmap;
- }
- }
-
- err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE,
- (dev->flags & MLX4_FLAG_MSI_X) ? dev->caps.num_comp_vectors : 0,
- &priv->eq_table.eq[dev->caps.num_comp_vectors]);
- if (err)
- goto err_out_comp;
-
- /*if additional completion vectors poolsize is 0 this loop will not run*/
- for (i = dev->caps.num_comp_vectors + 1;
- i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) {
+ for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) {
+ if (i == MLX4_EQ_ASYNC) {
+ err = mlx4_create_eq(dev,
+ MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE,
+ 0, &priv->eq_table.eq[MLX4_EQ_ASYNC]);
+ } else {
+ struct mlx4_eq *eq = &priv->eq_table.eq[i];
+#ifdef CONFIG_RFS_ACCEL
+ int port = find_first_bit(eq->actv_ports.ports,
+ dev->caps.num_ports) + 1;
+
+ if (port <= dev->caps.num_ports) {
+ struct mlx4_port_info *info =
+ &mlx4_priv(dev)->port[port];
+
+ if (!info->rmap) {
+ info->rmap = alloc_irq_cpu_rmap(
+ mlx4_get_eqs_per_port(dev, port));
+ if (!info->rmap) {
+ mlx4_warn(dev, "Failed to allocate cpu rmap\n");
+ err = -ENOMEM;
+ goto err_out_unmap;
+ }
+ }
- err = mlx4_create_eq(dev, dev->caps.num_cqs -
- dev->caps.reserved_cqs +
- MLX4_NUM_SPARE_EQE,
- (dev->flags & MLX4_FLAG_MSI_X) ? i : 0,
- &priv->eq_table.eq[i]);
- if (err) {
- --i;
- goto err_out_unmap;
+ err = irq_cpu_rmap_add(
+ info->rmap, eq->irq);
+ if (err)
+ mlx4_warn(dev, "Failed adding irq rmap\n");
+ }
+#endif
+ err = mlx4_create_eq(dev, dev->caps.num_cqs -
+ dev->caps.reserved_cqs +
+ MLX4_NUM_SPARE_EQE,
+ (dev->flags & MLX4_FLAG_MSI_X) ?
+ i + 1 - !!(i > MLX4_EQ_ASYNC) : 0,
+ eq);
}
+ if (err)
+ goto err_out_unmap;
}
-
if (dev->flags & MLX4_FLAG_MSI_X) {
const char *eq_name;
- for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) {
- if (i < dev->caps.num_comp_vectors) {
- snprintf(priv->eq_table.irq_names +
- i * MLX4_IRQNAME_SIZE,
- MLX4_IRQNAME_SIZE,
- "mlx4-comp-%d@pci:%s", i,
- pci_name(dev->persist->pdev));
- } else {
- snprintf(priv->eq_table.irq_names +
- i * MLX4_IRQNAME_SIZE,
- MLX4_IRQNAME_SIZE,
- "mlx4-async@pci:%s",
- pci_name(dev->persist->pdev));
- }
+ snprintf(priv->eq_table.irq_names +
+ MLX4_EQ_ASYNC * MLX4_IRQNAME_SIZE,
+ MLX4_IRQNAME_SIZE,
+ "mlx4-async@pci:%s",
+ pci_name(dev->persist->pdev));
+ eq_name = priv->eq_table.irq_names +
+ MLX4_EQ_ASYNC * MLX4_IRQNAME_SIZE;
- eq_name = priv->eq_table.irq_names +
- i * MLX4_IRQNAME_SIZE;
- err = request_irq(priv->eq_table.eq[i].irq,
- mlx4_msi_x_interrupt, 0, eq_name,
- priv->eq_table.eq + i);
- if (err)
- goto err_out_async;
+ err = request_irq(priv->eq_table.eq[MLX4_EQ_ASYNC].irq,
+ mlx4_msi_x_interrupt, 0, eq_name,
+ priv->eq_table.eq + MLX4_EQ_ASYNC);
+ if (err)
+ goto err_out_unmap;
- priv->eq_table.eq[i].have_irq = 1;
- }
+ priv->eq_table.eq[MLX4_EQ_ASYNC].have_irq = 1;
} else {
snprintf(priv->eq_table.irq_names,
MLX4_IRQNAME_SIZE,
@@ -1253,36 +1271,38 @@ int mlx4_init_eq_table(struct mlx4_dev *dev)
err = request_irq(dev->persist->pdev->irq, mlx4_interrupt,
IRQF_SHARED, priv->eq_table.irq_names, dev);
if (err)
- goto err_out_async;
+ goto err_out_unmap;
priv->eq_table.have_irq = 1;
}
err = mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0,
- priv->eq_table.eq[dev->caps.num_comp_vectors].eqn);
+ priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
if (err)
mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n",
- priv->eq_table.eq[dev->caps.num_comp_vectors].eqn, err);
+ priv->eq_table.eq[MLX4_EQ_ASYNC].eqn, err);
- for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i)
- eq_set_ci(&priv->eq_table.eq[i], 1);
+ /* arm ASYNC eq */
+ eq_set_ci(&priv->eq_table.eq[MLX4_EQ_ASYNC], 1);
return 0;
-err_out_async:
- mlx4_free_eq(dev, &priv->eq_table.eq[dev->caps.num_comp_vectors]);
-
-err_out_comp:
- i = dev->caps.num_comp_vectors - 1;
-
err_out_unmap:
- while (i >= 0) {
- mlx4_free_eq(dev, &priv->eq_table.eq[i]);
- --i;
+ while (i >= 0)
+ mlx4_free_eq(dev, &priv->eq_table.eq[i--]);
+#ifdef CONFIG_RFS_ACCEL
+ for (i = 1; i <= dev->caps.num_ports; i++) {
+ if (mlx4_priv(dev)->port[i].rmap) {
+ free_irq_cpu_rmap(mlx4_priv(dev)->port[i].rmap);
+ mlx4_priv(dev)->port[i].rmap = NULL;
+ }
}
+#endif
+ mlx4_free_irqs(dev);
+
+err_out_clr_int:
if (!mlx4_is_slave(dev))
mlx4_unmap_clr_int(dev);
- mlx4_free_irqs(dev);
err_out_bitmap:
mlx4_unmap_uar(dev);
@@ -1300,11 +1320,19 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
int i;
mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 1,
- priv->eq_table.eq[dev->caps.num_comp_vectors].eqn);
+ priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
+#ifdef CONFIG_RFS_ACCEL
+ for (i = 1; i <= dev->caps.num_ports; i++) {
+ if (mlx4_priv(dev)->port[i].rmap) {
+ free_irq_cpu_rmap(mlx4_priv(dev)->port[i].rmap);
+ mlx4_priv(dev)->port[i].rmap = NULL;
+ }
+ }
+#endif
mlx4_free_irqs(dev);
- for (i = 0; i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i)
+ for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i)
mlx4_free_eq(dev, &priv->eq_table.eq[i]);
if (!mlx4_is_slave(dev))
@@ -1355,87 +1383,169 @@ int mlx4_test_interrupts(struct mlx4_dev *dev)
/* Return to default */
mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0,
- priv->eq_table.eq[dev->caps.num_comp_vectors].eqn);
+ priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
return err;
}
EXPORT_SYMBOL(mlx4_test_interrupts);
-int mlx4_assign_eq(struct mlx4_dev *dev, char *name, struct cpu_rmap *rmap,
- int *vector)
+bool mlx4_is_eq_vector_valid(struct mlx4_dev *dev, u8 port, int vector)
{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+
+ vector = MLX4_CQ_TO_EQ_VECTOR(vector);
+ if (vector < 0 || (vector >= dev->caps.num_comp_vectors + 1) ||
+ (vector == MLX4_EQ_ASYNC))
+ return false;
+
+ return test_bit(port - 1, priv->eq_table.eq[vector].actv_ports.ports);
+}
+EXPORT_SYMBOL(mlx4_is_eq_vector_valid);
+u32 mlx4_get_eqs_per_port(struct mlx4_dev *dev, u8 port)
+{
struct mlx4_priv *priv = mlx4_priv(dev);
- int vec = 0, err = 0, i;
+ unsigned int i;
+ unsigned int sum = 0;
+
+ for (i = 0; i < dev->caps.num_comp_vectors + 1; i++)
+ sum += !!test_bit(port - 1,
+ priv->eq_table.eq[i].actv_ports.ports);
+
+ return sum;
+}
+EXPORT_SYMBOL(mlx4_get_eqs_per_port);
+
+int mlx4_is_eq_shared(struct mlx4_dev *dev, int vector)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+
+ vector = MLX4_CQ_TO_EQ_VECTOR(vector);
+ if (vector <= 0 || (vector >= dev->caps.num_comp_vectors + 1))
+ return -EINVAL;
+
+ return !!(bitmap_weight(priv->eq_table.eq[vector].actv_ports.ports,
+ dev->caps.num_ports) > 1);
+}
+EXPORT_SYMBOL(mlx4_is_eq_shared);
+
+struct cpu_rmap *mlx4_get_cpu_rmap(struct mlx4_dev *dev, int port)
+{
+ return mlx4_priv(dev)->port[port].rmap;
+}
+EXPORT_SYMBOL(mlx4_get_cpu_rmap);
+
+int mlx4_assign_eq(struct mlx4_dev *dev, u8 port, int *vector)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ int err = 0, i = 0;
+ u32 min_ref_count_val = (u32)-1;
+ int requested_vector = MLX4_CQ_TO_EQ_VECTOR(*vector);
+ int *prequested_vector = NULL;
+
mutex_lock(&priv->msix_ctl.pool_lock);
- for (i = 0; !vec && i < dev->caps.comp_pool; i++) {
- if (~priv->msix_ctl.pool_bm & 1ULL << i) {
- priv->msix_ctl.pool_bm |= 1ULL << i;
- vec = dev->caps.num_comp_vectors + 1 + i;
- snprintf(priv->eq_table.irq_names +
- vec * MLX4_IRQNAME_SIZE,
- MLX4_IRQNAME_SIZE, "%s", name);
-#ifdef CONFIG_RFS_ACCEL
- if (rmap) {
- err = irq_cpu_rmap_add(rmap,
- priv->eq_table.eq[vec].irq);
- if (err)
- mlx4_warn(dev, "Failed adding irq rmap\n");
+ if (requested_vector < (dev->caps.num_comp_vectors + 1) &&
+ (requested_vector >= 0) &&
+ (requested_vector != MLX4_EQ_ASYNC)) {
+ if (test_bit(port - 1,
+ priv->eq_table.eq[requested_vector].actv_ports.ports)) {
+ prequested_vector = &requested_vector;
+ } else {
+ struct mlx4_eq *eq;
+
+ for (i = 1; i < port;
+ requested_vector += mlx4_get_eqs_per_port(dev, i++))
+ ;
+
+ eq = &priv->eq_table.eq[requested_vector];
+ if (requested_vector < dev->caps.num_comp_vectors + 1 &&
+ test_bit(port - 1, eq->actv_ports.ports)) {
+ prequested_vector = &requested_vector;
}
-#endif
- err = request_irq(priv->eq_table.eq[vec].irq,
- mlx4_msi_x_interrupt, 0,
- &priv->eq_table.irq_names[vec<<5],
- priv->eq_table.eq + vec);
- if (err) {
- /*zero out bit by fliping it*/
- priv->msix_ctl.pool_bm ^= 1 << i;
- vec = 0;
- continue;
- /*we dont want to break here*/
+ }
+ }
+
+ if (!prequested_vector) {
+ requested_vector = -1;
+ for (i = 0; min_ref_count_val && i < dev->caps.num_comp_vectors + 1;
+ i++) {
+ struct mlx4_eq *eq = &priv->eq_table.eq[i];
+
+ if (min_ref_count_val > eq->ref_count &&
+ test_bit(port - 1, eq->actv_ports.ports)) {
+ min_ref_count_val = eq->ref_count;
+ requested_vector = i;
}
+ }
+
+ if (requested_vector < 0) {
+ err = -ENOSPC;
+ goto err_unlock;
+ }
+
+ prequested_vector = &requested_vector;
+ }
+
+ if (!test_bit(*prequested_vector, priv->msix_ctl.pool_bm) &&
+ dev->flags & MLX4_FLAG_MSI_X) {
+ set_bit(*prequested_vector, priv->msix_ctl.pool_bm);
+ snprintf(priv->eq_table.irq_names +
+ *prequested_vector * MLX4_IRQNAME_SIZE,
+ MLX4_IRQNAME_SIZE, "mlx4-%d@%s",
+ *prequested_vector, dev_name(&dev->persist->pdev->dev));
- eq_set_ci(&priv->eq_table.eq[vec], 1);
+ err = request_irq(priv->eq_table.eq[*prequested_vector].irq,
+ mlx4_msi_x_interrupt, 0,
+ &priv->eq_table.irq_names[*prequested_vector << 5],
+ priv->eq_table.eq + *prequested_vector);
+
+ if (err) {
+ clear_bit(*prequested_vector, priv->msix_ctl.pool_bm);
+ *prequested_vector = -1;
+ } else {
+#if defined(CONFIG_SMP)
+ mlx4_set_eq_affinity_hint(priv, *prequested_vector);
+#endif
+ eq_set_ci(&priv->eq_table.eq[*prequested_vector], 1);
+ priv->eq_table.eq[*prequested_vector].have_irq = 1;
}
}
+
+ if (!err && *prequested_vector >= 0)
+ priv->eq_table.eq[*prequested_vector].ref_count++;
+
+err_unlock:
mutex_unlock(&priv->msix_ctl.pool_lock);
- if (vec) {
- *vector = vec;
- } else {
+ if (!err && *prequested_vector >= 0)
+ *vector = MLX4_EQ_TO_CQ_VECTOR(*prequested_vector);
+ else
*vector = 0;
- err = (i == dev->caps.comp_pool) ? -ENOSPC : err;
- }
+
return err;
}
EXPORT_SYMBOL(mlx4_assign_eq);
-int mlx4_eq_get_irq(struct mlx4_dev *dev, int vec)
+int mlx4_eq_get_irq(struct mlx4_dev *dev, int cq_vec)
{
struct mlx4_priv *priv = mlx4_priv(dev);
- return priv->eq_table.eq[vec].irq;
+ return priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(cq_vec)].irq;
}
EXPORT_SYMBOL(mlx4_eq_get_irq);
void mlx4_release_eq(struct mlx4_dev *dev, int vec)
{
struct mlx4_priv *priv = mlx4_priv(dev);
- /*bm index*/
- int i = vec - dev->caps.num_comp_vectors - 1;
-
- if (likely(i >= 0)) {
- /*sanity check , making sure were not trying to free irq's
- Belonging to a legacy EQ*/
- mutex_lock(&priv->msix_ctl.pool_lock);
- if (priv->msix_ctl.pool_bm & 1ULL << i) {
- free_irq(priv->eq_table.eq[vec].irq,
- &priv->eq_table.eq[vec]);
- priv->msix_ctl.pool_bm &= ~(1ULL << i);
- }
- mutex_unlock(&priv->msix_ctl.pool_lock);
- }
+ int eq_vec = MLX4_CQ_TO_EQ_VECTOR(vec);
+ mutex_lock(&priv->msix_ctl.pool_lock);
+ priv->eq_table.eq[eq_vec].ref_count--;
+
+ /* once we allocated EQ, we don't release it because it might be binded
+ * to cpu_rmap.
+ */
+ mutex_unlock(&priv->msix_ctl.pool_lock);
}
EXPORT_SYMBOL(mlx4_release_eq);
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 70de39c6a397..12fbfcb44d8a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -479,7 +479,15 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
}
}
- dev->caps.max_counters = 1 << ilog2(dev_cap->max_counters);
+ if (mlx4_is_master(dev) && (dev->caps.num_ports == 2) &&
+ (port_type_array[0] == MLX4_PORT_TYPE_IB) &&
+ (port_type_array[1] == MLX4_PORT_TYPE_ETH)) {
+ mlx4_warn(dev,
+ "Granular QoS per VF not supported with IB/Eth configuration\n");
+ dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_QOS_VPP;
+ }
+
+ dev->caps.max_counters = dev_cap->max_counters;
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] = dev_cap->reserved_qps;
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] =
@@ -2212,20 +2220,73 @@ err_free_icm:
static int mlx4_init_counters_table(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
- int nent;
+ int nent_pow2;
if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS))
return -ENOENT;
- nent = dev->caps.max_counters;
- return mlx4_bitmap_init(&priv->counters_bitmap, nent, nent - 1, 0, 0);
+ if (!dev->caps.max_counters)
+ return -ENOSPC;
+
+ nent_pow2 = roundup_pow_of_two(dev->caps.max_counters);
+ /* reserve last counter index for sink counter */
+ return mlx4_bitmap_init(&priv->counters_bitmap, nent_pow2,
+ nent_pow2 - 1, 0,
+ nent_pow2 - dev->caps.max_counters + 1);
}
static void mlx4_cleanup_counters_table(struct mlx4_dev *dev)
{
+ if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS))
+ return;
+
+ if (!dev->caps.max_counters)
+ return;
+
mlx4_bitmap_cleanup(&mlx4_priv(dev)->counters_bitmap);
}
+static void mlx4_cleanup_default_counters(struct mlx4_dev *dev)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ int port;
+
+ for (port = 0; port < dev->caps.num_ports; port++)
+ if (priv->def_counter[port] != -1)
+ mlx4_counter_free(dev, priv->def_counter[port]);
+}
+
+static int mlx4_allocate_default_counters(struct mlx4_dev *dev)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ int port, err = 0;
+ u32 idx;
+
+ for (port = 0; port < dev->caps.num_ports; port++)
+ priv->def_counter[port] = -1;
+
+ for (port = 0; port < dev->caps.num_ports; port++) {
+ err = mlx4_counter_alloc(dev, &idx);
+
+ if (!err || err == -ENOSPC) {
+ priv->def_counter[port] = idx;
+ } else if (err == -ENOENT) {
+ err = 0;
+ continue;
+ } else {
+ mlx4_err(dev, "%s: failed to allocate default counter port %d err %d\n",
+ __func__, port + 1, err);
+ mlx4_cleanup_default_counters(dev);
+ return err;
+ }
+
+ mlx4_dbg(dev, "%s: default counter index %d for port %d\n",
+ __func__, priv->def_counter[port], port + 1);
+ }
+
+ return err;
+}
+
int __mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx)
{
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -2234,8 +2295,10 @@ int __mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx)
return -ENOENT;
*idx = mlx4_bitmap_alloc(&priv->counters_bitmap);
- if (*idx == -1)
- return -ENOMEM;
+ if (*idx == -1) {
+ *idx = MLX4_SINK_COUNTER_INDEX(dev);
+ return -ENOSPC;
+ }
return 0;
}
@@ -2258,8 +2321,35 @@ int mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx)
}
EXPORT_SYMBOL_GPL(mlx4_counter_alloc);
+static int __mlx4_clear_if_stat(struct mlx4_dev *dev,
+ u8 counter_index)
+{
+ struct mlx4_cmd_mailbox *if_stat_mailbox;
+ int err;
+ u32 if_stat_in_mod = (counter_index & 0xff) | MLX4_QUERY_IF_STAT_RESET;
+
+ if_stat_mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(if_stat_mailbox))
+ return PTR_ERR(if_stat_mailbox);
+
+ err = mlx4_cmd_box(dev, 0, if_stat_mailbox->dma, if_stat_in_mod, 0,
+ MLX4_CMD_QUERY_IF_STAT, MLX4_CMD_TIME_CLASS_C,
+ MLX4_CMD_NATIVE);
+
+ mlx4_free_cmd_mailbox(dev, if_stat_mailbox);
+ return err;
+}
+
void __mlx4_counter_free(struct mlx4_dev *dev, u32 idx)
{
+ if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS))
+ return;
+
+ if (idx == MLX4_SINK_COUNTER_INDEX(dev))
+ return;
+
+ __mlx4_clear_if_stat(dev, idx);
+
mlx4_bitmap_free(&mlx4_priv(dev)->counters_bitmap, idx, MLX4_USE_RR);
return;
}
@@ -2279,6 +2369,14 @@ void mlx4_counter_free(struct mlx4_dev *dev, u32 idx)
}
EXPORT_SYMBOL_GPL(mlx4_counter_free);
+int mlx4_get_default_counter_index(struct mlx4_dev *dev, int port)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+
+ return priv->def_counter[port - 1];
+}
+EXPORT_SYMBOL_GPL(mlx4_get_default_counter_index);
+
void mlx4_set_admin_guid(struct mlx4_dev *dev, __be64 guid, int entry, int port)
{
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -2383,11 +2481,11 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
if (err) {
if (dev->flags & MLX4_FLAG_MSI_X) {
mlx4_warn(dev, "NOP command failed to generate MSI-X interrupt IRQ %d)\n",
- priv->eq_table.eq[dev->caps.num_comp_vectors].irq);
+ priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
mlx4_warn(dev, "Trying again without MSI-X\n");
} else {
mlx4_err(dev, "NOP command failed to generate interrupt (IRQ %d), aborting\n",
- priv->eq_table.eq[dev->caps.num_comp_vectors].irq);
+ priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
mlx4_err(dev, "BIOS or ACPI interrupt routing problem?\n");
}
@@ -2414,10 +2512,18 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
goto err_srq_table_free;
}
- err = mlx4_init_counters_table(dev);
- if (err && err != -ENOENT) {
- mlx4_err(dev, "Failed to initialize counters table, aborting\n");
- goto err_qp_table_free;
+ if (!mlx4_is_slave(dev)) {
+ err = mlx4_init_counters_table(dev);
+ if (err && err != -ENOENT) {
+ mlx4_err(dev, "Failed to initialize counters table, aborting\n");
+ goto err_qp_table_free;
+ }
+ }
+
+ err = mlx4_allocate_default_counters(dev);
+ if (err) {
+ mlx4_err(dev, "Failed to allocate default counters, aborting\n");
+ goto err_counters_table_free;
}
if (!mlx4_is_slave(dev)) {
@@ -2451,15 +2557,19 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
if (err) {
mlx4_err(dev, "Failed to set port %d, aborting\n",
port);
- goto err_counters_table_free;
+ goto err_default_countes_free;
}
}
}
return 0;
+err_default_countes_free:
+ mlx4_cleanup_default_counters(dev);
+
err_counters_table_free:
- mlx4_cleanup_counters_table(dev);
+ if (!mlx4_is_slave(dev))
+ mlx4_cleanup_counters_table(dev);
err_qp_table_free:
mlx4_cleanup_qp_table(dev);
@@ -2500,14 +2610,45 @@ err_uar_table_free:
return err;
}
+static int mlx4_init_affinity_hint(struct mlx4_dev *dev, int port, int eqn)
+{
+ int requested_cpu = 0;
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_eq *eq;
+ int off = 0;
+ int i;
+
+ if (eqn > dev->caps.num_comp_vectors)
+ return -EINVAL;
+
+ for (i = 1; i < port; i++)
+ off += mlx4_get_eqs_per_port(dev, i);
+
+ requested_cpu = eqn - off - !!(eqn > MLX4_EQ_ASYNC);
+
+ /* Meaning EQs are shared, and this call comes from the second port */
+ if (requested_cpu < 0)
+ return 0;
+
+ eq = &priv->eq_table.eq[eqn];
+
+ if (!zalloc_cpumask_var(&eq->affinity_mask, GFP_KERNEL))
+ return -ENOMEM;
+
+ cpumask_set_cpu(requested_cpu, eq->affinity_mask);
+
+ return 0;
+}
+
static void mlx4_enable_msi_x(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct msix_entry *entries;
int i;
+ int port = 0;
if (msi_x) {
- int nreq = dev->caps.num_ports * num_online_cpus() + MSIX_LEGACY_SZ;
+ int nreq = dev->caps.num_ports * num_online_cpus() + 1;
nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs,
nreq);
@@ -2522,20 +2663,55 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
nreq = pci_enable_msix_range(dev->persist->pdev, entries, 2,
nreq);
- if (nreq < 0) {
+ if (nreq < 0 || nreq < MLX4_EQ_ASYNC) {
kfree(entries);
goto no_msi;
- } else if (nreq < MSIX_LEGACY_SZ +
- dev->caps.num_ports * MIN_MSIX_P_PORT) {
- /*Working in legacy mode , all EQ's shared*/
- dev->caps.comp_pool = 0;
- dev->caps.num_comp_vectors = nreq - 1;
- } else {
- dev->caps.comp_pool = nreq - MSIX_LEGACY_SZ;
- dev->caps.num_comp_vectors = MSIX_LEGACY_SZ - 1;
}
- for (i = 0; i < nreq; ++i)
- priv->eq_table.eq[i].irq = entries[i].vector;
+ /* 1 is reserved for events (asyncrounous EQ) */
+ dev->caps.num_comp_vectors = nreq - 1;
+
+ priv->eq_table.eq[MLX4_EQ_ASYNC].irq = entries[0].vector;
+ bitmap_zero(priv->eq_table.eq[MLX4_EQ_ASYNC].actv_ports.ports,
+ dev->caps.num_ports);
+
+ for (i = 0; i < dev->caps.num_comp_vectors + 1; i++) {
+ if (i == MLX4_EQ_ASYNC)
+ continue;
+
+ priv->eq_table.eq[i].irq =
+ entries[i + 1 - !!(i > MLX4_EQ_ASYNC)].vector;
+
+ if (MLX4_IS_LEGACY_EQ_MODE(dev->caps)) {
+ bitmap_fill(priv->eq_table.eq[i].actv_ports.ports,
+ dev->caps.num_ports);
+ /* We don't set affinity hint when there
+ * aren't enough EQs
+ */
+ } else {
+ set_bit(port,
+ priv->eq_table.eq[i].actv_ports.ports);
+ if (mlx4_init_affinity_hint(dev, port + 1, i))
+ mlx4_warn(dev, "Couldn't init hint cpumask for EQ %d\n",
+ i);
+ }
+ /* We divide the Eqs evenly between the two ports.
+ * (dev->caps.num_comp_vectors / dev->caps.num_ports)
+ * refers to the number of Eqs per port
+ * (i.e eqs_per_port). Theoretically, we would like to
+ * write something like (i + 1) % eqs_per_port == 0.
+ * However, since there's an asynchronous Eq, we have
+ * to skip over it by comparing this condition to
+ * !!((i + 1) > MLX4_EQ_ASYNC).
+ */
+ if ((dev->caps.num_comp_vectors > dev->caps.num_ports) &&
+ ((i + 1) %
+ (dev->caps.num_comp_vectors / dev->caps.num_ports)) ==
+ !!((i + 1) > MLX4_EQ_ASYNC))
+ /* If dev->caps.num_comp_vectors < dev->caps.num_ports,
+ * everything is shared anyway.
+ */
+ port++;
+ }
dev->flags |= MLX4_FLAG_MSI_X;
@@ -2545,10 +2721,15 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
no_msi:
dev->caps.num_comp_vectors = 1;
- dev->caps.comp_pool = 0;
- for (i = 0; i < 2; ++i)
+ BUG_ON(MLX4_EQ_ASYNC >= 2);
+ for (i = 0; i < 2; ++i) {
priv->eq_table.eq[i].irq = dev->persist->pdev->irq;
+ if (i != MLX4_EQ_ASYNC) {
+ bitmap_fill(priv->eq_table.eq[i].actv_ports.ports,
+ dev->caps.num_ports);
+ }
+ }
}
static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
@@ -2613,6 +2794,10 @@ static void mlx4_cleanup_port_info(struct mlx4_port_info *info)
device_remove_file(&info->dev->persist->pdev->dev, &info->port_attr);
device_remove_file(&info->dev->persist->pdev->dev,
&info->port_mtu_attr);
+#ifdef CONFIG_RFS_ACCEL
+ free_irq_cpu_rmap(info->rmap);
+ info->rmap = NULL;
+#endif
}
static int mlx4_init_steering(struct mlx4_dev *dev)
@@ -2768,6 +2953,7 @@ disable_sriov:
free_mem:
dev->persist->num_vfs = 0;
kfree(dev->dev_vfs);
+ dev->dev_vfs = NULL;
return dev_flags & ~MLX4_FLAG_MASTER;
}
@@ -2919,6 +3105,7 @@ slave_start:
existing_vfs,
reset_flow);
+ mlx4_close_fw(dev);
mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_ALL);
dev->flags = dev_flags;
if (!SRIOV_VALID_STATE(dev->flags)) {
@@ -3007,18 +3194,6 @@ slave_start:
/* In master functions, the communication channel must be initialized
* after obtaining its address from fw */
if (mlx4_is_master(dev)) {
- int ib_ports = 0;
-
- mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
- ib_ports++;
-
- if (ib_ports &&
- (num_vfs_argc > 1 || probe_vfs_argc > 1)) {
- mlx4_err(dev,
- "Invalid syntax of num_vfs/probe_vfs with IB port - single port VFs syntax is only supported when all ports are configured as ethernet\n");
- err = -EINVAL;
- goto err_close;
- }
if (dev->caps.num_ports < 2 &&
num_vfs_argc > 1) {
err = -EINVAL;
@@ -3055,7 +3230,7 @@ slave_start:
if (err)
goto err_master_mfunc;
- priv->msix_ctl.pool_bm = 0;
+ bitmap_zero(priv->msix_ctl.pool_bm, MAX_MSIX);
mutex_init(&priv->msix_ctl.pool_lock);
mlx4_enable_msi_x(dev);
@@ -3077,7 +3252,6 @@ slave_start:
!mlx4_is_mfunc(dev)) {
dev->flags &= ~MLX4_FLAG_MSI_X;
dev->caps.num_comp_vectors = 1;
- dev->caps.comp_pool = 0;
pci_disable_msix(pdev);
err = mlx4_setup_hca(dev);
}
@@ -3128,7 +3302,9 @@ err_port:
for (--port; port >= 1; --port)
mlx4_cleanup_port_info(&priv->port[port]);
- mlx4_cleanup_counters_table(dev);
+ mlx4_cleanup_default_counters(dev);
+ if (!mlx4_is_slave(dev))
+ mlx4_cleanup_counters_table(dev);
mlx4_cleanup_qp_table(dev);
mlx4_cleanup_srq_table(dev);
mlx4_cleanup_cq_table(dev);
@@ -3426,7 +3602,9 @@ static void mlx4_unload_one(struct pci_dev *pdev)
mlx4_free_resource_tracker(dev,
RES_TR_FREE_SLAVES_ONLY);
- mlx4_cleanup_counters_table(dev);
+ mlx4_cleanup_default_counters(dev);
+ if (!mlx4_is_slave(dev))
+ mlx4_cleanup_counters_table(dev);
mlx4_cleanup_qp_table(dev);
mlx4_cleanup_srq_table(dev);
mlx4_cleanup_cq_table(dev);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index 502d3dd2c888..a092c5c34d43 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -65,6 +65,8 @@
#define INIT_HCA_TPT_MW_ENABLE (1 << 7)
+#define MLX4_QUERY_IF_STAT_RESET BIT(31)
+
enum {
MLX4_HCR_BASE = 0x80680,
MLX4_HCR_SIZE = 0x0001c,
@@ -287,6 +289,12 @@ struct mlx4_icm_table {
#define MLX4_CQE_SIZE_MASK_STRIDE 0x3
#define MLX4_EQE_SIZE_MASK_STRIDE 0x30
+#define MLX4_EQ_ASYNC 0
+#define MLX4_EQ_TO_CQ_VECTOR(vector) ((vector) - \
+ !!((int)(vector) >= MLX4_EQ_ASYNC))
+#define MLX4_CQ_TO_EQ_VECTOR(vector) ((vector) + \
+ !!((int)(vector) >= MLX4_EQ_ASYNC))
+
/*
* Must be packed because mtt_seg is 64 bits but only aligned to 32 bits.
*/
@@ -391,6 +399,9 @@ struct mlx4_eq {
struct mlx4_buf_list *page_list;
struct mlx4_mtt mtt;
struct mlx4_eq_tasklet tasklet_ctx;
+ struct mlx4_active_ports actv_ports;
+ u32 ref_count;
+ cpumask_var_t affinity_mask;
};
struct mlx4_slave_eqe {
@@ -808,6 +819,7 @@ struct mlx4_port_info {
struct mlx4_vlan_table vlan_table;
struct mlx4_roce_gid_table gid_table;
int base_qpn;
+ struct cpu_rmap *rmap;
};
struct mlx4_sense {
@@ -818,7 +830,7 @@ struct mlx4_sense {
};
struct mlx4_msix_ctl {
- u64 pool_bm;
+ DECLARE_BITMAP(pool_bm, MAX_MSIX);
struct mutex pool_lock;
};
@@ -864,6 +876,7 @@ struct mlx4_priv {
struct mlx4_qp_table qp_table;
struct mlx4_mcg_table mcg_table;
struct mlx4_bitmap counters_bitmap;
+ int def_counter[MLX4_MAX_PORTS];
struct mlx4_catas_err catas_err;
@@ -997,6 +1010,8 @@ int __mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
int start_index, int npages, u64 *page_list);
int __mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx);
void __mlx4_counter_free(struct mlx4_dev *dev, u32 idx);
+int mlx4_calc_vf_counters(struct mlx4_dev *dev, int slave, int port,
+ struct mlx4_counter *data);
int __mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn);
void __mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index d021f079f181..d5f9adb6a784 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -338,7 +338,7 @@ struct mlx4_en_cq {
struct napi_struct napi;
int size;
int buf_size;
- unsigned vector;
+ int vector;
enum cq_type is_tx;
u16 moder_time;
u16 moder_cnt;
@@ -566,6 +566,7 @@ struct mlx4_en_priv {
#endif
struct mlx4_en_perf_stats pstats;
struct mlx4_en_pkt_stats pkstats;
+ struct mlx4_en_counter_stats pf_stats;
struct mlx4_en_flow_stats_rx rx_priority_flowstats[MLX4_NUM_PRIORITIES];
struct mlx4_en_flow_stats_tx tx_priority_flowstats[MLX4_NUM_PRIORITIES];
struct mlx4_en_flow_stats_rx rx_flowstats;
@@ -582,6 +583,7 @@ struct mlx4_en_priv {
int base_tx_qpn;
struct hlist_head mac_hash[MLX4_EN_MAC_HASH_SIZE];
struct hwtstamp_config hwtstamp_config;
+ u32 counter_index;
#ifdef CONFIG_MLX4_EN_DCB
struct ieee_ets ets;
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_stats.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_stats.h
index 00555832a4ae..7fd466c0b929 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_stats.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_stats.h
@@ -23,6 +23,14 @@ struct mlx4_en_pkt_stats {
#define NUM_PKT_STATS 43
};
+struct mlx4_en_counter_stats {
+ unsigned long rx_packets;
+ unsigned long rx_bytes;
+ unsigned long tx_packets;
+ unsigned long tx_bytes;
+#define NUM_PF_STATS 4
+};
+
struct mlx4_en_port_stats {
unsigned long tso_packets;
unsigned long xmit_more;
@@ -99,7 +107,7 @@ enum {
};
#define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + \
- NUM_FLOW_STATS + NUM_PERF_STATS)
+ NUM_FLOW_STATS + NUM_PERF_STATS + NUM_PF_STATS)
#define MLX4_FIND_NETDEV_STAT(n) (offsetof(struct net_device_stats, n) / \
sizeof(((struct net_device_stats *)0)->n))
diff --git a/drivers/net/ethernet/mellanox/mlx4/profile.c b/drivers/net/ethernet/mellanox/mlx4/profile.c
index 2bf437aafc53..bae8b22edbb7 100644
--- a/drivers/net/ethernet/mellanox/mlx4/profile.c
+++ b/drivers/net/ethernet/mellanox/mlx4/profile.c
@@ -82,7 +82,6 @@ u64 mlx4_make_profile(struct mlx4_dev *dev,
u64 total_size = 0;
struct mlx4_resource *profile;
- struct mlx4_resource tmp;
struct sysinfo si;
int i, j;
@@ -149,11 +148,8 @@ u64 mlx4_make_profile(struct mlx4_dev *dev,
*/
for (i = MLX4_RES_NUM; i > 0; --i)
for (j = 1; j < i; ++j) {
- if (profile[j].size > profile[j - 1].size) {
- tmp = profile[j];
- profile[j] = profile[j - 1];
- profile[j - 1] = tmp;
- }
+ if (profile[j].size > profile[j - 1].size)
+ swap(profile[j], profile[j - 1]);
}
for (i = 0; i < MLX4_RES_NUM; ++i) {
diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c
index b75214a80d0e..20268634a9ab 100644
--- a/drivers/net/ethernet/mellanox/mlx4/qp.c
+++ b/drivers/net/ethernet/mellanox/mlx4/qp.c
@@ -749,7 +749,7 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
{
int sort[MLX4_NUM_QP_REGION];
- int i, j, tmp;
+ int i, j;
int last_base = dev->caps.num_qps;
for (i = 1; i < MLX4_NUM_QP_REGION; ++i)
@@ -758,11 +758,8 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
for (i = MLX4_NUM_QP_REGION; i > MLX4_QP_REGION_BOTTOM; --i) {
for (j = MLX4_QP_REGION_BOTTOM + 2; j < i; ++j) {
if (dev->caps.reserved_qps_cnt[sort[j]] >
- dev->caps.reserved_qps_cnt[sort[j - 1]]) {
- tmp = sort[j];
- sort[j] = sort[j - 1];
- sort[j - 1] = tmp;
- }
+ dev->caps.reserved_qps_cnt[sort[j - 1]])
+ swap(sort[j], sort[j - 1]);
}
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index bafe2180cf0c..731423ca575d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -46,8 +46,11 @@
#include "mlx4.h"
#include "fw.h"
+#include "mlx4_stats.h"
#define MLX4_MAC_VALID (1ull << 63)
+#define MLX4_PF_COUNTERS_PER_PORT 2
+#define MLX4_VF_COUNTERS_PER_PORT 1
struct mac_res {
struct list_head list;
@@ -459,11 +462,21 @@ void mlx4_init_quotas(struct mlx4_dev *dev)
dev->quotas.mpt =
priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[pf];
}
+
+static int get_max_gauranteed_vfs_counter(struct mlx4_dev *dev)
+{
+ /* reduce the sink counter */
+ return (dev->caps.max_counters - 1 -
+ (MLX4_PF_COUNTERS_PER_PORT * MLX4_MAX_PORTS))
+ / MLX4_MAX_PORTS;
+}
+
int mlx4_init_resource_tracker(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int i, j;
int t;
+ int max_vfs_guarantee_counter = get_max_gauranteed_vfs_counter(dev);
priv->mfunc.master.res_tracker.slave_list =
kzalloc(dev->num_slaves * sizeof(struct slave_list),
@@ -499,6 +512,9 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev)
res_alloc->allocated = kzalloc((dev->persist->
num_vfs + 1) *
sizeof(int), GFP_KERNEL);
+ /* Reduce the sink counter */
+ if (i == RES_COUNTER)
+ res_alloc->res_free = dev->caps.max_counters - 1;
if (!res_alloc->quota || !res_alloc->guaranteed ||
!res_alloc->allocated)
@@ -577,9 +593,17 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev)
break;
case RES_COUNTER:
res_alloc->quota[t] = dev->caps.max_counters;
- res_alloc->guaranteed[t] = 0;
if (t == mlx4_master_func_num(dev))
- res_alloc->res_free = res_alloc->quota[t];
+ res_alloc->guaranteed[t] =
+ MLX4_PF_COUNTERS_PER_PORT *
+ MLX4_MAX_PORTS;
+ else if (t <= max_vfs_guarantee_counter)
+ res_alloc->guaranteed[t] =
+ MLX4_VF_COUNTERS_PER_PORT *
+ MLX4_MAX_PORTS;
+ else
+ res_alloc->guaranteed[t] = 0;
+ res_alloc->res_free -= res_alloc->guaranteed[t];
break;
default:
break;
@@ -700,6 +724,9 @@ static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox,
}
}
+static int handle_counter(struct mlx4_dev *dev, struct mlx4_qp_context *qpc,
+ u8 slave, int port);
+
static int update_vport_qp_param(struct mlx4_dev *dev,
struct mlx4_cmd_mailbox *inbox,
u8 slave, u32 qpn)
@@ -715,6 +742,10 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
+ err = handle_counter(dev, qpc, slave, port);
+ if (err)
+ goto out;
+
if (MLX4_VGT != vp_oper->state.default_vlan) {
/* the reserved QPs (special, proxy, tunnel)
* do not operate over vlans
@@ -859,6 +890,83 @@ static void put_res(struct mlx4_dev *dev, int slave, u64 res_id,
spin_unlock_irq(mlx4_tlock(dev));
}
+static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
+ u64 in_param, u64 *out_param, int port);
+
+static int handle_existing_counter(struct mlx4_dev *dev, u8 slave, int port,
+ int counter_index)
+{
+ struct res_common *r;
+ struct res_counter *counter;
+ int ret = 0;
+
+ if (counter_index == MLX4_SINK_COUNTER_INDEX(dev))
+ return ret;
+
+ spin_lock_irq(mlx4_tlock(dev));
+ r = find_res(dev, counter_index, RES_COUNTER);
+ if (!r || r->owner != slave)
+ ret = -EINVAL;
+ counter = container_of(r, struct res_counter, com);
+ if (!counter->port)
+ counter->port = port;
+
+ spin_unlock_irq(mlx4_tlock(dev));
+ return ret;
+}
+
+static int handle_unexisting_counter(struct mlx4_dev *dev,
+ struct mlx4_qp_context *qpc, u8 slave,
+ int port)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
+ struct res_common *tmp;
+ struct res_counter *counter;
+ u64 counter_idx = MLX4_SINK_COUNTER_INDEX(dev);
+ int err = 0;
+
+ spin_lock_irq(mlx4_tlock(dev));
+ list_for_each_entry(tmp,
+ &tracker->slave_list[slave].res_list[RES_COUNTER],
+ list) {
+ counter = container_of(tmp, struct res_counter, com);
+ if (port == counter->port) {
+ qpc->pri_path.counter_index = counter->com.res_id;
+ spin_unlock_irq(mlx4_tlock(dev));
+ return 0;
+ }
+ }
+ spin_unlock_irq(mlx4_tlock(dev));
+
+ /* No existing counter, need to allocate a new counter */
+ err = counter_alloc_res(dev, slave, RES_OP_RESERVE, 0, 0, &counter_idx,
+ port);
+ if (err == -ENOENT) {
+ err = 0;
+ } else if (err && err != -ENOSPC) {
+ mlx4_err(dev, "%s: failed to create new counter for slave %d err %d\n",
+ __func__, slave, err);
+ } else {
+ qpc->pri_path.counter_index = counter_idx;
+ mlx4_dbg(dev, "%s: alloc new counter for slave %d index %d\n",
+ __func__, slave, qpc->pri_path.counter_index);
+ err = 0;
+ }
+
+ return err;
+}
+
+static int handle_counter(struct mlx4_dev *dev, struct mlx4_qp_context *qpc,
+ u8 slave, int port)
+{
+ if (qpc->pri_path.counter_index != MLX4_SINK_COUNTER_INDEX(dev))
+ return handle_existing_counter(dev, slave, port,
+ qpc->pri_path.counter_index);
+
+ return handle_unexisting_counter(dev, qpc, slave, port);
+}
+
static struct res_common *alloc_qp_tr(int id)
{
struct res_qp *ret;
@@ -952,7 +1060,7 @@ static struct res_common *alloc_srq_tr(int id)
return &ret->com;
}
-static struct res_common *alloc_counter_tr(int id)
+static struct res_common *alloc_counter_tr(int id, int port)
{
struct res_counter *ret;
@@ -962,6 +1070,7 @@ static struct res_common *alloc_counter_tr(int id)
ret->com.res_id = id;
ret->com.state = RES_COUNTER_ALLOCATED;
+ ret->port = port;
return &ret->com;
}
@@ -1022,7 +1131,7 @@ static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave,
pr_err("implementation missing\n");
return NULL;
case RES_COUNTER:
- ret = alloc_counter_tr(id);
+ ret = alloc_counter_tr(id, extra);
break;
case RES_XRCD:
ret = alloc_xrcdn_tr(id);
@@ -1039,6 +1148,53 @@ static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave,
return ret;
}
+int mlx4_calc_vf_counters(struct mlx4_dev *dev, int slave, int port,
+ struct mlx4_counter *data)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
+ struct res_common *tmp;
+ struct res_counter *counter;
+ int *counters_arr;
+ int i = 0, err = 0;
+
+ memset(data, 0, sizeof(*data));
+
+ counters_arr = kmalloc_array(dev->caps.max_counters,
+ sizeof(*counters_arr), GFP_KERNEL);
+ if (!counters_arr)
+ return -ENOMEM;
+
+ spin_lock_irq(mlx4_tlock(dev));
+ list_for_each_entry(tmp,
+ &tracker->slave_list[slave].res_list[RES_COUNTER],
+ list) {
+ counter = container_of(tmp, struct res_counter, com);
+ if (counter->port == port) {
+ counters_arr[i] = (int)tmp->res_id;
+ i++;
+ }
+ }
+ spin_unlock_irq(mlx4_tlock(dev));
+ counters_arr[i] = -1;
+
+ i = 0;
+
+ while (counters_arr[i] != -1) {
+ err = mlx4_get_counter_stats(dev, counters_arr[i], data,
+ 0);
+ if (err) {
+ memset(data, 0, sizeof(*data));
+ goto table_changed;
+ }
+ i++;
+ }
+
+table_changed:
+ kfree(counters_arr);
+ return 0;
+}
+
static int add_res_range(struct mlx4_dev *dev, int slave, u64 base, int count,
enum mlx4_resource type, int extra)
{
@@ -2001,7 +2157,7 @@ static int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
}
static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
- u64 in_param, u64 *out_param)
+ u64 in_param, u64 *out_param, int port)
{
u32 index;
int err;
@@ -2019,7 +2175,7 @@ static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
return err;
}
- err = add_res_range(dev, slave, index, 1, RES_COUNTER, 0);
+ err = add_res_range(dev, slave, index, 1, RES_COUNTER, port);
if (err) {
__mlx4_counter_free(dev, index);
mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
@@ -2101,7 +2257,7 @@ int mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave,
case RES_COUNTER:
err = counter_alloc_res(dev, slave, vhcr->op_modifier, alop,
- vhcr->in_param, &vhcr->out_param);
+ vhcr->in_param, &vhcr->out_param, 0);
break;
case RES_XRCD:
@@ -2335,6 +2491,9 @@ static int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
return -EINVAL;
index = get_param_l(&in_param);
+ if (index == MLX4_SINK_COUNTER_INDEX(dev))
+ return 0;
+
err = rem_res_range(dev, slave, index, 1, RES_COUNTER, 0);
if (err)
return err;
@@ -2703,6 +2862,10 @@ static void adjust_proxy_tun_qkey(struct mlx4_dev *dev, struct mlx4_vhcr *vhcr,
context->qkey = cpu_to_be32(qkey);
}
+static int adjust_qp_sched_queue(struct mlx4_dev *dev, int slave,
+ struct mlx4_qp_context *qpc,
+ struct mlx4_cmd_mailbox *inbox);
+
int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
@@ -2725,6 +2888,10 @@ int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave,
struct res_srq *srq;
int local_qpn = be32_to_cpu(qpc->local_qpn) & 0xffffff;
+ err = adjust_qp_sched_queue(dev, slave, qpc, inbox);
+ if (err)
+ return err;
+
err = qp_res_start_move_to(dev, slave, qpn, RES_QP_HW, &qp, 0);
if (err)
return err;
@@ -3526,8 +3693,8 @@ static int adjust_qp_sched_queue(struct mlx4_dev *dev, int slave,
pri_sched_queue = (qpc->pri_path.sched_queue & ~(1 << 6)) |
((port & 1) << 6);
- if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH ||
- mlx4_is_eth(dev, port + 1)) {
+ if (optpar & (MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH | MLX4_QP_OPTPAR_SCHED_QUEUE) ||
+ qpc->pri_path.sched_queue || mlx4_is_eth(dev, port + 1)) {
qpc->pri_path.sched_queue = pri_sched_queue;
}
@@ -3965,6 +4132,22 @@ static int validate_eth_header_mac(int slave, struct _rule_hw *eth_header,
return 0;
}
+static void handle_eth_header_mcast_prio(struct mlx4_net_trans_rule_hw_ctrl *ctrl,
+ struct _rule_hw *eth_header)
+{
+ if (is_multicast_ether_addr(eth_header->eth.dst_mac) ||
+ is_broadcast_ether_addr(eth_header->eth.dst_mac)) {
+ struct mlx4_net_trans_rule_hw_eth *eth =
+ (struct mlx4_net_trans_rule_hw_eth *)eth_header;
+ struct _rule_hw *next_rule = (struct _rule_hw *)(eth + 1);
+ bool last_rule = next_rule->size == 0 && next_rule->id == 0 &&
+ next_rule->rsvd == 0;
+
+ if (last_rule)
+ ctrl->prio = cpu_to_be16(MLX4_DOMAIN_NIC);
+ }
+}
+
/*
* In case of missing eth header, append eth header with a MAC address
* assigned to the VF.
@@ -4117,6 +4300,12 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
rule_header = (struct _rule_hw *)(ctrl + 1);
header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id));
+ if (header_id == MLX4_NET_TRANS_RULE_ID_ETH)
+ handle_eth_header_mcast_prio(ctrl, rule_header);
+
+ if (slave == dev->caps.function)
+ goto execute;
+
switch (header_id) {
case MLX4_NET_TRANS_RULE_ID_ETH:
if (validate_eth_header_mac(slave, rule_header, rlist)) {
@@ -4143,6 +4332,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
goto err_put;
}
+execute:
err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param,
vhcr->in_modifier, 0,
MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
index 8ff57e8e3e91..158c88c69ef9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
@@ -3,6 +3,18 @@
#
config MLX5_CORE
- tristate
+ tristate "Mellanox Technologies ConnectX-4 and Connect-IB core driver"
depends on PCI
default n
+ ---help---
+ Core driver for low level functionality of the ConnectX-4 and
+ Connect-IB cards by Mellanox Technologies.
+
+config MLX5_CORE_EN
+ bool "Mellanox Technologies ConnectX-4 Ethernet support"
+ depends on NETDEVICES && ETHERNET && PCI && MLX5_CORE
+ default n
+ ---help---
+ Ethernet support in Mellanox Technologies ConnectX-4 NIC.
+ Ethernet and Infiniband support in ConnectX-4 are currently mutually
+ exclusive.
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
index 105780bb980b..26a68b8af2c5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -2,4 +2,7 @@ obj-$(CONFIG_MLX5_CORE) += mlx5_core.o
mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \
- mad.o
+ mad.o transobj.o vport.o
+mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o flow_table.o \
+ en_main.o en_flow_table.o en_ethtool.o en_tx.o en_rx.o \
+ en_txrx.o
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c
index ac0f7bf4be95..0715b497511f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c
@@ -42,95 +42,36 @@
#include "mlx5_core.h"
/* Handling for queue buffers -- we allocate a bunch of memory and
- * register it in a memory region at HCA virtual address 0. If the
- * requested size is > max_direct, we split the allocation into
- * multiple pages, so we don't require too much contiguous memory.
+ * register it in a memory region at HCA virtual address 0.
*/
-int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, int max_direct,
- struct mlx5_buf *buf)
+int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf)
{
dma_addr_t t;
buf->size = size;
- if (size <= max_direct) {
- buf->nbufs = 1;
- buf->npages = 1;
- buf->page_shift = (u8)get_order(size) + PAGE_SHIFT;
- buf->direct.buf = dma_zalloc_coherent(&dev->pdev->dev,
- size, &t, GFP_KERNEL);
- if (!buf->direct.buf)
- return -ENOMEM;
-
- buf->direct.map = t;
-
- while (t & ((1 << buf->page_shift) - 1)) {
- --buf->page_shift;
- buf->npages *= 2;
- }
- } else {
- int i;
-
- buf->direct.buf = NULL;
- buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE;
- buf->npages = buf->nbufs;
- buf->page_shift = PAGE_SHIFT;
- buf->page_list = kcalloc(buf->nbufs, sizeof(*buf->page_list),
- GFP_KERNEL);
- if (!buf->page_list)
- return -ENOMEM;
-
- for (i = 0; i < buf->nbufs; i++) {
- buf->page_list[i].buf =
- dma_zalloc_coherent(&dev->pdev->dev, PAGE_SIZE,
- &t, GFP_KERNEL);
- if (!buf->page_list[i].buf)
- goto err_free;
-
- buf->page_list[i].map = t;
- }
-
- if (BITS_PER_LONG == 64) {
- struct page **pages;
- pages = kmalloc(sizeof(*pages) * buf->nbufs, GFP_KERNEL);
- if (!pages)
- goto err_free;
- for (i = 0; i < buf->nbufs; i++)
- pages[i] = virt_to_page(buf->page_list[i].buf);
- buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL);
- kfree(pages);
- if (!buf->direct.buf)
- goto err_free;
- }
- }
+ buf->npages = 1;
+ buf->page_shift = (u8)get_order(size) + PAGE_SHIFT;
+ buf->direct.buf = dma_zalloc_coherent(&dev->pdev->dev,
+ size, &t, GFP_KERNEL);
+ if (!buf->direct.buf)
+ return -ENOMEM;
- return 0;
+ buf->direct.map = t;
-err_free:
- mlx5_buf_free(dev, buf);
+ while (t & ((1 << buf->page_shift) - 1)) {
+ --buf->page_shift;
+ buf->npages *= 2;
+ }
- return -ENOMEM;
+ return 0;
}
EXPORT_SYMBOL_GPL(mlx5_buf_alloc);
void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf)
{
- int i;
-
- if (buf->nbufs == 1)
- dma_free_coherent(&dev->pdev->dev, buf->size, buf->direct.buf,
- buf->direct.map);
- else {
- if (BITS_PER_LONG == 64)
- vunmap(buf->direct.buf);
-
- for (i = 0; i < buf->nbufs; i++)
- if (buf->page_list[i].buf)
- dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
- buf->page_list[i].buf,
- buf->page_list[i].map);
- kfree(buf->page_list);
- }
+ dma_free_coherent(&dev->pdev->dev, buf->size, buf->direct.buf,
+ buf->direct.map);
}
EXPORT_SYMBOL_GPL(mlx5_buf_free);
@@ -230,10 +171,7 @@ void mlx5_fill_page_array(struct mlx5_buf *buf, __be64 *pas)
int i;
for (i = 0; i < buf->npages; i++) {
- if (buf->nbufs == 1)
- addr = buf->direct.map + (i << buf->page_shift);
- else
- addr = buf->page_list[i].map;
+ addr = buf->direct.map + (i << buf->page_shift);
pas[i] = cpu_to_be64(addr);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index e3273faf4568..75ff58dc1ff5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -75,25 +75,6 @@ enum {
MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR = 0x10,
};
-enum {
- MLX5_CMD_STAT_OK = 0x0,
- MLX5_CMD_STAT_INT_ERR = 0x1,
- MLX5_CMD_STAT_BAD_OP_ERR = 0x2,
- MLX5_CMD_STAT_BAD_PARAM_ERR = 0x3,
- MLX5_CMD_STAT_BAD_SYS_STATE_ERR = 0x4,
- MLX5_CMD_STAT_BAD_RES_ERR = 0x5,
- MLX5_CMD_STAT_RES_BUSY = 0x6,
- MLX5_CMD_STAT_LIM_ERR = 0x8,
- MLX5_CMD_STAT_BAD_RES_STATE_ERR = 0x9,
- MLX5_CMD_STAT_IX_ERR = 0xa,
- MLX5_CMD_STAT_NO_RES_ERR = 0xf,
- MLX5_CMD_STAT_BAD_INP_LEN_ERR = 0x50,
- MLX5_CMD_STAT_BAD_OUTP_LEN_ERR = 0x51,
- MLX5_CMD_STAT_BAD_QP_STATE_ERR = 0x10,
- MLX5_CMD_STAT_BAD_PKT_ERR = 0x30,
- MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR = 0x40,
-};
-
static struct mlx5_cmd_work_ent *alloc_cmd(struct mlx5_cmd *cmd,
struct mlx5_cmd_msg *in,
struct mlx5_cmd_msg *out,
@@ -390,8 +371,17 @@ const char *mlx5_command_str(int command)
case MLX5_CMD_OP_ARM_RQ:
return "ARM_RQ";
- case MLX5_CMD_OP_RESIZE_SRQ:
- return "RESIZE_SRQ";
+ case MLX5_CMD_OP_CREATE_XRC_SRQ:
+ return "CREATE_XRC_SRQ";
+
+ case MLX5_CMD_OP_DESTROY_XRC_SRQ:
+ return "DESTROY_XRC_SRQ";
+
+ case MLX5_CMD_OP_QUERY_XRC_SRQ:
+ return "QUERY_XRC_SRQ";
+
+ case MLX5_CMD_OP_ARM_XRC_SRQ:
+ return "ARM_XRC_SRQ";
case MLX5_CMD_OP_ALLOC_PD:
return "ALLOC_PD";
@@ -408,8 +398,8 @@ const char *mlx5_command_str(int command)
case MLX5_CMD_OP_ATTACH_TO_MCG:
return "ATTACH_TO_MCG";
- case MLX5_CMD_OP_DETACH_FROM_MCG:
- return "DETACH_FROM_MCG";
+ case MLX5_CMD_OP_DETTACH_FROM_MCG:
+ return "DETTACH_FROM_MCG";
case MLX5_CMD_OP_ALLOC_XRCD:
return "ALLOC_XRCD";
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
index eb0cf81f5f45..04ab7e445eae 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
@@ -219,6 +219,24 @@ int mlx5_core_modify_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
}
EXPORT_SYMBOL(mlx5_core_modify_cq);
+int mlx5_core_modify_cq_moderation(struct mlx5_core_dev *dev,
+ struct mlx5_core_cq *cq,
+ u16 cq_period,
+ u16 cq_max_count)
+{
+ struct mlx5_modify_cq_mbox_in in;
+
+ memset(&in, 0, sizeof(in));
+
+ in.cqn = cpu_to_be32(cq->cqn);
+ in.ctx.cq_period = cpu_to_be16(cq_period);
+ in.ctx.cq_max_count = cpu_to_be16(cq_max_count);
+ in.field_select = cpu_to_be32(MLX5_CQ_MODIFY_PERIOD |
+ MLX5_CQ_MODIFY_COUNT);
+
+ return mlx5_core_modify_cq(dev, cq, &in, sizeof(in));
+}
+
int mlx5_init_cq_table(struct mlx5_core_dev *dev)
{
struct mlx5_cq_table *table = &dev->priv.cq_table;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
new file mode 100644
index 000000000000..3d23bd657e3c
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ */
+
+#include <linux/if_vlan.h>
+#include <linux/etherdevice.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/qp.h>
+#include <linux/mlx5/cq.h>
+#include <linux/mlx5/vport.h>
+#include "wq.h"
+#include "transobj.h"
+#include "mlx5_core.h"
+
+#define MLX5E_MAX_NUM_TC 8
+
+#define MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE 0x7
+#define MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE 0xa
+#define MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE 0xd
+
+#define MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE 0x7
+#define MLX5E_PARAMS_DEFAULT_LOG_RQ_SIZE 0xa
+#define MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE 0xd
+
+#define MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ (16 * 1024)
+#define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC 0x10
+#define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS 0x20
+#define MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_USEC 0x10
+#define MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_PKTS 0x20
+#define MLX5E_PARAMS_DEFAULT_MIN_RX_WQES 0x80
+#define MLX5E_PARAMS_DEFAULT_RX_HASH_LOG_TBL_SZ 0x7
+
+#define MLX5E_TX_CQ_POLL_BUDGET 128
+#define MLX5E_UPDATE_STATS_INTERVAL 200 /* msecs */
+
+static const char vport_strings[][ETH_GSTRING_LEN] = {
+ /* vport statistics */
+ "rx_packets",
+ "rx_bytes",
+ "tx_packets",
+ "tx_bytes",
+ "rx_error_packets",
+ "rx_error_bytes",
+ "tx_error_packets",
+ "tx_error_bytes",
+ "rx_unicast_packets",
+ "rx_unicast_bytes",
+ "tx_unicast_packets",
+ "tx_unicast_bytes",
+ "rx_multicast_packets",
+ "rx_multicast_bytes",
+ "tx_multicast_packets",
+ "tx_multicast_bytes",
+ "rx_broadcast_packets",
+ "rx_broadcast_bytes",
+ "tx_broadcast_packets",
+ "tx_broadcast_bytes",
+
+ /* SW counters */
+ "tso_packets",
+ "tso_bytes",
+ "lro_packets",
+ "lro_bytes",
+ "rx_csum_good",
+ "rx_csum_none",
+ "tx_csum_offload",
+ "tx_queue_stopped",
+ "tx_queue_wake",
+ "tx_queue_dropped",
+ "rx_wqe_err",
+};
+
+struct mlx5e_vport_stats {
+ /* HW counters */
+ u64 rx_packets;
+ u64 rx_bytes;
+ u64 tx_packets;
+ u64 tx_bytes;
+ u64 rx_error_packets;
+ u64 rx_error_bytes;
+ u64 tx_error_packets;
+ u64 tx_error_bytes;
+ u64 rx_unicast_packets;
+ u64 rx_unicast_bytes;
+ u64 tx_unicast_packets;
+ u64 tx_unicast_bytes;
+ u64 rx_multicast_packets;
+ u64 rx_multicast_bytes;
+ u64 tx_multicast_packets;
+ u64 tx_multicast_bytes;
+ u64 rx_broadcast_packets;
+ u64 rx_broadcast_bytes;
+ u64 tx_broadcast_packets;
+ u64 tx_broadcast_bytes;
+
+ /* SW counters */
+ u64 tso_packets;
+ u64 tso_bytes;
+ u64 lro_packets;
+ u64 lro_bytes;
+ u64 rx_csum_good;
+ u64 rx_csum_none;
+ u64 tx_csum_offload;
+ u64 tx_queue_stopped;
+ u64 tx_queue_wake;
+ u64 tx_queue_dropped;
+ u64 rx_wqe_err;
+
+#define NUM_VPORT_COUNTERS 31
+};
+
+static const char rq_stats_strings[][ETH_GSTRING_LEN] = {
+ "packets",
+ "csum_none",
+ "lro_packets",
+ "lro_bytes",
+ "wqe_err"
+};
+
+struct mlx5e_rq_stats {
+ u64 packets;
+ u64 csum_none;
+ u64 lro_packets;
+ u64 lro_bytes;
+ u64 wqe_err;
+#define NUM_RQ_STATS 5
+};
+
+static const char sq_stats_strings[][ETH_GSTRING_LEN] = {
+ "packets",
+ "tso_packets",
+ "tso_bytes",
+ "csum_offload_none",
+ "stopped",
+ "wake",
+ "dropped",
+ "nop"
+};
+
+struct mlx5e_sq_stats {
+ u64 packets;
+ u64 tso_packets;
+ u64 tso_bytes;
+ u64 csum_offload_none;
+ u64 stopped;
+ u64 wake;
+ u64 dropped;
+ u64 nop;
+#define NUM_SQ_STATS 8
+};
+
+struct mlx5e_stats {
+ struct mlx5e_vport_stats vport;
+};
+
+struct mlx5e_params {
+ u8 log_sq_size;
+ u8 log_rq_size;
+ u16 num_channels;
+ u8 default_vlan_prio;
+ u8 num_tc;
+ u16 rx_cq_moderation_usec;
+ u16 rx_cq_moderation_pkts;
+ u16 tx_cq_moderation_usec;
+ u16 tx_cq_moderation_pkts;
+ u16 min_rx_wqes;
+ u16 rx_hash_log_tbl_sz;
+ bool lro_en;
+ u32 lro_wqe_sz;
+};
+
+enum {
+ MLX5E_RQ_STATE_POST_WQES_ENABLE,
+};
+
+enum cq_flags {
+ MLX5E_CQ_HAS_CQES = 1,
+};
+
+struct mlx5e_cq {
+ /* data path - accessed per cqe */
+ struct mlx5_cqwq wq;
+ unsigned long flags;
+
+ /* data path - accessed per napi poll */
+ struct napi_struct *napi;
+ struct mlx5_core_cq mcq;
+ struct mlx5e_channel *channel;
+
+ /* control */
+ struct mlx5_wq_ctrl wq_ctrl;
+} ____cacheline_aligned_in_smp;
+
+struct mlx5e_rq {
+ /* data path */
+ struct mlx5_wq_ll wq;
+ u32 wqe_sz;
+ struct sk_buff **skb;
+
+ struct device *pdev;
+ struct net_device *netdev;
+ struct mlx5e_rq_stats stats;
+ struct mlx5e_cq cq;
+
+ unsigned long state;
+ int ix;
+
+ /* control */
+ struct mlx5_wq_ctrl wq_ctrl;
+ u32 rqn;
+ struct mlx5e_channel *channel;
+} ____cacheline_aligned_in_smp;
+
+struct mlx5e_tx_skb_cb {
+ u32 num_bytes;
+ u8 num_wqebbs;
+ u8 num_dma;
+};
+
+#define MLX5E_TX_SKB_CB(__skb) ((struct mlx5e_tx_skb_cb *)__skb->cb)
+
+struct mlx5e_sq_dma {
+ dma_addr_t addr;
+ u32 size;
+};
+
+enum {
+ MLX5E_SQ_STATE_WAKE_TXQ_ENABLE,
+};
+
+struct mlx5e_sq {
+ /* data path */
+
+ /* dirtied @completion */
+ u16 cc;
+ u32 dma_fifo_cc;
+
+ /* dirtied @xmit */
+ u16 pc ____cacheline_aligned_in_smp;
+ u32 dma_fifo_pc;
+ u32 bf_offset;
+ struct mlx5e_sq_stats stats;
+
+ struct mlx5e_cq cq;
+
+ /* pointers to per packet info: write@xmit, read@completion */
+ struct sk_buff **skb;
+ struct mlx5e_sq_dma *dma_fifo;
+
+ /* read only */
+ struct mlx5_wq_cyc wq;
+ u32 dma_fifo_mask;
+ void __iomem *uar_map;
+ struct netdev_queue *txq;
+ u32 sqn;
+ u32 bf_buf_size;
+ u16 max_inline;
+ u16 edge;
+ struct device *pdev;
+ __be32 mkey_be;
+ unsigned long state;
+
+ /* control path */
+ struct mlx5_wq_ctrl wq_ctrl;
+ struct mlx5_uar uar;
+ struct mlx5e_channel *channel;
+ int tc;
+} ____cacheline_aligned_in_smp;
+
+static inline bool mlx5e_sq_has_room_for(struct mlx5e_sq *sq, u16 n)
+{
+ return (((sq->wq.sz_m1 & (sq->cc - sq->pc)) >= n) ||
+ (sq->cc == sq->pc));
+}
+
+enum channel_flags {
+ MLX5E_CHANNEL_NAPI_SCHED = 1,
+};
+
+struct mlx5e_channel {
+ /* data path */
+ struct mlx5e_rq rq;
+ struct mlx5e_sq sq[MLX5E_MAX_NUM_TC];
+ struct napi_struct napi;
+ struct device *pdev;
+ struct net_device *netdev;
+ __be32 mkey_be;
+ u8 num_tc;
+ unsigned long flags;
+ int tc_to_txq_map[MLX5E_MAX_NUM_TC];
+
+ /* control */
+ struct mlx5e_priv *priv;
+ int ix;
+ int cpu;
+};
+
+enum mlx5e_traffic_types {
+ MLX5E_TT_IPV4_TCP = 0,
+ MLX5E_TT_IPV6_TCP = 1,
+ MLX5E_TT_IPV4_UDP = 2,
+ MLX5E_TT_IPV6_UDP = 3,
+ MLX5E_TT_IPV4 = 4,
+ MLX5E_TT_IPV6 = 5,
+ MLX5E_TT_ANY = 6,
+ MLX5E_NUM_TT = 7,
+};
+
+enum {
+ MLX5E_RQT_SPREADING = 0,
+ MLX5E_RQT_DEFAULT_RQ = 1,
+ MLX5E_NUM_RQT = 2,
+};
+
+struct mlx5e_eth_addr_info {
+ u8 addr[ETH_ALEN + 2];
+ u32 tt_vec;
+ u32 ft_ix[MLX5E_NUM_TT]; /* flow table index per traffic type */
+};
+
+#define MLX5E_ETH_ADDR_HASH_SIZE (1 << BITS_PER_BYTE)
+
+struct mlx5e_eth_addr_db {
+ struct hlist_head netdev_uc[MLX5E_ETH_ADDR_HASH_SIZE];
+ struct hlist_head netdev_mc[MLX5E_ETH_ADDR_HASH_SIZE];
+ struct mlx5e_eth_addr_info broadcast;
+ struct mlx5e_eth_addr_info allmulti;
+ struct mlx5e_eth_addr_info promisc;
+ bool broadcast_enabled;
+ bool allmulti_enabled;
+ bool promisc_enabled;
+};
+
+enum {
+ MLX5E_STATE_ASYNC_EVENTS_ENABLE,
+ MLX5E_STATE_OPENED,
+};
+
+struct mlx5e_vlan_db {
+ unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+ u32 active_vlans_ft_ix[VLAN_N_VID];
+ u32 untagged_rule_ft_ix;
+ u32 any_vlan_rule_ft_ix;
+ bool filter_disabled;
+};
+
+struct mlx5e_flow_table {
+ void *vlan;
+ void *main;
+};
+
+struct mlx5e_priv {
+ /* priv data path fields - start */
+ int num_tc;
+ int default_vlan_prio;
+ struct mlx5e_sq **txq_to_sq_map;
+ /* priv data path fields - end */
+
+ unsigned long state;
+ struct mutex state_lock; /* Protects Interface state */
+ struct mlx5_uar cq_uar;
+ u32 pdn;
+ u32 tdn;
+ struct mlx5_core_mr mr;
+
+ struct mlx5e_channel **channel;
+ u32 tisn[MLX5E_MAX_NUM_TC];
+ u32 rqtn;
+ u32 tirn[MLX5E_NUM_TT];
+
+ struct mlx5e_flow_table ft;
+ struct mlx5e_eth_addr_db eth_addr;
+ struct mlx5e_vlan_db vlan;
+
+ struct mlx5e_params params;
+ spinlock_t async_events_spinlock; /* sync hw events */
+ struct work_struct update_carrier_work;
+ struct work_struct set_rx_mode_work;
+ struct delayed_work update_stats_work;
+
+ struct mlx5_core_dev *mdev;
+ struct net_device *netdev;
+ struct mlx5e_stats stats;
+};
+
+#define MLX5E_NET_IP_ALIGN 2
+
+struct mlx5e_tx_wqe {
+ struct mlx5_wqe_ctrl_seg ctrl;
+ struct mlx5_wqe_eth_seg eth;
+};
+
+struct mlx5e_rx_wqe {
+ struct mlx5_wqe_srq_next_seg next;
+ struct mlx5_wqe_data_seg data;
+};
+
+enum mlx5e_link_mode {
+ MLX5E_1000BASE_CX_SGMII = 0,
+ MLX5E_1000BASE_KX = 1,
+ MLX5E_10GBASE_CX4 = 2,
+ MLX5E_10GBASE_KX4 = 3,
+ MLX5E_10GBASE_KR = 4,
+ MLX5E_20GBASE_KR2 = 5,
+ MLX5E_40GBASE_CR4 = 6,
+ MLX5E_40GBASE_KR4 = 7,
+ MLX5E_56GBASE_R4 = 8,
+ MLX5E_10GBASE_CR = 12,
+ MLX5E_10GBASE_SR = 13,
+ MLX5E_10GBASE_ER = 14,
+ MLX5E_40GBASE_SR4 = 15,
+ MLX5E_40GBASE_LR4 = 16,
+ MLX5E_100GBASE_CR4 = 20,
+ MLX5E_100GBASE_SR4 = 21,
+ MLX5E_100GBASE_KR4 = 22,
+ MLX5E_100GBASE_LR4 = 23,
+ MLX5E_100BASE_TX = 24,
+ MLX5E_100BASE_T = 25,
+ MLX5E_10GBASE_T = 26,
+ MLX5E_25GBASE_CR = 27,
+ MLX5E_25GBASE_KR = 28,
+ MLX5E_25GBASE_SR = 29,
+ MLX5E_50GBASE_CR2 = 30,
+ MLX5E_50GBASE_KR2 = 31,
+ MLX5E_LINK_MODES_NUMBER,
+};
+
+#define MLX5E_PROT_MASK(link_mode) (1 << link_mode)
+
+void mlx5e_send_nop(struct mlx5e_sq *sq, bool notify_hw);
+u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb,
+ void *accel_priv, select_queue_fallback_t fallback);
+netdev_tx_t mlx5e_xmit(struct sk_buff *skb, struct net_device *dev);
+
+void mlx5e_completion_event(struct mlx5_core_cq *mcq);
+void mlx5e_cq_error_event(struct mlx5_core_cq *mcq, enum mlx5_event event);
+int mlx5e_napi_poll(struct napi_struct *napi, int budget);
+bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq);
+bool mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget);
+bool mlx5e_post_rx_wqes(struct mlx5e_rq *rq);
+struct mlx5_cqe64 *mlx5e_get_cqe(struct mlx5e_cq *cq);
+
+void mlx5e_update_stats(struct mlx5e_priv *priv);
+
+int mlx5e_open_flow_table(struct mlx5e_priv *priv);
+void mlx5e_close_flow_table(struct mlx5e_priv *priv);
+void mlx5e_init_eth_addr(struct mlx5e_priv *priv);
+void mlx5e_set_rx_mode_core(struct mlx5e_priv *priv);
+void mlx5e_set_rx_mode_work(struct work_struct *work);
+
+int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto,
+ u16 vid);
+int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto,
+ u16 vid);
+void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv);
+void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv);
+int mlx5e_add_all_vlan_rules(struct mlx5e_priv *priv);
+void mlx5e_del_all_vlan_rules(struct mlx5e_priv *priv);
+
+int mlx5e_open_locked(struct net_device *netdev);
+int mlx5e_close_locked(struct net_device *netdev);
+int mlx5e_update_priv_params(struct mlx5e_priv *priv,
+ struct mlx5e_params *new_params);
+
+static inline void mlx5e_tx_notify_hw(struct mlx5e_sq *sq,
+ struct mlx5e_tx_wqe *wqe)
+{
+ /* ensure wqe is visible to device before updating doorbell record */
+ dma_wmb();
+
+ *sq->wq.db = cpu_to_be32(sq->pc);
+
+ /* ensure doorbell record is visible to device before ringing the
+ * doorbell
+ */
+ wmb();
+
+ mlx5_write64((__be32 *)&wqe->ctrl,
+ sq->uar_map + MLX5_BF_OFFSET + sq->bf_offset,
+ NULL);
+
+ sq->bf_offset ^= sq->bf_buf_size;
+}
+
+static inline void mlx5e_cq_arm(struct mlx5e_cq *cq)
+{
+ struct mlx5_core_cq *mcq;
+
+ mcq = &cq->mcq;
+ mlx5_cq_arm(mcq, MLX5_CQ_DB_REQ_NOT, mcq->uar->map, NULL, cq->wq.cc);
+}
+
+extern const struct ethtool_ops mlx5e_ethtool_ops;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
new file mode 100644
index 000000000000..388938482ff9
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -0,0 +1,679 @@
+/*
+ * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ */
+
+#include "en.h"
+
+static void mlx5e_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+ struct mlx5_core_dev *mdev = priv->mdev;
+
+ strlcpy(drvinfo->driver, DRIVER_NAME, sizeof(drvinfo->driver));
+ strlcpy(drvinfo->version, DRIVER_VERSION " (" DRIVER_RELDATE ")",
+ sizeof(drvinfo->version));
+ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+ "%d.%d.%d",
+ fw_rev_maj(mdev), fw_rev_min(mdev), fw_rev_sub(mdev));
+ strlcpy(drvinfo->bus_info, pci_name(mdev->pdev),
+ sizeof(drvinfo->bus_info));
+}
+
+static const struct {
+ u32 supported;
+ u32 advertised;
+ u32 speed;
+} ptys2ethtool_table[MLX5E_LINK_MODES_NUMBER] = {
+ [MLX5E_1000BASE_CX_SGMII] = {
+ .supported = SUPPORTED_1000baseKX_Full,
+ .advertised = ADVERTISED_1000baseKX_Full,
+ .speed = 1000,
+ },
+ [MLX5E_1000BASE_KX] = {
+ .supported = SUPPORTED_1000baseKX_Full,
+ .advertised = ADVERTISED_1000baseKX_Full,
+ .speed = 1000,
+ },
+ [MLX5E_10GBASE_CX4] = {
+ .supported = SUPPORTED_10000baseKX4_Full,
+ .advertised = ADVERTISED_10000baseKX4_Full,
+ .speed = 10000,
+ },
+ [MLX5E_10GBASE_KX4] = {
+ .supported = SUPPORTED_10000baseKX4_Full,
+ .advertised = ADVERTISED_10000baseKX4_Full,
+ .speed = 10000,
+ },
+ [MLX5E_10GBASE_KR] = {
+ .supported = SUPPORTED_10000baseKR_Full,
+ .advertised = ADVERTISED_10000baseKR_Full,
+ .speed = 10000,
+ },
+ [MLX5E_20GBASE_KR2] = {
+ .supported = SUPPORTED_20000baseKR2_Full,
+ .advertised = ADVERTISED_20000baseKR2_Full,
+ .speed = 20000,
+ },
+ [MLX5E_40GBASE_CR4] = {
+ .supported = SUPPORTED_40000baseCR4_Full,
+ .advertised = ADVERTISED_40000baseCR4_Full,
+ .speed = 40000,
+ },
+ [MLX5E_40GBASE_KR4] = {
+ .supported = SUPPORTED_40000baseKR4_Full,
+ .advertised = ADVERTISED_40000baseKR4_Full,
+ .speed = 40000,
+ },
+ [MLX5E_56GBASE_R4] = {
+ .supported = SUPPORTED_56000baseKR4_Full,
+ .advertised = ADVERTISED_56000baseKR4_Full,
+ .speed = 56000,
+ },
+ [MLX5E_10GBASE_CR] = {
+ .supported = SUPPORTED_10000baseKR_Full,
+ .advertised = ADVERTISED_10000baseKR_Full,
+ .speed = 10000,
+ },
+ [MLX5E_10GBASE_SR] = {
+ .supported = SUPPORTED_10000baseKR_Full,
+ .advertised = ADVERTISED_10000baseKR_Full,
+ .speed = 10000,
+ },
+ [MLX5E_10GBASE_ER] = {
+ .supported = SUPPORTED_10000baseKR_Full,
+ .advertised = ADVERTISED_10000baseKR_Full,
+ .speed = 10000,
+ },
+ [MLX5E_40GBASE_SR4] = {
+ .supported = SUPPORTED_40000baseSR4_Full,
+ .advertised = ADVERTISED_40000baseSR4_Full,
+ .speed = 40000,
+ },
+ [MLX5E_40GBASE_LR4] = {
+ .supported = SUPPORTED_40000baseLR4_Full,
+ .advertised = ADVERTISED_40000baseLR4_Full,
+ .speed = 40000,
+ },
+ [MLX5E_100GBASE_CR4] = {
+ .speed = 100000,
+ },
+ [MLX5E_100GBASE_SR4] = {
+ .speed = 100000,
+ },
+ [MLX5E_100GBASE_KR4] = {
+ .speed = 100000,
+ },
+ [MLX5E_100GBASE_LR4] = {
+ .speed = 100000,
+ },
+ [MLX5E_100BASE_TX] = {
+ .speed = 100,
+ },
+ [MLX5E_100BASE_T] = {
+ .supported = SUPPORTED_100baseT_Full,
+ .advertised = ADVERTISED_100baseT_Full,
+ .speed = 100,
+ },
+ [MLX5E_10GBASE_T] = {
+ .supported = SUPPORTED_10000baseT_Full,
+ .advertised = ADVERTISED_10000baseT_Full,
+ .speed = 1000,
+ },
+ [MLX5E_25GBASE_CR] = {
+ .speed = 25000,
+ },
+ [MLX5E_25GBASE_KR] = {
+ .speed = 25000,
+ },
+ [MLX5E_25GBASE_SR] = {
+ .speed = 25000,
+ },
+ [MLX5E_50GBASE_CR2] = {
+ .speed = 50000,
+ },
+ [MLX5E_50GBASE_KR2] = {
+ .speed = 50000,
+ },
+};
+
+static int mlx5e_get_sset_count(struct net_device *dev, int sset)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+
+ switch (sset) {
+ case ETH_SS_STATS:
+ return NUM_VPORT_COUNTERS +
+ priv->params.num_channels * NUM_RQ_STATS +
+ priv->params.num_channels * priv->num_tc *
+ NUM_SQ_STATS;
+ /* fallthrough */
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void mlx5e_get_strings(struct net_device *dev,
+ uint32_t stringset, uint8_t *data)
+{
+ int i, j, tc, idx = 0;
+ struct mlx5e_priv *priv = netdev_priv(dev);
+
+ switch (stringset) {
+ case ETH_SS_PRIV_FLAGS:
+ break;
+
+ case ETH_SS_TEST:
+ break;
+
+ case ETH_SS_STATS:
+ /* VPORT counters */
+ for (i = 0; i < NUM_VPORT_COUNTERS; i++)
+ strcpy(data + (idx++) * ETH_GSTRING_LEN,
+ vport_strings[i]);
+
+ /* per channel counters */
+ for (i = 0; i < priv->params.num_channels; i++)
+ for (j = 0; j < NUM_RQ_STATS; j++)
+ sprintf(data + (idx++) * ETH_GSTRING_LEN,
+ "rx%d_%s", i, rq_stats_strings[j]);
+
+ for (i = 0; i < priv->params.num_channels; i++)
+ for (tc = 0; tc < priv->num_tc; tc++)
+ for (j = 0; j < NUM_SQ_STATS; j++)
+ sprintf(data +
+ (idx++) * ETH_GSTRING_LEN,
+ "tx%d_%d_%s", i, tc,
+ sq_stats_strings[j]);
+ break;
+ }
+}
+
+static void mlx5e_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+ int i, j, tc, idx = 0;
+
+ if (!data)
+ return;
+
+ mutex_lock(&priv->state_lock);
+ if (test_bit(MLX5E_STATE_OPENED, &priv->state))
+ mlx5e_update_stats(priv);
+ mutex_unlock(&priv->state_lock);
+
+ for (i = 0; i < NUM_VPORT_COUNTERS; i++)
+ data[idx++] = ((u64 *)&priv->stats.vport)[i];
+
+ /* per channel counters */
+ for (i = 0; i < priv->params.num_channels; i++)
+ for (j = 0; j < NUM_RQ_STATS; j++)
+ data[idx++] = !test_bit(MLX5E_STATE_OPENED,
+ &priv->state) ? 0 :
+ ((u64 *)&priv->channel[i]->rq.stats)[j];
+
+ for (i = 0; i < priv->params.num_channels; i++)
+ for (tc = 0; tc < priv->num_tc; tc++)
+ for (j = 0; j < NUM_SQ_STATS; j++)
+ data[idx++] = !test_bit(MLX5E_STATE_OPENED,
+ &priv->state) ? 0 :
+ ((u64 *)&priv->channel[i]->sq[tc].stats)[j];
+}
+
+static void mlx5e_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *param)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+
+ param->rx_max_pending = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE;
+ param->tx_max_pending = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE;
+ param->rx_pending = 1 << priv->params.log_rq_size;
+ param->tx_pending = 1 << priv->params.log_sq_size;
+}
+
+static int mlx5e_set_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *param)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+ struct mlx5e_params new_params;
+ u16 min_rx_wqes;
+ u8 log_rq_size;
+ u8 log_sq_size;
+ int err = 0;
+
+ if (param->rx_jumbo_pending) {
+ netdev_info(dev, "%s: rx_jumbo_pending not supported\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (param->rx_mini_pending) {
+ netdev_info(dev, "%s: rx_mini_pending not supported\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (param->rx_pending < (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) {
+ netdev_info(dev, "%s: rx_pending (%d) < min (%d)\n",
+ __func__, param->rx_pending,
+ 1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE);
+ return -EINVAL;
+ }
+ if (param->rx_pending > (1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE)) {
+ netdev_info(dev, "%s: rx_pending (%d) > max (%d)\n",
+ __func__, param->rx_pending,
+ 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE);
+ return -EINVAL;
+ }
+ if (param->tx_pending < (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) {
+ netdev_info(dev, "%s: tx_pending (%d) < min (%d)\n",
+ __func__, param->tx_pending,
+ 1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE);
+ return -EINVAL;
+ }
+ if (param->tx_pending > (1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE)) {
+ netdev_info(dev, "%s: tx_pending (%d) > max (%d)\n",
+ __func__, param->tx_pending,
+ 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE);
+ return -EINVAL;
+ }
+
+ log_rq_size = order_base_2(param->rx_pending);
+ log_sq_size = order_base_2(param->tx_pending);
+ min_rx_wqes = min_t(u16, param->rx_pending - 1,
+ MLX5E_PARAMS_DEFAULT_MIN_RX_WQES);
+
+ if (log_rq_size == priv->params.log_rq_size &&
+ log_sq_size == priv->params.log_sq_size &&
+ min_rx_wqes == priv->params.min_rx_wqes)
+ return 0;
+
+ mutex_lock(&priv->state_lock);
+ new_params = priv->params;
+ new_params.log_rq_size = log_rq_size;
+ new_params.log_sq_size = log_sq_size;
+ new_params.min_rx_wqes = min_rx_wqes;
+ err = mlx5e_update_priv_params(priv, &new_params);
+ mutex_unlock(&priv->state_lock);
+
+ return err;
+}
+
+static void mlx5e_get_channels(struct net_device *dev,
+ struct ethtool_channels *ch)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+ int ncv = priv->mdev->priv.eq_table.num_comp_vectors;
+
+ ch->max_combined = ncv;
+ ch->combined_count = priv->params.num_channels;
+}
+
+static int mlx5e_set_channels(struct net_device *dev,
+ struct ethtool_channels *ch)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+ int ncv = priv->mdev->priv.eq_table.num_comp_vectors;
+ unsigned int count = ch->combined_count;
+ struct mlx5e_params new_params;
+ int err = 0;
+
+ if (!count) {
+ netdev_info(dev, "%s: combined_count=0 not supported\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (ch->rx_count || ch->tx_count) {
+ netdev_info(dev, "%s: separate rx/tx count not supported\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (count > ncv) {
+ netdev_info(dev, "%s: count (%d) > max (%d)\n",
+ __func__, count, ncv);
+ return -EINVAL;
+ }
+
+ if (priv->params.num_channels == count)
+ return 0;
+
+ mutex_lock(&priv->state_lock);
+ new_params = priv->params;
+ new_params.num_channels = count;
+ err = mlx5e_update_priv_params(priv, &new_params);
+ mutex_unlock(&priv->state_lock);
+
+ return err;
+}
+
+static int mlx5e_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *coal)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+
+ coal->rx_coalesce_usecs = priv->params.rx_cq_moderation_usec;
+ coal->rx_max_coalesced_frames = priv->params.rx_cq_moderation_pkts;
+ coal->tx_coalesce_usecs = priv->params.tx_cq_moderation_usec;
+ coal->tx_max_coalesced_frames = priv->params.tx_cq_moderation_pkts;
+
+ return 0;
+}
+
+static int mlx5e_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *coal)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ struct mlx5_core_dev *mdev = priv->mdev;
+ struct mlx5e_channel *c;
+ int tc;
+ int i;
+
+ priv->params.tx_cq_moderation_usec = coal->tx_coalesce_usecs;
+ priv->params.tx_cq_moderation_pkts = coal->tx_max_coalesced_frames;
+ priv->params.rx_cq_moderation_usec = coal->rx_coalesce_usecs;
+ priv->params.rx_cq_moderation_pkts = coal->rx_max_coalesced_frames;
+
+ for (i = 0; i < priv->params.num_channels; ++i) {
+ c = priv->channel[i];
+
+ for (tc = 0; tc < c->num_tc; tc++) {
+ mlx5_core_modify_cq_moderation(mdev,
+ &c->sq[tc].cq.mcq,
+ coal->tx_coalesce_usecs,
+ coal->tx_max_coalesced_frames);
+ }
+
+ mlx5_core_modify_cq_moderation(mdev, &c->rq.cq.mcq,
+ coal->rx_coalesce_usecs,
+ coal->rx_max_coalesced_frames);
+ }
+
+ return 0;
+}
+
+static u32 ptys2ethtool_supported_link(u32 eth_proto_cap)
+{
+ int i;
+ u32 supported_modes = 0;
+
+ for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) {
+ if (eth_proto_cap & MLX5E_PROT_MASK(i))
+ supported_modes |= ptys2ethtool_table[i].supported;
+ }
+ return supported_modes;
+}
+
+static u32 ptys2ethtool_adver_link(u32 eth_proto_cap)
+{
+ int i;
+ u32 advertising_modes = 0;
+
+ for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) {
+ if (eth_proto_cap & MLX5E_PROT_MASK(i))
+ advertising_modes |= ptys2ethtool_table[i].advertised;
+ }
+ return advertising_modes;
+}
+
+static u32 ptys2ethtool_supported_port(u32 eth_proto_cap)
+{
+ if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_10GBASE_CR)
+ | MLX5E_PROT_MASK(MLX5E_10GBASE_SR)
+ | MLX5E_PROT_MASK(MLX5E_40GBASE_CR4)
+ | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4)
+ | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4)
+ | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) {
+ return SUPPORTED_FIBRE;
+ }
+
+ if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_100GBASE_KR4)
+ | MLX5E_PROT_MASK(MLX5E_40GBASE_KR4)
+ | MLX5E_PROT_MASK(MLX5E_10GBASE_KR)
+ | MLX5E_PROT_MASK(MLX5E_10GBASE_KX4)
+ | MLX5E_PROT_MASK(MLX5E_1000BASE_KX))) {
+ return SUPPORTED_Backplane;
+ }
+ return 0;
+}
+
+static void get_speed_duplex(struct net_device *netdev,
+ u32 eth_proto_oper,
+ struct ethtool_cmd *cmd)
+{
+ int i;
+ u32 speed = SPEED_UNKNOWN;
+ u8 duplex = DUPLEX_UNKNOWN;
+
+ if (!netif_carrier_ok(netdev))
+ goto out;
+
+ for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) {
+ if (eth_proto_oper & MLX5E_PROT_MASK(i)) {
+ speed = ptys2ethtool_table[i].speed;
+ duplex = DUPLEX_FULL;
+ break;
+ }
+ }
+out:
+ ethtool_cmd_speed_set(cmd, speed);
+ cmd->duplex = duplex;
+}
+
+static void get_supported(u32 eth_proto_cap, u32 *supported)
+{
+ *supported |= ptys2ethtool_supported_port(eth_proto_cap);
+ *supported |= ptys2ethtool_supported_link(eth_proto_cap);
+ *supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+}
+
+static void get_advertising(u32 eth_proto_cap, u8 tx_pause,
+ u8 rx_pause, u32 *advertising)
+{
+ *advertising |= ptys2ethtool_adver_link(eth_proto_cap);
+ *advertising |= tx_pause ? ADVERTISED_Pause : 0;
+ *advertising |= (tx_pause ^ rx_pause) ? ADVERTISED_Asym_Pause : 0;
+}
+
+static u8 get_connector_port(u32 eth_proto)
+{
+ if (eth_proto & (MLX5E_PROT_MASK(MLX5E_10GBASE_SR)
+ | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4)
+ | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4)
+ | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) {
+ return PORT_FIBRE;
+ }
+
+ if (eth_proto & (MLX5E_PROT_MASK(MLX5E_40GBASE_CR4)
+ | MLX5E_PROT_MASK(MLX5E_10GBASE_CR)
+ | MLX5E_PROT_MASK(MLX5E_100GBASE_CR4))) {
+ return PORT_DA;
+ }
+
+ if (eth_proto & (MLX5E_PROT_MASK(MLX5E_10GBASE_KX4)
+ | MLX5E_PROT_MASK(MLX5E_10GBASE_KR)
+ | MLX5E_PROT_MASK(MLX5E_40GBASE_KR4)
+ | MLX5E_PROT_MASK(MLX5E_100GBASE_KR4))) {
+ return PORT_NONE;
+ }
+
+ return PORT_OTHER;
+}
+
+static void get_lp_advertising(u32 eth_proto_lp, u32 *lp_advertising)
+{
+ *lp_advertising = ptys2ethtool_adver_link(eth_proto_lp);
+}
+
+static int mlx5e_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *cmd)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ struct mlx5_core_dev *mdev = priv->mdev;
+ u32 out[MLX5_ST_SZ_DW(ptys_reg)];
+ u32 eth_proto_cap;
+ u32 eth_proto_admin;
+ u32 eth_proto_lp;
+ u32 eth_proto_oper;
+ int err;
+
+ err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, 1);
+
+ if (err) {
+ netdev_err(netdev, "%s: query port ptys failed: %d\n",
+ __func__, err);
+ goto err_query_ptys;
+ }
+
+ eth_proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability);
+ eth_proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin);
+ eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
+ eth_proto_lp = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise);
+
+ cmd->supported = 0;
+ cmd->advertising = 0;
+
+ get_supported(eth_proto_cap, &cmd->supported);
+ get_advertising(eth_proto_admin, 0, 0, &cmd->advertising);
+ get_speed_duplex(netdev, eth_proto_oper, cmd);
+
+ eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap;
+
+ cmd->port = get_connector_port(eth_proto_oper);
+ get_lp_advertising(eth_proto_lp, &cmd->lp_advertising);
+
+ cmd->transceiver = XCVR_INTERNAL;
+
+err_query_ptys:
+ return err;
+}
+
+static u32 mlx5e_ethtool2ptys_adver_link(u32 link_modes)
+{
+ u32 i, ptys_modes = 0;
+
+ for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) {
+ if (ptys2ethtool_table[i].advertised & link_modes)
+ ptys_modes |= MLX5E_PROT_MASK(i);
+ }
+
+ return ptys_modes;
+}
+
+static u32 mlx5e_ethtool2ptys_speed_link(u32 speed)
+{
+ u32 i, speed_links = 0;
+
+ for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) {
+ if (ptys2ethtool_table[i].speed == speed)
+ speed_links |= MLX5E_PROT_MASK(i);
+ }
+
+ return speed_links;
+}
+
+static int mlx5e_set_settings(struct net_device *netdev,
+ struct ethtool_cmd *cmd)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ struct mlx5_core_dev *mdev = priv->mdev;
+ u32 link_modes;
+ u32 speed;
+ u32 eth_proto_cap, eth_proto_admin;
+ u8 port_status;
+ int err;
+
+ speed = ethtool_cmd_speed(cmd);
+
+ link_modes = cmd->autoneg == AUTONEG_ENABLE ?
+ mlx5e_ethtool2ptys_adver_link(cmd->advertising) :
+ mlx5e_ethtool2ptys_speed_link(speed);
+
+ err = mlx5_query_port_proto_cap(mdev, &eth_proto_cap, MLX5_PTYS_EN);
+ if (err) {
+ netdev_err(netdev, "%s: query port eth proto cap failed: %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ link_modes = link_modes & eth_proto_cap;
+ if (!link_modes) {
+ netdev_err(netdev, "%s: Not supported link mode(s) requested",
+ __func__);
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = mlx5_query_port_proto_admin(mdev, &eth_proto_admin, MLX5_PTYS_EN);
+ if (err) {
+ netdev_err(netdev, "%s: query port eth proto admin failed: %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ if (link_modes == eth_proto_admin)
+ goto out;
+
+ err = mlx5_set_port_proto(mdev, link_modes, MLX5_PTYS_EN);
+ if (err) {
+ netdev_err(netdev, "%s: set port eth proto admin failed: %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ err = mlx5_query_port_status(mdev, &port_status);
+ if (err)
+ goto out;
+
+ if (port_status == MLX5_PORT_DOWN)
+ return 0;
+
+ err = mlx5_set_port_status(mdev, MLX5_PORT_DOWN);
+ if (err)
+ goto out;
+ err = mlx5_set_port_status(mdev, MLX5_PORT_UP);
+out:
+ return err;
+}
+
+const struct ethtool_ops mlx5e_ethtool_ops = {
+ .get_drvinfo = mlx5e_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_strings = mlx5e_get_strings,
+ .get_sset_count = mlx5e_get_sset_count,
+ .get_ethtool_stats = mlx5e_get_ethtool_stats,
+ .get_ringparam = mlx5e_get_ringparam,
+ .set_ringparam = mlx5e_set_ringparam,
+ .get_channels = mlx5e_get_channels,
+ .set_channels = mlx5e_set_channels,
+ .get_coalesce = mlx5e_get_coalesce,
+ .set_coalesce = mlx5e_set_coalesce,
+ .get_settings = mlx5e_get_settings,
+ .set_settings = mlx5e_set_settings,
+};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c
new file mode 100644
index 000000000000..120db80c47aa
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c
@@ -0,0 +1,860 @@
+/*
+ * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ */
+
+#include <linux/list.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/mlx5/flow_table.h>
+#include "en.h"
+
+enum {
+ MLX5E_FULLMATCH = 0,
+ MLX5E_ALLMULTI = 1,
+ MLX5E_PROMISC = 2,
+};
+
+enum {
+ MLX5E_UC = 0,
+ MLX5E_MC_IPV4 = 1,
+ MLX5E_MC_IPV6 = 2,
+ MLX5E_MC_OTHER = 3,
+};
+
+enum {
+ MLX5E_ACTION_NONE = 0,
+ MLX5E_ACTION_ADD = 1,
+ MLX5E_ACTION_DEL = 2,
+};
+
+struct mlx5e_eth_addr_hash_node {
+ struct hlist_node hlist;
+ u8 action;
+ struct mlx5e_eth_addr_info ai;
+};
+
+static inline int mlx5e_hash_eth_addr(u8 *addr)
+{
+ return addr[5];
+}
+
+static void mlx5e_add_eth_addr_to_hash(struct hlist_head *hash, u8 *addr)
+{
+ struct mlx5e_eth_addr_hash_node *hn;
+ int ix = mlx5e_hash_eth_addr(addr);
+ int found = 0;
+
+ hlist_for_each_entry(hn, &hash[ix], hlist)
+ if (ether_addr_equal_64bits(hn->ai.addr, addr)) {
+ found = 1;
+ break;
+ }
+
+ if (found) {
+ hn->action = MLX5E_ACTION_NONE;
+ return;
+ }
+
+ hn = kzalloc(sizeof(*hn), GFP_ATOMIC);
+ if (!hn)
+ return;
+
+ ether_addr_copy(hn->ai.addr, addr);
+ hn->action = MLX5E_ACTION_ADD;
+
+ hlist_add_head(&hn->hlist, &hash[ix]);
+}
+
+static void mlx5e_del_eth_addr_from_hash(struct mlx5e_eth_addr_hash_node *hn)
+{
+ hlist_del(&hn->hlist);
+ kfree(hn);
+}
+
+static void mlx5e_del_eth_addr_from_flow_table(struct mlx5e_priv *priv,
+ struct mlx5e_eth_addr_info *ai)
+{
+ void *ft = priv->ft.main;
+
+ if (ai->tt_vec & (1 << MLX5E_TT_IPV6_TCP))
+ mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_TCP]);
+
+ if (ai->tt_vec & (1 << MLX5E_TT_IPV4_TCP))
+ mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_TCP]);
+
+ if (ai->tt_vec & (1 << MLX5E_TT_IPV6_UDP))
+ mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_UDP]);
+
+ if (ai->tt_vec & (1 << MLX5E_TT_IPV4_UDP))
+ mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_UDP]);
+
+ if (ai->tt_vec & (1 << MLX5E_TT_IPV6))
+ mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6]);
+
+ if (ai->tt_vec & (1 << MLX5E_TT_IPV4))
+ mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4]);
+
+ if (ai->tt_vec & (1 << MLX5E_TT_ANY))
+ mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_ANY]);
+}
+
+static int mlx5e_get_eth_addr_type(u8 *addr)
+{
+ if (is_unicast_ether_addr(addr))
+ return MLX5E_UC;
+
+ if ((addr[0] == 0x01) &&
+ (addr[1] == 0x00) &&
+ (addr[2] == 0x5e) &&
+ !(addr[3] & 0x80))
+ return MLX5E_MC_IPV4;
+
+ if ((addr[0] == 0x33) &&
+ (addr[1] == 0x33))
+ return MLX5E_MC_IPV6;
+
+ return MLX5E_MC_OTHER;
+}
+
+static u32 mlx5e_get_tt_vec(struct mlx5e_eth_addr_info *ai, int type)
+{
+ int eth_addr_type;
+ u32 ret;
+
+ switch (type) {
+ case MLX5E_FULLMATCH:
+ eth_addr_type = mlx5e_get_eth_addr_type(ai->addr);
+ switch (eth_addr_type) {
+ case MLX5E_UC:
+ ret =
+ (1 << MLX5E_TT_IPV4_TCP) |
+ (1 << MLX5E_TT_IPV6_TCP) |
+ (1 << MLX5E_TT_IPV4_UDP) |
+ (1 << MLX5E_TT_IPV6_UDP) |
+ (1 << MLX5E_TT_IPV4) |
+ (1 << MLX5E_TT_IPV6) |
+ (1 << MLX5E_TT_ANY) |
+ 0;
+ break;
+
+ case MLX5E_MC_IPV4:
+ ret =
+ (1 << MLX5E_TT_IPV4_UDP) |
+ (1 << MLX5E_TT_IPV4) |
+ 0;
+ break;
+
+ case MLX5E_MC_IPV6:
+ ret =
+ (1 << MLX5E_TT_IPV6_UDP) |
+ (1 << MLX5E_TT_IPV6) |
+ 0;
+ break;
+
+ case MLX5E_MC_OTHER:
+ ret =
+ (1 << MLX5E_TT_ANY) |
+ 0;
+ break;
+ }
+
+ break;
+
+ case MLX5E_ALLMULTI:
+ ret =
+ (1 << MLX5E_TT_IPV4_UDP) |
+ (1 << MLX5E_TT_IPV6_UDP) |
+ (1 << MLX5E_TT_IPV4) |
+ (1 << MLX5E_TT_IPV6) |
+ (1 << MLX5E_TT_ANY) |
+ 0;
+ break;
+
+ default: /* MLX5E_PROMISC */
+ ret =
+ (1 << MLX5E_TT_IPV4_TCP) |
+ (1 << MLX5E_TT_IPV6_TCP) |
+ (1 << MLX5E_TT_IPV4_UDP) |
+ (1 << MLX5E_TT_IPV6_UDP) |
+ (1 << MLX5E_TT_IPV4) |
+ (1 << MLX5E_TT_IPV6) |
+ (1 << MLX5E_TT_ANY) |
+ 0;
+ break;
+ }
+
+ return ret;
+}
+
+static int __mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv,
+ struct mlx5e_eth_addr_info *ai, int type,
+ void *flow_context, void *match_criteria)
+{
+ u8 match_criteria_enable = 0;
+ void *match_value;
+ void *dest;
+ u8 *dmac;
+ u8 *match_criteria_dmac;
+ void *ft = priv->ft.main;
+ u32 *tirn = priv->tirn;
+ u32 tt_vec;
+ int err;
+
+ match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value);
+ dmac = MLX5_ADDR_OF(fte_match_param, match_value,
+ outer_headers.dmac_47_16);
+ match_criteria_dmac = MLX5_ADDR_OF(fte_match_param, match_criteria,
+ outer_headers.dmac_47_16);
+ dest = MLX5_ADDR_OF(flow_context, flow_context, destination);
+
+ MLX5_SET(flow_context, flow_context, action,
+ MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
+ MLX5_SET(flow_context, flow_context, destination_list_size, 1);
+ MLX5_SET(dest_format_struct, dest, destination_type,
+ MLX5_FLOW_CONTEXT_DEST_TYPE_TIR);
+
+ switch (type) {
+ case MLX5E_FULLMATCH:
+ match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ memset(match_criteria_dmac, 0xff, ETH_ALEN);
+ ether_addr_copy(dmac, ai->addr);
+ break;
+
+ case MLX5E_ALLMULTI:
+ match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ match_criteria_dmac[0] = 0x01;
+ dmac[0] = 0x01;
+ break;
+
+ case MLX5E_PROMISC:
+ break;
+ }
+
+ tt_vec = mlx5e_get_tt_vec(ai, type);
+
+ if (tt_vec & (1 << MLX5E_TT_ANY)) {
+ MLX5_SET(dest_format_struct, dest, destination_id,
+ tirn[MLX5E_TT_ANY]);
+ err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
+ match_criteria, flow_context,
+ &ai->ft_ix[MLX5E_TT_ANY]);
+ if (err) {
+ mlx5e_del_eth_addr_from_flow_table(priv, ai);
+ return err;
+ }
+ ai->tt_vec |= (1 << MLX5E_TT_ANY);
+ }
+
+ match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ MLX5_SET_TO_ONES(fte_match_param, match_criteria,
+ outer_headers.ethertype);
+
+ if (tt_vec & (1 << MLX5E_TT_IPV4)) {
+ MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
+ ETH_P_IP);
+ MLX5_SET(dest_format_struct, dest, destination_id,
+ tirn[MLX5E_TT_IPV4]);
+ err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
+ match_criteria, flow_context,
+ &ai->ft_ix[MLX5E_TT_IPV4]);
+ if (err) {
+ mlx5e_del_eth_addr_from_flow_table(priv, ai);
+ return err;
+ }
+ ai->tt_vec |= (1 << MLX5E_TT_IPV4);
+ }
+
+ if (tt_vec & (1 << MLX5E_TT_IPV6)) {
+ MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
+ ETH_P_IPV6);
+ MLX5_SET(dest_format_struct, dest, destination_id,
+ tirn[MLX5E_TT_IPV6]);
+ err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
+ match_criteria, flow_context,
+ &ai->ft_ix[MLX5E_TT_IPV6]);
+ if (err) {
+ mlx5e_del_eth_addr_from_flow_table(priv, ai);
+ return err;
+ }
+ ai->tt_vec |= (1 << MLX5E_TT_IPV6);
+ }
+
+ MLX5_SET_TO_ONES(fte_match_param, match_criteria,
+ outer_headers.ip_protocol);
+ MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol,
+ IPPROTO_UDP);
+
+ if (tt_vec & (1 << MLX5E_TT_IPV4_UDP)) {
+ MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
+ ETH_P_IP);
+ MLX5_SET(dest_format_struct, dest, destination_id,
+ tirn[MLX5E_TT_IPV4_UDP]);
+ err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
+ match_criteria, flow_context,
+ &ai->ft_ix[MLX5E_TT_IPV4_UDP]);
+ if (err) {
+ mlx5e_del_eth_addr_from_flow_table(priv, ai);
+ return err;
+ }
+ ai->tt_vec |= (1 << MLX5E_TT_IPV4_UDP);
+ }
+
+ if (tt_vec & (1 << MLX5E_TT_IPV6_UDP)) {
+ MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
+ ETH_P_IPV6);
+ MLX5_SET(dest_format_struct, dest, destination_id,
+ tirn[MLX5E_TT_IPV6_UDP]);
+ err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
+ match_criteria, flow_context,
+ &ai->ft_ix[MLX5E_TT_IPV6_UDP]);
+ if (err) {
+ mlx5e_del_eth_addr_from_flow_table(priv, ai);
+ return err;
+ }
+ ai->tt_vec |= (1 << MLX5E_TT_IPV6_UDP);
+ }
+
+ MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol,
+ IPPROTO_TCP);
+
+ if (tt_vec & (1 << MLX5E_TT_IPV4_TCP)) {
+ MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
+ ETH_P_IP);
+ MLX5_SET(dest_format_struct, dest, destination_id,
+ tirn[MLX5E_TT_IPV4_TCP]);
+ err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
+ match_criteria, flow_context,
+ &ai->ft_ix[MLX5E_TT_IPV4_TCP]);
+ if (err) {
+ mlx5e_del_eth_addr_from_flow_table(priv, ai);
+ return err;
+ }
+ ai->tt_vec |= (1 << MLX5E_TT_IPV4_TCP);
+ }
+
+ if (tt_vec & (1 << MLX5E_TT_IPV6_TCP)) {
+ MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
+ ETH_P_IPV6);
+ MLX5_SET(dest_format_struct, dest, destination_id,
+ tirn[MLX5E_TT_IPV6_TCP]);
+ err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
+ match_criteria, flow_context,
+ &ai->ft_ix[MLX5E_TT_IPV6_TCP]);
+ if (err) {
+ mlx5e_del_eth_addr_from_flow_table(priv, ai);
+ return err;
+ }
+ ai->tt_vec |= (1 << MLX5E_TT_IPV6_TCP);
+ }
+
+ return 0;
+}
+
+static int mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv,
+ struct mlx5e_eth_addr_info *ai, int type)
+{
+ u32 *flow_context;
+ u32 *match_criteria;
+ int err;
+
+ flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context) +
+ MLX5_ST_SZ_BYTES(dest_format_struct));
+ match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
+ if (!flow_context || !match_criteria) {
+ netdev_err(priv->netdev, "%s: alloc failed\n", __func__);
+ err = -ENOMEM;
+ goto add_eth_addr_rule_out;
+ }
+
+ err = __mlx5e_add_eth_addr_rule(priv, ai, type, flow_context,
+ match_criteria);
+ if (err)
+ netdev_err(priv->netdev, "%s: failed\n", __func__);
+
+add_eth_addr_rule_out:
+ kvfree(match_criteria);
+ kvfree(flow_context);
+ return err;
+}
+
+enum mlx5e_vlan_rule_type {
+ MLX5E_VLAN_RULE_TYPE_UNTAGGED,
+ MLX5E_VLAN_RULE_TYPE_ANY_VID,
+ MLX5E_VLAN_RULE_TYPE_MATCH_VID,
+};
+
+static int mlx5e_add_vlan_rule(struct mlx5e_priv *priv,
+ enum mlx5e_vlan_rule_type rule_type, u16 vid)
+{
+ u8 match_criteria_enable = 0;
+ u32 *flow_context;
+ void *match_value;
+ void *dest;
+ u32 *match_criteria;
+ u32 *ft_ix;
+ int err;
+
+ flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context) +
+ MLX5_ST_SZ_BYTES(dest_format_struct));
+ match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
+ if (!flow_context || !match_criteria) {
+ netdev_err(priv->netdev, "%s: alloc failed\n", __func__);
+ err = -ENOMEM;
+ goto add_vlan_rule_out;
+ }
+ match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value);
+ dest = MLX5_ADDR_OF(flow_context, flow_context, destination);
+
+ MLX5_SET(flow_context, flow_context, action,
+ MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
+ MLX5_SET(flow_context, flow_context, destination_list_size, 1);
+ MLX5_SET(dest_format_struct, dest, destination_type,
+ MLX5_FLOW_CONTEXT_DEST_TYPE_FLOW_TABLE);
+ MLX5_SET(dest_format_struct, dest, destination_id,
+ mlx5_get_flow_table_id(priv->ft.main));
+
+ match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ MLX5_SET_TO_ONES(fte_match_param, match_criteria,
+ outer_headers.vlan_tag);
+
+ switch (rule_type) {
+ case MLX5E_VLAN_RULE_TYPE_UNTAGGED:
+ ft_ix = &priv->vlan.untagged_rule_ft_ix;
+ break;
+ case MLX5E_VLAN_RULE_TYPE_ANY_VID:
+ ft_ix = &priv->vlan.any_vlan_rule_ft_ix;
+ MLX5_SET(fte_match_param, match_value, outer_headers.vlan_tag,
+ 1);
+ break;
+ default: /* MLX5E_VLAN_RULE_TYPE_MATCH_VID */
+ ft_ix = &priv->vlan.active_vlans_ft_ix[vid];
+ MLX5_SET(fte_match_param, match_value, outer_headers.vlan_tag,
+ 1);
+ MLX5_SET_TO_ONES(fte_match_param, match_criteria,
+ outer_headers.first_vid);
+ MLX5_SET(fte_match_param, match_value, outer_headers.first_vid,
+ vid);
+ break;
+ }
+
+ err = mlx5_add_flow_table_entry(priv->ft.vlan, match_criteria_enable,
+ match_criteria, flow_context, ft_ix);
+ if (err)
+ netdev_err(priv->netdev, "%s: failed\n", __func__);
+
+add_vlan_rule_out:
+ kvfree(match_criteria);
+ kvfree(flow_context);
+ return err;
+}
+
+static void mlx5e_del_vlan_rule(struct mlx5e_priv *priv,
+ enum mlx5e_vlan_rule_type rule_type, u16 vid)
+{
+ switch (rule_type) {
+ case MLX5E_VLAN_RULE_TYPE_UNTAGGED:
+ mlx5_del_flow_table_entry(priv->ft.vlan,
+ priv->vlan.untagged_rule_ft_ix);
+ break;
+ case MLX5E_VLAN_RULE_TYPE_ANY_VID:
+ mlx5_del_flow_table_entry(priv->ft.vlan,
+ priv->vlan.any_vlan_rule_ft_ix);
+ break;
+ case MLX5E_VLAN_RULE_TYPE_MATCH_VID:
+ mlx5_del_flow_table_entry(priv->ft.vlan,
+ priv->vlan.active_vlans_ft_ix[vid]);
+ break;
+ }
+}
+
+void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv)
+{
+ WARN_ON(!mutex_is_locked(&priv->state_lock));
+
+ if (priv->vlan.filter_disabled) {
+ priv->vlan.filter_disabled = false;
+ if (test_bit(MLX5E_STATE_OPENED, &priv->state))
+ mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID,
+ 0);
+ }
+}
+
+void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv)
+{
+ WARN_ON(!mutex_is_locked(&priv->state_lock));
+
+ if (!priv->vlan.filter_disabled) {
+ priv->vlan.filter_disabled = true;
+ if (test_bit(MLX5E_STATE_OPENED, &priv->state))
+ mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID,
+ 0);
+ }
+}
+
+int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto,
+ u16 vid)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+ int err = 0;
+
+ mutex_lock(&priv->state_lock);
+
+ set_bit(vid, priv->vlan.active_vlans);
+ if (test_bit(MLX5E_STATE_OPENED, &priv->state))
+ err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID,
+ vid);
+
+ mutex_unlock(&priv->state_lock);
+
+ return err;
+}
+
+int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto,
+ u16 vid)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+
+ mutex_lock(&priv->state_lock);
+
+ clear_bit(vid, priv->vlan.active_vlans);
+ if (test_bit(MLX5E_STATE_OPENED, &priv->state))
+ mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid);
+
+ mutex_unlock(&priv->state_lock);
+
+ return 0;
+}
+
+int mlx5e_add_all_vlan_rules(struct mlx5e_priv *priv)
+{
+ u16 vid;
+ int err;
+
+ for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID) {
+ err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID,
+ vid);
+ if (err)
+ return err;
+ }
+
+ err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0);
+ if (err)
+ return err;
+
+ if (priv->vlan.filter_disabled) {
+ err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID,
+ 0);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+void mlx5e_del_all_vlan_rules(struct mlx5e_priv *priv)
+{
+ u16 vid;
+
+ if (priv->vlan.filter_disabled)
+ mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0);
+
+ mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0);
+
+ for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID)
+ mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid);
+}
+
+#define mlx5e_for_each_hash_node(hn, tmp, hash, i) \
+ for (i = 0; i < MLX5E_ETH_ADDR_HASH_SIZE; i++) \
+ hlist_for_each_entry_safe(hn, tmp, &hash[i], hlist)
+
+static void mlx5e_execute_action(struct mlx5e_priv *priv,
+ struct mlx5e_eth_addr_hash_node *hn)
+{
+ switch (hn->action) {
+ case MLX5E_ACTION_ADD:
+ mlx5e_add_eth_addr_rule(priv, &hn->ai, MLX5E_FULLMATCH);
+ hn->action = MLX5E_ACTION_NONE;
+ break;
+
+ case MLX5E_ACTION_DEL:
+ mlx5e_del_eth_addr_from_flow_table(priv, &hn->ai);
+ mlx5e_del_eth_addr_from_hash(hn);
+ break;
+ }
+}
+
+static void mlx5e_sync_netdev_addr(struct mlx5e_priv *priv)
+{
+ struct net_device *netdev = priv->netdev;
+ struct netdev_hw_addr *ha;
+
+ netif_addr_lock_bh(netdev);
+
+ mlx5e_add_eth_addr_to_hash(priv->eth_addr.netdev_uc,
+ priv->netdev->dev_addr);
+
+ netdev_for_each_uc_addr(ha, netdev)
+ mlx5e_add_eth_addr_to_hash(priv->eth_addr.netdev_uc, ha->addr);
+
+ netdev_for_each_mc_addr(ha, netdev)
+ mlx5e_add_eth_addr_to_hash(priv->eth_addr.netdev_mc, ha->addr);
+
+ netif_addr_unlock_bh(netdev);
+}
+
+static void mlx5e_apply_netdev_addr(struct mlx5e_priv *priv)
+{
+ struct mlx5e_eth_addr_hash_node *hn;
+ struct hlist_node *tmp;
+ int i;
+
+ mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.netdev_uc, i)
+ mlx5e_execute_action(priv, hn);
+
+ mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.netdev_mc, i)
+ mlx5e_execute_action(priv, hn);
+}
+
+static void mlx5e_handle_netdev_addr(struct mlx5e_priv *priv)
+{
+ struct mlx5e_eth_addr_hash_node *hn;
+ struct hlist_node *tmp;
+ int i;
+
+ mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.netdev_uc, i)
+ hn->action = MLX5E_ACTION_DEL;
+ mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.netdev_mc, i)
+ hn->action = MLX5E_ACTION_DEL;
+
+ if (test_bit(MLX5E_STATE_OPENED, &priv->state))
+ mlx5e_sync_netdev_addr(priv);
+
+ mlx5e_apply_netdev_addr(priv);
+}
+
+void mlx5e_set_rx_mode_core(struct mlx5e_priv *priv)
+{
+ struct mlx5e_eth_addr_db *ea = &priv->eth_addr;
+ struct net_device *ndev = priv->netdev;
+
+ bool rx_mode_enable = test_bit(MLX5E_STATE_OPENED, &priv->state);
+ bool promisc_enabled = rx_mode_enable && (ndev->flags & IFF_PROMISC);
+ bool allmulti_enabled = rx_mode_enable && (ndev->flags & IFF_ALLMULTI);
+ bool broadcast_enabled = rx_mode_enable;
+
+ bool enable_promisc = !ea->promisc_enabled && promisc_enabled;
+ bool disable_promisc = ea->promisc_enabled && !promisc_enabled;
+ bool enable_allmulti = !ea->allmulti_enabled && allmulti_enabled;
+ bool disable_allmulti = ea->allmulti_enabled && !allmulti_enabled;
+ bool enable_broadcast = !ea->broadcast_enabled && broadcast_enabled;
+ bool disable_broadcast = ea->broadcast_enabled && !broadcast_enabled;
+
+ if (enable_promisc)
+ mlx5e_add_eth_addr_rule(priv, &ea->promisc, MLX5E_PROMISC);
+ if (enable_allmulti)
+ mlx5e_add_eth_addr_rule(priv, &ea->allmulti, MLX5E_ALLMULTI);
+ if (enable_broadcast)
+ mlx5e_add_eth_addr_rule(priv, &ea->broadcast, MLX5E_FULLMATCH);
+
+ mlx5e_handle_netdev_addr(priv);
+
+ if (disable_broadcast)
+ mlx5e_del_eth_addr_from_flow_table(priv, &ea->broadcast);
+ if (disable_allmulti)
+ mlx5e_del_eth_addr_from_flow_table(priv, &ea->allmulti);
+ if (disable_promisc)
+ mlx5e_del_eth_addr_from_flow_table(priv, &ea->promisc);
+
+ ea->promisc_enabled = promisc_enabled;
+ ea->allmulti_enabled = allmulti_enabled;
+ ea->broadcast_enabled = broadcast_enabled;
+}
+
+void mlx5e_set_rx_mode_work(struct work_struct *work)
+{
+ struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv,
+ set_rx_mode_work);
+
+ mutex_lock(&priv->state_lock);
+ if (test_bit(MLX5E_STATE_OPENED, &priv->state))
+ mlx5e_set_rx_mode_core(priv);
+ mutex_unlock(&priv->state_lock);
+}
+
+void mlx5e_init_eth_addr(struct mlx5e_priv *priv)
+{
+ ether_addr_copy(priv->eth_addr.broadcast.addr, priv->netdev->broadcast);
+}
+
+static int mlx5e_create_main_flow_table(struct mlx5e_priv *priv)
+{
+ struct mlx5_flow_table_group *g;
+ u8 *dmac;
+
+ g = kcalloc(9, sizeof(*g), GFP_KERNEL);
+ if (!g)
+ return -ENOMEM;
+
+ g[0].log_sz = 2;
+ g[0].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria,
+ outer_headers.ethertype);
+ MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria,
+ outer_headers.ip_protocol);
+
+ g[1].log_sz = 1;
+ g[1].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ MLX5_SET_TO_ONES(fte_match_param, g[1].match_criteria,
+ outer_headers.ethertype);
+
+ g[2].log_sz = 0;
+
+ g[3].log_sz = 14;
+ g[3].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ dmac = MLX5_ADDR_OF(fte_match_param, g[3].match_criteria,
+ outer_headers.dmac_47_16);
+ memset(dmac, 0xff, ETH_ALEN);
+ MLX5_SET_TO_ONES(fte_match_param, g[3].match_criteria,
+ outer_headers.ethertype);
+ MLX5_SET_TO_ONES(fte_match_param, g[3].match_criteria,
+ outer_headers.ip_protocol);
+
+ g[4].log_sz = 13;
+ g[4].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ dmac = MLX5_ADDR_OF(fte_match_param, g[4].match_criteria,
+ outer_headers.dmac_47_16);
+ memset(dmac, 0xff, ETH_ALEN);
+ MLX5_SET_TO_ONES(fte_match_param, g[4].match_criteria,
+ outer_headers.ethertype);
+
+ g[5].log_sz = 11;
+ g[5].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ dmac = MLX5_ADDR_OF(fte_match_param, g[5].match_criteria,
+ outer_headers.dmac_47_16);
+ memset(dmac, 0xff, ETH_ALEN);
+
+ g[6].log_sz = 2;
+ g[6].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ dmac = MLX5_ADDR_OF(fte_match_param, g[6].match_criteria,
+ outer_headers.dmac_47_16);
+ dmac[0] = 0x01;
+ MLX5_SET_TO_ONES(fte_match_param, g[6].match_criteria,
+ outer_headers.ethertype);
+ MLX5_SET_TO_ONES(fte_match_param, g[6].match_criteria,
+ outer_headers.ip_protocol);
+
+ g[7].log_sz = 1;
+ g[7].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ dmac = MLX5_ADDR_OF(fte_match_param, g[7].match_criteria,
+ outer_headers.dmac_47_16);
+ dmac[0] = 0x01;
+ MLX5_SET_TO_ONES(fte_match_param, g[7].match_criteria,
+ outer_headers.ethertype);
+
+ g[8].log_sz = 0;
+ g[8].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ dmac = MLX5_ADDR_OF(fte_match_param, g[8].match_criteria,
+ outer_headers.dmac_47_16);
+ dmac[0] = 0x01;
+ priv->ft.main = mlx5_create_flow_table(priv->mdev, 1,
+ MLX5_FLOW_TABLE_TYPE_NIC_RCV,
+ 9, g);
+ kfree(g);
+
+ return priv->ft.main ? 0 : -ENOMEM;
+}
+
+static void mlx5e_destroy_main_flow_table(struct mlx5e_priv *priv)
+{
+ mlx5_destroy_flow_table(priv->ft.main);
+}
+
+static int mlx5e_create_vlan_flow_table(struct mlx5e_priv *priv)
+{
+ struct mlx5_flow_table_group *g;
+
+ g = kcalloc(2, sizeof(*g), GFP_KERNEL);
+ if (!g)
+ return -ENOMEM;
+
+ g[0].log_sz = 12;
+ g[0].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria,
+ outer_headers.vlan_tag);
+ MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria,
+ outer_headers.first_vid);
+
+ /* untagged + any vlan id */
+ g[1].log_sz = 1;
+ g[1].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ MLX5_SET_TO_ONES(fte_match_param, g[1].match_criteria,
+ outer_headers.vlan_tag);
+
+ priv->ft.vlan = mlx5_create_flow_table(priv->mdev, 0,
+ MLX5_FLOW_TABLE_TYPE_NIC_RCV,
+ 2, g);
+
+ kfree(g);
+ return priv->ft.vlan ? 0 : -ENOMEM;
+}
+
+static void mlx5e_destroy_vlan_flow_table(struct mlx5e_priv *priv)
+{
+ mlx5_destroy_flow_table(priv->ft.vlan);
+}
+
+int mlx5e_open_flow_table(struct mlx5e_priv *priv)
+{
+ int err;
+
+ err = mlx5e_create_main_flow_table(priv);
+ if (err)
+ return err;
+
+ err = mlx5e_create_vlan_flow_table(priv);
+ if (err)
+ goto err_destroy_main_flow_table;
+
+ return 0;
+
+err_destroy_main_flow_table:
+ mlx5e_destroy_main_flow_table(priv);
+
+ return err;
+}
+
+void mlx5e_close_flow_table(struct mlx5e_priv *priv)
+{
+ mlx5e_destroy_vlan_flow_table(priv);
+ mlx5e_destroy_main_flow_table(priv);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
new file mode 100644
index 000000000000..40206da1f9d7
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -0,0 +1,1915 @@
+/*
+ * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ */
+
+#include <linux/mlx5/flow_table.h>
+#include "en.h"
+
+struct mlx5e_rq_param {
+ u32 rqc[MLX5_ST_SZ_DW(rqc)];
+ struct mlx5_wq_param wq;
+};
+
+struct mlx5e_sq_param {
+ u32 sqc[MLX5_ST_SZ_DW(sqc)];
+ struct mlx5_wq_param wq;
+};
+
+struct mlx5e_cq_param {
+ u32 cqc[MLX5_ST_SZ_DW(cqc)];
+ struct mlx5_wq_param wq;
+ u16 eq_ix;
+};
+
+struct mlx5e_channel_param {
+ struct mlx5e_rq_param rq;
+ struct mlx5e_sq_param sq;
+ struct mlx5e_cq_param rx_cq;
+ struct mlx5e_cq_param tx_cq;
+};
+
+static void mlx5e_update_carrier(struct mlx5e_priv *priv)
+{
+ struct mlx5_core_dev *mdev = priv->mdev;
+ u8 port_state;
+
+ port_state = mlx5_query_vport_state(mdev,
+ MLX5_QUERY_VPORT_STATE_IN_OP_MOD_VNIC_VPORT);
+
+ if (port_state == VPORT_STATE_UP)
+ netif_carrier_on(priv->netdev);
+ else
+ netif_carrier_off(priv->netdev);
+}
+
+static void mlx5e_update_carrier_work(struct work_struct *work)
+{
+ struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv,
+ update_carrier_work);
+
+ mutex_lock(&priv->state_lock);
+ if (test_bit(MLX5E_STATE_OPENED, &priv->state))
+ mlx5e_update_carrier(priv);
+ mutex_unlock(&priv->state_lock);
+}
+
+void mlx5e_update_stats(struct mlx5e_priv *priv)
+{
+ struct mlx5_core_dev *mdev = priv->mdev;
+ struct mlx5e_vport_stats *s = &priv->stats.vport;
+ struct mlx5e_rq_stats *rq_stats;
+ struct mlx5e_sq_stats *sq_stats;
+ u32 in[MLX5_ST_SZ_DW(query_vport_counter_in)];
+ u32 *out;
+ int outlen = MLX5_ST_SZ_BYTES(query_vport_counter_out);
+ u64 tx_offload_none;
+ int i, j;
+
+ out = mlx5_vzalloc(outlen);
+ if (!out)
+ return;
+
+ /* Collect firts the SW counters and then HW for consistency */
+ s->tso_packets = 0;
+ s->tso_bytes = 0;
+ s->tx_queue_stopped = 0;
+ s->tx_queue_wake = 0;
+ s->tx_queue_dropped = 0;
+ tx_offload_none = 0;
+ s->lro_packets = 0;
+ s->lro_bytes = 0;
+ s->rx_csum_none = 0;
+ s->rx_wqe_err = 0;
+ for (i = 0; i < priv->params.num_channels; i++) {
+ rq_stats = &priv->channel[i]->rq.stats;
+
+ s->lro_packets += rq_stats->lro_packets;
+ s->lro_bytes += rq_stats->lro_bytes;
+ s->rx_csum_none += rq_stats->csum_none;
+ s->rx_wqe_err += rq_stats->wqe_err;
+
+ for (j = 0; j < priv->num_tc; j++) {
+ sq_stats = &priv->channel[i]->sq[j].stats;
+
+ s->tso_packets += sq_stats->tso_packets;
+ s->tso_bytes += sq_stats->tso_bytes;
+ s->tx_queue_stopped += sq_stats->stopped;
+ s->tx_queue_wake += sq_stats->wake;
+ s->tx_queue_dropped += sq_stats->dropped;
+ tx_offload_none += sq_stats->csum_offload_none;
+ }
+ }
+
+ /* HW counters */
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(query_vport_counter_in, in, opcode,
+ MLX5_CMD_OP_QUERY_VPORT_COUNTER);
+ MLX5_SET(query_vport_counter_in, in, op_mod, 0);
+ MLX5_SET(query_vport_counter_in, in, other_vport, 0);
+
+ memset(out, 0, outlen);
+
+ if (mlx5_cmd_exec(mdev, in, sizeof(in), out, outlen))
+ goto free_out;
+
+#define MLX5_GET_CTR(p, x) \
+ MLX5_GET64(query_vport_counter_out, p, x)
+
+ s->rx_error_packets =
+ MLX5_GET_CTR(out, received_errors.packets);
+ s->rx_error_bytes =
+ MLX5_GET_CTR(out, received_errors.octets);
+ s->tx_error_packets =
+ MLX5_GET_CTR(out, transmit_errors.packets);
+ s->tx_error_bytes =
+ MLX5_GET_CTR(out, transmit_errors.octets);
+
+ s->rx_unicast_packets =
+ MLX5_GET_CTR(out, received_eth_unicast.packets);
+ s->rx_unicast_bytes =
+ MLX5_GET_CTR(out, received_eth_unicast.octets);
+ s->tx_unicast_packets =
+ MLX5_GET_CTR(out, transmitted_eth_unicast.packets);
+ s->tx_unicast_bytes =
+ MLX5_GET_CTR(out, transmitted_eth_unicast.octets);
+
+ s->rx_multicast_packets =
+ MLX5_GET_CTR(out, received_eth_multicast.packets);
+ s->rx_multicast_bytes =
+ MLX5_GET_CTR(out, received_eth_multicast.octets);
+ s->tx_multicast_packets =
+ MLX5_GET_CTR(out, transmitted_eth_multicast.packets);
+ s->tx_multicast_bytes =
+ MLX5_GET_CTR(out, transmitted_eth_multicast.octets);
+
+ s->rx_broadcast_packets =
+ MLX5_GET_CTR(out, received_eth_broadcast.packets);
+ s->rx_broadcast_bytes =
+ MLX5_GET_CTR(out, received_eth_broadcast.octets);
+ s->tx_broadcast_packets =
+ MLX5_GET_CTR(out, transmitted_eth_broadcast.packets);
+ s->tx_broadcast_bytes =
+ MLX5_GET_CTR(out, transmitted_eth_broadcast.octets);
+
+ s->rx_packets =
+ s->rx_unicast_packets +
+ s->rx_multicast_packets +
+ s->rx_broadcast_packets;
+ s->rx_bytes =
+ s->rx_unicast_bytes +
+ s->rx_multicast_bytes +
+ s->rx_broadcast_bytes;
+ s->tx_packets =
+ s->tx_unicast_packets +
+ s->tx_multicast_packets +
+ s->tx_broadcast_packets;
+ s->tx_bytes =
+ s->tx_unicast_bytes +
+ s->tx_multicast_bytes +
+ s->tx_broadcast_bytes;
+
+ /* Update calculated offload counters */
+ s->tx_csum_offload = s->tx_packets - tx_offload_none;
+ s->rx_csum_good = s->rx_packets - s->rx_csum_none;
+
+free_out:
+ kvfree(out);
+}
+
+static void mlx5e_update_stats_work(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct mlx5e_priv *priv = container_of(dwork, struct mlx5e_priv,
+ update_stats_work);
+ mutex_lock(&priv->state_lock);
+ if (test_bit(MLX5E_STATE_OPENED, &priv->state)) {
+ mlx5e_update_stats(priv);
+ schedule_delayed_work(dwork,
+ msecs_to_jiffies(
+ MLX5E_UPDATE_STATS_INTERVAL));
+ }
+ mutex_unlock(&priv->state_lock);
+}
+
+static void __mlx5e_async_event(struct mlx5e_priv *priv,
+ enum mlx5_dev_event event)
+{
+ switch (event) {
+ case MLX5_DEV_EVENT_PORT_UP:
+ case MLX5_DEV_EVENT_PORT_DOWN:
+ schedule_work(&priv->update_carrier_work);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void mlx5e_async_event(struct mlx5_core_dev *mdev, void *vpriv,
+ enum mlx5_dev_event event, unsigned long param)
+{
+ struct mlx5e_priv *priv = vpriv;
+
+ spin_lock(&priv->async_events_spinlock);
+ if (test_bit(MLX5E_STATE_ASYNC_EVENTS_ENABLE, &priv->state))
+ __mlx5e_async_event(priv, event);
+ spin_unlock(&priv->async_events_spinlock);
+}
+
+static void mlx5e_enable_async_events(struct mlx5e_priv *priv)
+{
+ set_bit(MLX5E_STATE_ASYNC_EVENTS_ENABLE, &priv->state);
+}
+
+static void mlx5e_disable_async_events(struct mlx5e_priv *priv)
+{
+ spin_lock_irq(&priv->async_events_spinlock);
+ clear_bit(MLX5E_STATE_ASYNC_EVENTS_ENABLE, &priv->state);
+ spin_unlock_irq(&priv->async_events_spinlock);
+}
+
+#define MLX5E_HW2SW_MTU(hwmtu) (hwmtu - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN))
+#define MLX5E_SW2HW_MTU(swmtu) (swmtu + (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN))
+
+static int mlx5e_create_rq(struct mlx5e_channel *c,
+ struct mlx5e_rq_param *param,
+ struct mlx5e_rq *rq)
+{
+ struct mlx5e_priv *priv = c->priv;
+ struct mlx5_core_dev *mdev = priv->mdev;
+ void *rqc = param->rqc;
+ void *rqc_wq = MLX5_ADDR_OF(rqc, rqc, wq);
+ int wq_sz;
+ int err;
+ int i;
+
+ err = mlx5_wq_ll_create(mdev, &param->wq, rqc_wq, &rq->wq,
+ &rq->wq_ctrl);
+ if (err)
+ return err;
+
+ rq->wq.db = &rq->wq.db[MLX5_RCV_DBR];
+
+ wq_sz = mlx5_wq_ll_get_size(&rq->wq);
+ rq->skb = kzalloc_node(wq_sz * sizeof(*rq->skb), GFP_KERNEL,
+ cpu_to_node(c->cpu));
+ if (!rq->skb) {
+ err = -ENOMEM;
+ goto err_rq_wq_destroy;
+ }
+
+ rq->wqe_sz = (priv->params.lro_en) ? priv->params.lro_wqe_sz :
+ MLX5E_SW2HW_MTU(priv->netdev->mtu);
+ rq->wqe_sz = SKB_DATA_ALIGN(rq->wqe_sz + MLX5E_NET_IP_ALIGN);
+
+ for (i = 0; i < wq_sz; i++) {
+ struct mlx5e_rx_wqe *wqe = mlx5_wq_ll_get_wqe(&rq->wq, i);
+ u32 byte_count = rq->wqe_sz - MLX5E_NET_IP_ALIGN;
+
+ wqe->data.lkey = c->mkey_be;
+ wqe->data.byte_count =
+ cpu_to_be32(byte_count | MLX5_HW_START_PADDING);
+ }
+
+ rq->pdev = c->pdev;
+ rq->netdev = c->netdev;
+ rq->channel = c;
+ rq->ix = c->ix;
+
+ return 0;
+
+err_rq_wq_destroy:
+ mlx5_wq_destroy(&rq->wq_ctrl);
+
+ return err;
+}
+
+static void mlx5e_destroy_rq(struct mlx5e_rq *rq)
+{
+ kfree(rq->skb);
+ mlx5_wq_destroy(&rq->wq_ctrl);
+}
+
+static int mlx5e_enable_rq(struct mlx5e_rq *rq, struct mlx5e_rq_param *param)
+{
+ struct mlx5e_channel *c = rq->channel;
+ struct mlx5e_priv *priv = c->priv;
+ struct mlx5_core_dev *mdev = priv->mdev;
+
+ void *in;
+ void *rqc;
+ void *wq;
+ int inlen;
+ int err;
+
+ inlen = MLX5_ST_SZ_BYTES(create_rq_in) +
+ sizeof(u64) * rq->wq_ctrl.buf.npages;
+ in = mlx5_vzalloc(inlen);
+ if (!in)
+ return -ENOMEM;
+
+ rqc = MLX5_ADDR_OF(create_rq_in, in, ctx);
+ wq = MLX5_ADDR_OF(rqc, rqc, wq);
+
+ memcpy(rqc, param->rqc, sizeof(param->rqc));
+
+ MLX5_SET(rqc, rqc, cqn, c->rq.cq.mcq.cqn);
+ MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RST);
+ MLX5_SET(rqc, rqc, flush_in_error_en, 1);
+ MLX5_SET(wq, wq, log_wq_pg_sz, rq->wq_ctrl.buf.page_shift -
+ PAGE_SHIFT);
+ MLX5_SET64(wq, wq, dbr_addr, rq->wq_ctrl.db.dma);
+
+ mlx5_fill_page_array(&rq->wq_ctrl.buf,
+ (__be64 *)MLX5_ADDR_OF(wq, wq, pas));
+
+ err = mlx5_core_create_rq(mdev, in, inlen, &rq->rqn);
+
+ kvfree(in);
+
+ return err;
+}
+
+static int mlx5e_modify_rq(struct mlx5e_rq *rq, int curr_state, int next_state)
+{
+ struct mlx5e_channel *c = rq->channel;
+ struct mlx5e_priv *priv = c->priv;
+ struct mlx5_core_dev *mdev = priv->mdev;
+
+ void *in;
+ void *rqc;
+ int inlen;
+ int err;
+
+ inlen = MLX5_ST_SZ_BYTES(modify_rq_in);
+ in = mlx5_vzalloc(inlen);
+ if (!in)
+ return -ENOMEM;
+
+ rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
+
+ MLX5_SET(modify_rq_in, in, rq_state, curr_state);
+ MLX5_SET(rqc, rqc, state, next_state);
+
+ err = mlx5_core_modify_rq(mdev, rq->rqn, in, inlen);
+
+ kvfree(in);
+
+ return err;
+}
+
+static void mlx5e_disable_rq(struct mlx5e_rq *rq)
+{
+ struct mlx5e_channel *c = rq->channel;
+ struct mlx5e_priv *priv = c->priv;
+ struct mlx5_core_dev *mdev = priv->mdev;
+
+ mlx5_core_destroy_rq(mdev, rq->rqn);
+}
+
+static int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq)
+{
+ struct mlx5e_channel *c = rq->channel;
+ struct mlx5e_priv *priv = c->priv;
+ struct mlx5_wq_ll *wq = &rq->wq;
+ int i;
+
+ for (i = 0; i < 1000; i++) {
+ if (wq->cur_sz >= priv->params.min_rx_wqes)
+ return 0;
+
+ msleep(20);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int mlx5e_open_rq(struct mlx5e_channel *c,
+ struct mlx5e_rq_param *param,
+ struct mlx5e_rq *rq)
+{
+ int err;
+
+ err = mlx5e_create_rq(c, param, rq);
+ if (err)
+ return err;
+
+ err = mlx5e_enable_rq(rq, param);
+ if (err)
+ goto err_destroy_rq;
+
+ err = mlx5e_modify_rq(rq, MLX5_RQC_STATE_RST, MLX5_RQC_STATE_RDY);
+ if (err)
+ goto err_disable_rq;
+
+ set_bit(MLX5E_RQ_STATE_POST_WQES_ENABLE, &rq->state);
+ mlx5e_send_nop(&c->sq[0], true); /* trigger mlx5e_post_rx_wqes() */
+
+ return 0;
+
+err_disable_rq:
+ mlx5e_disable_rq(rq);
+err_destroy_rq:
+ mlx5e_destroy_rq(rq);
+
+ return err;
+}
+
+static void mlx5e_close_rq(struct mlx5e_rq *rq)
+{
+ clear_bit(MLX5E_RQ_STATE_POST_WQES_ENABLE, &rq->state);
+ napi_synchronize(&rq->channel->napi); /* prevent mlx5e_post_rx_wqes */
+
+ mlx5e_modify_rq(rq, MLX5_RQC_STATE_RDY, MLX5_RQC_STATE_ERR);
+ while (!mlx5_wq_ll_is_empty(&rq->wq))
+ msleep(20);
+
+ /* avoid destroying rq before mlx5e_poll_rx_cq() is done with it */
+ napi_synchronize(&rq->channel->napi);
+
+ mlx5e_disable_rq(rq);
+ mlx5e_destroy_rq(rq);
+}
+
+static void mlx5e_free_sq_db(struct mlx5e_sq *sq)
+{
+ kfree(sq->dma_fifo);
+ kfree(sq->skb);
+}
+
+static int mlx5e_alloc_sq_db(struct mlx5e_sq *sq, int numa)
+{
+ int wq_sz = mlx5_wq_cyc_get_size(&sq->wq);
+ int df_sz = wq_sz * MLX5_SEND_WQEBB_NUM_DS;
+
+ sq->skb = kzalloc_node(wq_sz * sizeof(*sq->skb), GFP_KERNEL, numa);
+ sq->dma_fifo = kzalloc_node(df_sz * sizeof(*sq->dma_fifo), GFP_KERNEL,
+ numa);
+
+ if (!sq->skb || !sq->dma_fifo) {
+ mlx5e_free_sq_db(sq);
+ return -ENOMEM;
+ }
+
+ sq->dma_fifo_mask = df_sz - 1;
+
+ return 0;
+}
+
+static int mlx5e_create_sq(struct mlx5e_channel *c,
+ int tc,
+ struct mlx5e_sq_param *param,
+ struct mlx5e_sq *sq)
+{
+ struct mlx5e_priv *priv = c->priv;
+ struct mlx5_core_dev *mdev = priv->mdev;
+
+ void *sqc = param->sqc;
+ void *sqc_wq = MLX5_ADDR_OF(sqc, sqc, wq);
+ int txq_ix;
+ int err;
+
+ err = mlx5_alloc_map_uar(mdev, &sq->uar);
+ if (err)
+ return err;
+
+ err = mlx5_wq_cyc_create(mdev, &param->wq, sqc_wq, &sq->wq,
+ &sq->wq_ctrl);
+ if (err)
+ goto err_unmap_free_uar;
+
+ sq->wq.db = &sq->wq.db[MLX5_SND_DBR];
+ sq->uar_map = sq->uar.map;
+ sq->bf_buf_size = (1 << MLX5_CAP_GEN(mdev, log_bf_reg_size)) / 2;
+
+ err = mlx5e_alloc_sq_db(sq, cpu_to_node(c->cpu));
+ if (err)
+ goto err_sq_wq_destroy;
+
+ txq_ix = c->ix + tc * priv->params.num_channels;
+ sq->txq = netdev_get_tx_queue(priv->netdev, txq_ix);
+
+ sq->pdev = c->pdev;
+ sq->mkey_be = c->mkey_be;
+ sq->channel = c;
+ sq->tc = tc;
+ sq->edge = (sq->wq.sz_m1 + 1) - MLX5_SEND_WQE_MAX_WQEBBS;
+ priv->txq_to_sq_map[txq_ix] = sq;
+
+ return 0;
+
+err_sq_wq_destroy:
+ mlx5_wq_destroy(&sq->wq_ctrl);
+
+err_unmap_free_uar:
+ mlx5_unmap_free_uar(mdev, &sq->uar);
+
+ return err;
+}
+
+static void mlx5e_destroy_sq(struct mlx5e_sq *sq)
+{
+ struct mlx5e_channel *c = sq->channel;
+ struct mlx5e_priv *priv = c->priv;
+
+ mlx5e_free_sq_db(sq);
+ mlx5_wq_destroy(&sq->wq_ctrl);
+ mlx5_unmap_free_uar(priv->mdev, &sq->uar);
+}
+
+static int mlx5e_enable_sq(struct mlx5e_sq *sq, struct mlx5e_sq_param *param)
+{
+ struct mlx5e_channel *c = sq->channel;
+ struct mlx5e_priv *priv = c->priv;
+ struct mlx5_core_dev *mdev = priv->mdev;
+
+ void *in;
+ void *sqc;
+ void *wq;
+ int inlen;
+ int err;
+
+ inlen = MLX5_ST_SZ_BYTES(create_sq_in) +
+ sizeof(u64) * sq->wq_ctrl.buf.npages;
+ in = mlx5_vzalloc(inlen);
+ if (!in)
+ return -ENOMEM;
+
+ sqc = MLX5_ADDR_OF(create_sq_in, in, ctx);
+ wq = MLX5_ADDR_OF(sqc, sqc, wq);
+
+ memcpy(sqc, param->sqc, sizeof(param->sqc));
+
+ MLX5_SET(sqc, sqc, user_index, sq->tc);
+ MLX5_SET(sqc, sqc, tis_num_0, priv->tisn[sq->tc]);
+ MLX5_SET(sqc, sqc, cqn, c->sq[sq->tc].cq.mcq.cqn);
+ MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RST);
+ MLX5_SET(sqc, sqc, tis_lst_sz, 1);
+ MLX5_SET(sqc, sqc, flush_in_error_en, 1);
+
+ MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
+ MLX5_SET(wq, wq, uar_page, sq->uar.index);
+ MLX5_SET(wq, wq, log_wq_pg_sz, sq->wq_ctrl.buf.page_shift -
+ PAGE_SHIFT);
+ MLX5_SET64(wq, wq, dbr_addr, sq->wq_ctrl.db.dma);
+
+ mlx5_fill_page_array(&sq->wq_ctrl.buf,
+ (__be64 *)MLX5_ADDR_OF(wq, wq, pas));
+
+ err = mlx5_core_create_sq(mdev, in, inlen, &sq->sqn);
+
+ kvfree(in);
+
+ return err;
+}
+
+static int mlx5e_modify_sq(struct mlx5e_sq *sq, int curr_state, int next_state)
+{
+ struct mlx5e_channel *c = sq->channel;
+ struct mlx5e_priv *priv = c->priv;
+ struct mlx5_core_dev *mdev = priv->mdev;
+
+ void *in;
+ void *sqc;
+ int inlen;
+ int err;
+
+ inlen = MLX5_ST_SZ_BYTES(modify_sq_in);
+ in = mlx5_vzalloc(inlen);
+ if (!in)
+ return -ENOMEM;
+
+ sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx);
+
+ MLX5_SET(modify_sq_in, in, sq_state, curr_state);
+ MLX5_SET(sqc, sqc, state, next_state);
+
+ err = mlx5_core_modify_sq(mdev, sq->sqn, in, inlen);
+
+ kvfree(in);
+
+ return err;
+}
+
+static void mlx5e_disable_sq(struct mlx5e_sq *sq)
+{
+ struct mlx5e_channel *c = sq->channel;
+ struct mlx5e_priv *priv = c->priv;
+ struct mlx5_core_dev *mdev = priv->mdev;
+
+ mlx5_core_destroy_sq(mdev, sq->sqn);
+}
+
+static int mlx5e_open_sq(struct mlx5e_channel *c,
+ int tc,
+ struct mlx5e_sq_param *param,
+ struct mlx5e_sq *sq)
+{
+ int err;
+
+ err = mlx5e_create_sq(c, tc, param, sq);
+ if (err)
+ return err;
+
+ err = mlx5e_enable_sq(sq, param);
+ if (err)
+ goto err_destroy_sq;
+
+ err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RST, MLX5_SQC_STATE_RDY);
+ if (err)
+ goto err_disable_sq;
+
+ set_bit(MLX5E_SQ_STATE_WAKE_TXQ_ENABLE, &sq->state);
+ netdev_tx_reset_queue(sq->txq);
+ netif_tx_start_queue(sq->txq);
+
+ return 0;
+
+err_disable_sq:
+ mlx5e_disable_sq(sq);
+err_destroy_sq:
+ mlx5e_destroy_sq(sq);
+
+ return err;
+}
+
+static inline void netif_tx_disable_queue(struct netdev_queue *txq)
+{
+ __netif_tx_lock_bh(txq);
+ netif_tx_stop_queue(txq);
+ __netif_tx_unlock_bh(txq);
+}
+
+static void mlx5e_close_sq(struct mlx5e_sq *sq)
+{
+ clear_bit(MLX5E_SQ_STATE_WAKE_TXQ_ENABLE, &sq->state);
+ napi_synchronize(&sq->channel->napi); /* prevent netif_tx_wake_queue */
+ netif_tx_disable_queue(sq->txq);
+
+ /* ensure hw is notified of all pending wqes */
+ if (mlx5e_sq_has_room_for(sq, 1))
+ mlx5e_send_nop(sq, true);
+
+ mlx5e_modify_sq(sq, MLX5_SQC_STATE_RDY, MLX5_SQC_STATE_ERR);
+ while (sq->cc != sq->pc) /* wait till sq is empty */
+ msleep(20);
+
+ /* avoid destroying sq before mlx5e_poll_tx_cq() is done with it */
+ napi_synchronize(&sq->channel->napi);
+
+ mlx5e_disable_sq(sq);
+ mlx5e_destroy_sq(sq);
+}
+
+static int mlx5e_create_cq(struct mlx5e_channel *c,
+ struct mlx5e_cq_param *param,
+ struct mlx5e_cq *cq)
+{
+ struct mlx5e_priv *priv = c->priv;
+ struct mlx5_core_dev *mdev = priv->mdev;
+ struct mlx5_core_cq *mcq = &cq->mcq;
+ int eqn_not_used;
+ int irqn;
+ int err;
+ u32 i;
+
+ param->wq.numa = cpu_to_node(c->cpu);
+ param->eq_ix = c->ix;
+
+ err = mlx5_cqwq_create(mdev, &param->wq, param->cqc, &cq->wq,
+ &cq->wq_ctrl);
+ if (err)
+ return err;
+
+ mlx5_vector2eqn(mdev, param->eq_ix, &eqn_not_used, &irqn);
+
+ cq->napi = &c->napi;
+
+ mcq->cqe_sz = 64;
+ mcq->set_ci_db = cq->wq_ctrl.db.db;
+ mcq->arm_db = cq->wq_ctrl.db.db + 1;
+ *mcq->set_ci_db = 0;
+ *mcq->arm_db = 0;
+ mcq->vector = param->eq_ix;
+ mcq->comp = mlx5e_completion_event;
+ mcq->event = mlx5e_cq_error_event;
+ mcq->irqn = irqn;
+ mcq->uar = &priv->cq_uar;
+
+ for (i = 0; i < mlx5_cqwq_get_size(&cq->wq); i++) {
+ struct mlx5_cqe64 *cqe = mlx5_cqwq_get_wqe(&cq->wq, i);
+
+ cqe->op_own = 0xf1;
+ }
+
+ cq->channel = c;
+
+ return 0;
+}
+
+static void mlx5e_destroy_cq(struct mlx5e_cq *cq)
+{
+ mlx5_wq_destroy(&cq->wq_ctrl);
+}
+
+static int mlx5e_enable_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param)
+{
+ struct mlx5e_channel *c = cq->channel;
+ struct mlx5e_priv *priv = c->priv;
+ struct mlx5_core_dev *mdev = priv->mdev;
+ struct mlx5_core_cq *mcq = &cq->mcq;
+
+ void *in;
+ void *cqc;
+ int inlen;
+ int irqn_not_used;
+ int eqn;
+ int err;
+
+ inlen = MLX5_ST_SZ_BYTES(create_cq_in) +
+ sizeof(u64) * cq->wq_ctrl.buf.npages;
+ in = mlx5_vzalloc(inlen);
+ if (!in)
+ return -ENOMEM;
+
+ cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context);
+
+ memcpy(cqc, param->cqc, sizeof(param->cqc));
+
+ mlx5_fill_page_array(&cq->wq_ctrl.buf,
+ (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas));
+
+ mlx5_vector2eqn(mdev, param->eq_ix, &eqn, &irqn_not_used);
+
+ MLX5_SET(cqc, cqc, c_eqn, eqn);
+ MLX5_SET(cqc, cqc, uar_page, mcq->uar->index);
+ MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift -
+ PAGE_SHIFT);
+ MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma);
+
+ err = mlx5_core_create_cq(mdev, mcq, in, inlen);
+
+ kvfree(in);
+
+ if (err)
+ return err;
+
+ mlx5e_cq_arm(cq);
+
+ return 0;
+}
+
+static void mlx5e_disable_cq(struct mlx5e_cq *cq)
+{
+ struct mlx5e_channel *c = cq->channel;
+ struct mlx5e_priv *priv = c->priv;
+ struct mlx5_core_dev *mdev = priv->mdev;
+
+ mlx5_core_destroy_cq(mdev, &cq->mcq);
+}
+
+static int mlx5e_open_cq(struct mlx5e_channel *c,
+ struct mlx5e_cq_param *param,
+ struct mlx5e_cq *cq,
+ u16 moderation_usecs,
+ u16 moderation_frames)
+{
+ int err;
+ struct mlx5e_priv *priv = c->priv;
+ struct mlx5_core_dev *mdev = priv->mdev;
+
+ err = mlx5e_create_cq(c, param, cq);
+ if (err)
+ return err;
+
+ err = mlx5e_enable_cq(cq, param);
+ if (err)
+ goto err_destroy_cq;
+
+ err = mlx5_core_modify_cq_moderation(mdev, &cq->mcq,
+ moderation_usecs,
+ moderation_frames);
+ if (err)
+ goto err_destroy_cq;
+
+ return 0;
+
+err_destroy_cq:
+ mlx5e_destroy_cq(cq);
+
+ return err;
+}
+
+static void mlx5e_close_cq(struct mlx5e_cq *cq)
+{
+ mlx5e_disable_cq(cq);
+ mlx5e_destroy_cq(cq);
+}
+
+static int mlx5e_get_cpu(struct mlx5e_priv *priv, int ix)
+{
+ return cpumask_first(priv->mdev->priv.irq_info[ix].mask);
+}
+
+static int mlx5e_open_tx_cqs(struct mlx5e_channel *c,
+ struct mlx5e_channel_param *cparam)
+{
+ struct mlx5e_priv *priv = c->priv;
+ int err;
+ int tc;
+
+ for (tc = 0; tc < c->num_tc; tc++) {
+ err = mlx5e_open_cq(c, &cparam->tx_cq, &c->sq[tc].cq,
+ priv->params.tx_cq_moderation_usec,
+ priv->params.tx_cq_moderation_pkts);
+ if (err)
+ goto err_close_tx_cqs;
+ }
+
+ return 0;
+
+err_close_tx_cqs:
+ for (tc--; tc >= 0; tc--)
+ mlx5e_close_cq(&c->sq[tc].cq);
+
+ return err;
+}
+
+static void mlx5e_close_tx_cqs(struct mlx5e_channel *c)
+{
+ int tc;
+
+ for (tc = 0; tc < c->num_tc; tc++)
+ mlx5e_close_cq(&c->sq[tc].cq);
+}
+
+static int mlx5e_open_sqs(struct mlx5e_channel *c,
+ struct mlx5e_channel_param *cparam)
+{
+ int err;
+ int tc;
+
+ for (tc = 0; tc < c->num_tc; tc++) {
+ err = mlx5e_open_sq(c, tc, &cparam->sq, &c->sq[tc]);
+ if (err)
+ goto err_close_sqs;
+ }
+
+ return 0;
+
+err_close_sqs:
+ for (tc--; tc >= 0; tc--)
+ mlx5e_close_sq(&c->sq[tc]);
+
+ return err;
+}
+
+static void mlx5e_close_sqs(struct mlx5e_channel *c)
+{
+ int tc;
+
+ for (tc = 0; tc < c->num_tc; tc++)
+ mlx5e_close_sq(&c->sq[tc]);
+}
+
+static void mlx5e_build_tc_to_txq_map(struct mlx5e_channel *c,
+ int num_channels)
+{
+ int i;
+
+ for (i = 0; i < MLX5E_MAX_NUM_TC; i++)
+ c->tc_to_txq_map[i] = c->ix + i * num_channels;
+}
+
+static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
+ struct mlx5e_channel_param *cparam,
+ struct mlx5e_channel **cp)
+{
+ struct net_device *netdev = priv->netdev;
+ int cpu = mlx5e_get_cpu(priv, ix);
+ struct mlx5e_channel *c;
+ int err;
+
+ c = kzalloc_node(sizeof(*c), GFP_KERNEL, cpu_to_node(cpu));
+ if (!c)
+ return -ENOMEM;
+
+ c->priv = priv;
+ c->ix = ix;
+ c->cpu = cpu;
+ c->pdev = &priv->mdev->pdev->dev;
+ c->netdev = priv->netdev;
+ c->mkey_be = cpu_to_be32(priv->mr.key);
+ c->num_tc = priv->num_tc;
+
+ mlx5e_build_tc_to_txq_map(c, priv->params.num_channels);
+
+ netif_napi_add(netdev, &c->napi, mlx5e_napi_poll, 64);
+
+ err = mlx5e_open_tx_cqs(c, cparam);
+ if (err)
+ goto err_napi_del;
+
+ err = mlx5e_open_cq(c, &cparam->rx_cq, &c->rq.cq,
+ priv->params.rx_cq_moderation_usec,
+ priv->params.rx_cq_moderation_pkts);
+ if (err)
+ goto err_close_tx_cqs;
+
+ napi_enable(&c->napi);
+
+ err = mlx5e_open_sqs(c, cparam);
+ if (err)
+ goto err_disable_napi;
+
+ err = mlx5e_open_rq(c, &cparam->rq, &c->rq);
+ if (err)
+ goto err_close_sqs;
+
+ netif_set_xps_queue(netdev, get_cpu_mask(c->cpu), ix);
+ *cp = c;
+
+ return 0;
+
+err_close_sqs:
+ mlx5e_close_sqs(c);
+
+err_disable_napi:
+ napi_disable(&c->napi);
+ mlx5e_close_cq(&c->rq.cq);
+
+err_close_tx_cqs:
+ mlx5e_close_tx_cqs(c);
+
+err_napi_del:
+ netif_napi_del(&c->napi);
+ kfree(c);
+
+ return err;
+}
+
+static void mlx5e_close_channel(struct mlx5e_channel *c)
+{
+ mlx5e_close_rq(&c->rq);
+ mlx5e_close_sqs(c);
+ napi_disable(&c->napi);
+ mlx5e_close_cq(&c->rq.cq);
+ mlx5e_close_tx_cqs(c);
+ netif_napi_del(&c->napi);
+ kfree(c);
+}
+
+static void mlx5e_build_rq_param(struct mlx5e_priv *priv,
+ struct mlx5e_rq_param *param)
+{
+ void *rqc = param->rqc;
+ void *wq = MLX5_ADDR_OF(rqc, rqc, wq);
+
+ MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_LINKED_LIST);
+ MLX5_SET(wq, wq, end_padding_mode, MLX5_WQ_END_PAD_MODE_ALIGN);
+ MLX5_SET(wq, wq, log_wq_stride, ilog2(sizeof(struct mlx5e_rx_wqe)));
+ MLX5_SET(wq, wq, log_wq_sz, priv->params.log_rq_size);
+ MLX5_SET(wq, wq, pd, priv->pdn);
+
+ param->wq.numa = dev_to_node(&priv->mdev->pdev->dev);
+ param->wq.linear = 1;
+}
+
+static void mlx5e_build_sq_param(struct mlx5e_priv *priv,
+ struct mlx5e_sq_param *param)
+{
+ void *sqc = param->sqc;
+ void *wq = MLX5_ADDR_OF(sqc, sqc, wq);
+
+ MLX5_SET(wq, wq, log_wq_sz, priv->params.log_sq_size);
+ MLX5_SET(wq, wq, log_wq_stride, ilog2(MLX5_SEND_WQE_BB));
+ MLX5_SET(wq, wq, pd, priv->pdn);
+
+ param->wq.numa = dev_to_node(&priv->mdev->pdev->dev);
+}
+
+static void mlx5e_build_common_cq_param(struct mlx5e_priv *priv,
+ struct mlx5e_cq_param *param)
+{
+ void *cqc = param->cqc;
+
+ MLX5_SET(cqc, cqc, uar_page, priv->cq_uar.index);
+}
+
+static void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv,
+ struct mlx5e_cq_param *param)
+{
+ void *cqc = param->cqc;
+
+ MLX5_SET(cqc, cqc, log_cq_size, priv->params.log_rq_size);
+
+ mlx5e_build_common_cq_param(priv, param);
+}
+
+static void mlx5e_build_tx_cq_param(struct mlx5e_priv *priv,
+ struct mlx5e_cq_param *param)
+{
+ void *cqc = param->cqc;
+
+ MLX5_SET(cqc, cqc, log_cq_size, priv->params.log_sq_size);
+
+ mlx5e_build_common_cq_param(priv, param);
+}
+
+static void mlx5e_build_channel_param(struct mlx5e_priv *priv,
+ struct mlx5e_channel_param *cparam)
+{
+ memset(cparam, 0, sizeof(*cparam));
+
+ mlx5e_build_rq_param(priv, &cparam->rq);
+ mlx5e_build_sq_param(priv, &cparam->sq);
+ mlx5e_build_rx_cq_param(priv, &cparam->rx_cq);
+ mlx5e_build_tx_cq_param(priv, &cparam->tx_cq);
+}
+
+static int mlx5e_open_channels(struct mlx5e_priv *priv)
+{
+ struct mlx5e_channel_param cparam;
+ int err = -ENOMEM;
+ int i;
+ int j;
+
+ priv->channel = kcalloc(priv->params.num_channels,
+ sizeof(struct mlx5e_channel *), GFP_KERNEL);
+
+ priv->txq_to_sq_map = kcalloc(priv->params.num_channels * priv->num_tc,
+ sizeof(struct mlx5e_sq *), GFP_KERNEL);
+
+ if (!priv->channel || !priv->txq_to_sq_map)
+ goto err_free_txq_to_sq_map;
+
+ mlx5e_build_channel_param(priv, &cparam);
+ for (i = 0; i < priv->params.num_channels; i++) {
+ err = mlx5e_open_channel(priv, i, &cparam, &priv->channel[i]);
+ if (err)
+ goto err_close_channels;
+ }
+
+ for (j = 0; j < priv->params.num_channels; j++) {
+ err = mlx5e_wait_for_min_rx_wqes(&priv->channel[j]->rq);
+ if (err)
+ goto err_close_channels;
+ }
+
+ return 0;
+
+err_close_channels:
+ for (i--; i >= 0; i--)
+ mlx5e_close_channel(priv->channel[i]);
+
+err_free_txq_to_sq_map:
+ kfree(priv->txq_to_sq_map);
+ kfree(priv->channel);
+
+ return err;
+}
+
+static void mlx5e_close_channels(struct mlx5e_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < priv->params.num_channels; i++)
+ mlx5e_close_channel(priv->channel[i]);
+
+ kfree(priv->txq_to_sq_map);
+ kfree(priv->channel);
+}
+
+static int mlx5e_open_tis(struct mlx5e_priv *priv, int tc)
+{
+ struct mlx5_core_dev *mdev = priv->mdev;
+ u32 in[MLX5_ST_SZ_DW(create_tis_in)];
+ void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
+
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(tisc, tisc, prio, tc);
+ MLX5_SET(tisc, tisc, transport_domain, priv->tdn);
+
+ return mlx5_core_create_tis(mdev, in, sizeof(in), &priv->tisn[tc]);
+}
+
+static void mlx5e_close_tis(struct mlx5e_priv *priv, int tc)
+{
+ mlx5_core_destroy_tis(priv->mdev, priv->tisn[tc]);
+}
+
+static int mlx5e_open_tises(struct mlx5e_priv *priv)
+{
+ int num_tc = priv->num_tc;
+ int err;
+ int tc;
+
+ for (tc = 0; tc < num_tc; tc++) {
+ err = mlx5e_open_tis(priv, tc);
+ if (err)
+ goto err_close_tises;
+ }
+
+ return 0;
+
+err_close_tises:
+ for (tc--; tc >= 0; tc--)
+ mlx5e_close_tis(priv, tc);
+
+ return err;
+}
+
+static void mlx5e_close_tises(struct mlx5e_priv *priv)
+{
+ int num_tc = priv->num_tc;
+ int tc;
+
+ for (tc = 0; tc < num_tc; tc++)
+ mlx5e_close_tis(priv, tc);
+}
+
+static int mlx5e_open_rqt(struct mlx5e_priv *priv)
+{
+ struct mlx5_core_dev *mdev = priv->mdev;
+ u32 *in;
+ u32 out[MLX5_ST_SZ_DW(create_rqt_out)];
+ void *rqtc;
+ int inlen;
+ int err;
+ int sz;
+ int i;
+
+ sz = 1 << priv->params.rx_hash_log_tbl_sz;
+
+ inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * sz;
+ in = mlx5_vzalloc(inlen);
+ if (!in)
+ return -ENOMEM;
+
+ rqtc = MLX5_ADDR_OF(create_rqt_in, in, rqt_context);
+
+ MLX5_SET(rqtc, rqtc, rqt_actual_size, sz);
+ MLX5_SET(rqtc, rqtc, rqt_max_size, sz);
+
+ for (i = 0; i < sz; i++) {
+ int ix = i % priv->params.num_channels;
+
+ MLX5_SET(rqtc, rqtc, rq_num[i], priv->channel[ix]->rq.rqn);
+ }
+
+ MLX5_SET(create_rqt_in, in, opcode, MLX5_CMD_OP_CREATE_RQT);
+
+ memset(out, 0, sizeof(out));
+ err = mlx5_cmd_exec_check_status(mdev, in, inlen, out, sizeof(out));
+ if (!err)
+ priv->rqtn = MLX5_GET(create_rqt_out, out, rqtn);
+
+ kvfree(in);
+
+ return err;
+}
+
+static void mlx5e_close_rqt(struct mlx5e_priv *priv)
+{
+ u32 in[MLX5_ST_SZ_DW(destroy_rqt_in)];
+ u32 out[MLX5_ST_SZ_DW(destroy_rqt_out)];
+
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(destroy_rqt_in, in, opcode, MLX5_CMD_OP_DESTROY_RQT);
+ MLX5_SET(destroy_rqt_in, in, rqtn, priv->rqtn);
+
+ mlx5_cmd_exec_check_status(priv->mdev, in, sizeof(in), out,
+ sizeof(out));
+}
+
+static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt)
+{
+ void *hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer);
+
+ MLX5_SET(tirc, tirc, transport_domain, priv->tdn);
+
+#define ROUGH_MAX_L2_L3_HDR_SZ 256
+
+#define MLX5_HASH_IP (MLX5_HASH_FIELD_SEL_SRC_IP |\
+ MLX5_HASH_FIELD_SEL_DST_IP)
+
+#define MLX5_HASH_ALL (MLX5_HASH_FIELD_SEL_SRC_IP |\
+ MLX5_HASH_FIELD_SEL_DST_IP |\
+ MLX5_HASH_FIELD_SEL_L4_SPORT |\
+ MLX5_HASH_FIELD_SEL_L4_DPORT)
+
+ if (priv->params.lro_en) {
+ MLX5_SET(tirc, tirc, lro_enable_mask,
+ MLX5_TIRC_LRO_ENABLE_MASK_IPV4_LRO |
+ MLX5_TIRC_LRO_ENABLE_MASK_IPV6_LRO);
+ MLX5_SET(tirc, tirc, lro_max_ip_payload_size,
+ (priv->params.lro_wqe_sz -
+ ROUGH_MAX_L2_L3_HDR_SZ) >> 8);
+ MLX5_SET(tirc, tirc, lro_timeout_period_usecs,
+ MLX5_CAP_ETH(priv->mdev,
+ lro_timer_supported_periods[3]));
+ }
+
+ switch (tt) {
+ case MLX5E_TT_ANY:
+ MLX5_SET(tirc, tirc, disp_type,
+ MLX5_TIRC_DISP_TYPE_DIRECT);
+ MLX5_SET(tirc, tirc, inline_rqn,
+ priv->channel[0]->rq.rqn);
+ break;
+ default:
+ MLX5_SET(tirc, tirc, disp_type,
+ MLX5_TIRC_DISP_TYPE_INDIRECT);
+ MLX5_SET(tirc, tirc, indirect_table,
+ priv->rqtn);
+ MLX5_SET(tirc, tirc, rx_hash_fn,
+ MLX5_TIRC_RX_HASH_FN_HASH_TOEPLITZ);
+ MLX5_SET(tirc, tirc, rx_hash_symmetric, 1);
+ netdev_rss_key_fill(MLX5_ADDR_OF(tirc, tirc,
+ rx_hash_toeplitz_key),
+ MLX5_FLD_SZ_BYTES(tirc,
+ rx_hash_toeplitz_key));
+ break;
+ }
+
+ switch (tt) {
+ case MLX5E_TT_IPV4_TCP:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV4);
+ MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+ MLX5_L4_PROT_TYPE_TCP);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_ALL);
+ break;
+
+ case MLX5E_TT_IPV6_TCP:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV6);
+ MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+ MLX5_L4_PROT_TYPE_TCP);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_ALL);
+ break;
+
+ case MLX5E_TT_IPV4_UDP:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV4);
+ MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+ MLX5_L4_PROT_TYPE_UDP);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_ALL);
+ break;
+
+ case MLX5E_TT_IPV6_UDP:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV6);
+ MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+ MLX5_L4_PROT_TYPE_UDP);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_ALL);
+ break;
+
+ case MLX5E_TT_IPV4:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV4);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_IP);
+ break;
+
+ case MLX5E_TT_IPV6:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV6);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_IP);
+ break;
+ }
+}
+
+static int mlx5e_open_tir(struct mlx5e_priv *priv, int tt)
+{
+ struct mlx5_core_dev *mdev = priv->mdev;
+ u32 *in;
+ void *tirc;
+ int inlen;
+ int err;
+
+ inlen = MLX5_ST_SZ_BYTES(create_tir_in);
+ in = mlx5_vzalloc(inlen);
+ if (!in)
+ return -ENOMEM;
+
+ tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
+
+ mlx5e_build_tir_ctx(priv, tirc, tt);
+
+ err = mlx5_core_create_tir(mdev, in, inlen, &priv->tirn[tt]);
+
+ kvfree(in);
+
+ return err;
+}
+
+static void mlx5e_close_tir(struct mlx5e_priv *priv, int tt)
+{
+ mlx5_core_destroy_tir(priv->mdev, priv->tirn[tt]);
+}
+
+static int mlx5e_open_tirs(struct mlx5e_priv *priv)
+{
+ int err;
+ int i;
+
+ for (i = 0; i < MLX5E_NUM_TT; i++) {
+ err = mlx5e_open_tir(priv, i);
+ if (err)
+ goto err_close_tirs;
+ }
+
+ return 0;
+
+err_close_tirs:
+ for (i--; i >= 0; i--)
+ mlx5e_close_tir(priv, i);
+
+ return err;
+}
+
+static void mlx5e_close_tirs(struct mlx5e_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < MLX5E_NUM_TT; i++)
+ mlx5e_close_tir(priv, i);
+}
+
+static int mlx5e_set_dev_port_mtu(struct net_device *netdev)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ struct mlx5_core_dev *mdev = priv->mdev;
+ int hw_mtu;
+ int err;
+
+ err = mlx5_set_port_mtu(mdev, MLX5E_SW2HW_MTU(netdev->mtu), 1);
+ if (err)
+ return err;
+
+ mlx5_query_port_oper_mtu(mdev, &hw_mtu, 1);
+
+ if (MLX5E_HW2SW_MTU(hw_mtu) != netdev->mtu)
+ netdev_warn(netdev, "%s: Port MTU %d is different than netdev mtu %d\n",
+ __func__, MLX5E_HW2SW_MTU(hw_mtu), netdev->mtu);
+
+ netdev->mtu = MLX5E_HW2SW_MTU(hw_mtu);
+ return 0;
+}
+
+int mlx5e_open_locked(struct net_device *netdev)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ int num_txqs;
+ int err;
+
+ num_txqs = priv->params.num_channels * priv->params.num_tc;
+ netif_set_real_num_tx_queues(netdev, num_txqs);
+ netif_set_real_num_rx_queues(netdev, priv->params.num_channels);
+
+ err = mlx5e_set_dev_port_mtu(netdev);
+ if (err)
+ return err;
+
+ err = mlx5e_open_tises(priv);
+ if (err) {
+ netdev_err(netdev, "%s: mlx5e_open_tises failed, %d\n",
+ __func__, err);
+ return err;
+ }
+
+ err = mlx5e_open_channels(priv);
+ if (err) {
+ netdev_err(netdev, "%s: mlx5e_open_channels failed, %d\n",
+ __func__, err);
+ goto err_close_tises;
+ }
+
+ err = mlx5e_open_rqt(priv);
+ if (err) {
+ netdev_err(netdev, "%s: mlx5e_open_rqt failed, %d\n",
+ __func__, err);
+ goto err_close_channels;
+ }
+
+ err = mlx5e_open_tirs(priv);
+ if (err) {
+ netdev_err(netdev, "%s: mlx5e_open_tir failed, %d\n",
+ __func__, err);
+ goto err_close_rqls;
+ }
+
+ err = mlx5e_open_flow_table(priv);
+ if (err) {
+ netdev_err(netdev, "%s: mlx5e_open_flow_table failed, %d\n",
+ __func__, err);
+ goto err_close_tirs;
+ }
+
+ err = mlx5e_add_all_vlan_rules(priv);
+ if (err) {
+ netdev_err(netdev, "%s: mlx5e_add_all_vlan_rules failed, %d\n",
+ __func__, err);
+ goto err_close_flow_table;
+ }
+
+ mlx5e_init_eth_addr(priv);
+
+ set_bit(MLX5E_STATE_OPENED, &priv->state);
+
+ mlx5e_update_carrier(priv);
+ mlx5e_set_rx_mode_core(priv);
+
+ schedule_delayed_work(&priv->update_stats_work, 0);
+ return 0;
+
+err_close_flow_table:
+ mlx5e_close_flow_table(priv);
+
+err_close_tirs:
+ mlx5e_close_tirs(priv);
+
+err_close_rqls:
+ mlx5e_close_rqt(priv);
+
+err_close_channels:
+ mlx5e_close_channels(priv);
+
+err_close_tises:
+ mlx5e_close_tises(priv);
+
+ return err;
+}
+
+static int mlx5e_open(struct net_device *netdev)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ int err;
+
+ mutex_lock(&priv->state_lock);
+ err = mlx5e_open_locked(netdev);
+ mutex_unlock(&priv->state_lock);
+
+ return err;
+}
+
+int mlx5e_close_locked(struct net_device *netdev)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+
+ clear_bit(MLX5E_STATE_OPENED, &priv->state);
+
+ mlx5e_set_rx_mode_core(priv);
+ mlx5e_del_all_vlan_rules(priv);
+ netif_carrier_off(priv->netdev);
+ mlx5e_close_flow_table(priv);
+ mlx5e_close_tirs(priv);
+ mlx5e_close_rqt(priv);
+ mlx5e_close_channels(priv);
+ mlx5e_close_tises(priv);
+
+ return 0;
+}
+
+static int mlx5e_close(struct net_device *netdev)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ int err;
+
+ mutex_lock(&priv->state_lock);
+ err = mlx5e_close_locked(netdev);
+ mutex_unlock(&priv->state_lock);
+
+ return err;
+}
+
+int mlx5e_update_priv_params(struct mlx5e_priv *priv,
+ struct mlx5e_params *new_params)
+{
+ int err = 0;
+ int was_opened;
+
+ WARN_ON(!mutex_is_locked(&priv->state_lock));
+
+ was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
+ if (was_opened)
+ mlx5e_close_locked(priv->netdev);
+
+ priv->params = *new_params;
+
+ if (was_opened)
+ err = mlx5e_open_locked(priv->netdev);
+
+ return err;
+}
+
+static struct rtnl_link_stats64 *
+mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+ struct mlx5e_vport_stats *vstats = &priv->stats.vport;
+
+ stats->rx_packets = vstats->rx_packets;
+ stats->rx_bytes = vstats->rx_bytes;
+ stats->tx_packets = vstats->tx_packets;
+ stats->tx_bytes = vstats->tx_bytes;
+ stats->multicast = vstats->rx_multicast_packets +
+ vstats->tx_multicast_packets;
+ stats->tx_errors = vstats->tx_error_packets;
+ stats->rx_errors = vstats->rx_error_packets;
+ stats->tx_dropped = vstats->tx_queue_dropped;
+ stats->rx_crc_errors = 0;
+ stats->rx_length_errors = 0;
+
+ return stats;
+}
+
+static void mlx5e_set_rx_mode(struct net_device *dev)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+
+ schedule_work(&priv->set_rx_mode_work);
+}
+
+static int mlx5e_set_mac(struct net_device *netdev, void *addr)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ struct sockaddr *saddr = addr;
+
+ if (!is_valid_ether_addr(saddr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ netif_addr_lock_bh(netdev);
+ ether_addr_copy(netdev->dev_addr, saddr->sa_data);
+ netif_addr_unlock_bh(netdev);
+
+ schedule_work(&priv->set_rx_mode_work);
+
+ return 0;
+}
+
+static int mlx5e_set_features(struct net_device *netdev,
+ netdev_features_t features)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ netdev_features_t changes = features ^ netdev->features;
+ struct mlx5e_params new_params;
+ bool update_params = false;
+
+ mutex_lock(&priv->state_lock);
+ new_params = priv->params;
+
+ if (changes & NETIF_F_LRO) {
+ new_params.lro_en = !!(features & NETIF_F_LRO);
+ update_params = true;
+ }
+
+ if (update_params)
+ mlx5e_update_priv_params(priv, &new_params);
+
+ if (changes & NETIF_F_HW_VLAN_CTAG_FILTER) {
+ if (features & NETIF_F_HW_VLAN_CTAG_FILTER)
+ mlx5e_enable_vlan_filter(priv);
+ else
+ mlx5e_disable_vlan_filter(priv);
+ }
+
+ mutex_unlock(&priv->state_lock);
+
+ return 0;
+}
+
+static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ struct mlx5_core_dev *mdev = priv->mdev;
+ int max_mtu;
+ int err;
+
+ mlx5_query_port_max_mtu(mdev, &max_mtu, 1);
+
+ if (new_mtu > max_mtu) {
+ netdev_err(netdev,
+ "%s: Bad MTU (%d) > (%d) Max\n",
+ __func__, new_mtu, max_mtu);
+ return -EINVAL;
+ }
+
+ mutex_lock(&priv->state_lock);
+ netdev->mtu = new_mtu;
+ err = mlx5e_update_priv_params(priv, &priv->params);
+ mutex_unlock(&priv->state_lock);
+
+ return err;
+}
+
+static struct net_device_ops mlx5e_netdev_ops = {
+ .ndo_open = mlx5e_open,
+ .ndo_stop = mlx5e_close,
+ .ndo_start_xmit = mlx5e_xmit,
+ .ndo_get_stats64 = mlx5e_get_stats,
+ .ndo_set_rx_mode = mlx5e_set_rx_mode,
+ .ndo_set_mac_address = mlx5e_set_mac,
+ .ndo_vlan_rx_add_vid = mlx5e_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = mlx5e_vlan_rx_kill_vid,
+ .ndo_set_features = mlx5e_set_features,
+ .ndo_change_mtu = mlx5e_change_mtu,
+};
+
+static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev)
+{
+ if (MLX5_CAP_GEN(mdev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
+ return -ENOTSUPP;
+ if (!MLX5_CAP_GEN(mdev, eth_net_offloads) ||
+ !MLX5_CAP_GEN(mdev, nic_flow_table) ||
+ !MLX5_CAP_ETH(mdev, csum_cap) ||
+ !MLX5_CAP_ETH(mdev, max_lso_cap) ||
+ !MLX5_CAP_ETH(mdev, vlan_cap) ||
+ !MLX5_CAP_ETH(mdev, rss_ind_tbl_cap) ||
+ MLX5_CAP_FLOWTABLE(mdev,
+ flow_table_properties_nic_receive.max_ft_level)
+ < 3) {
+ mlx5_core_warn(mdev,
+ "Not creating net device, some required device capabilities are missing\n");
+ return -ENOTSUPP;
+ }
+ return 0;
+}
+
+static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
+ struct net_device *netdev,
+ int num_comp_vectors)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+
+ priv->params.log_sq_size =
+ MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE;
+ priv->params.log_rq_size =
+ MLX5E_PARAMS_DEFAULT_LOG_RQ_SIZE;
+ priv->params.rx_cq_moderation_usec =
+ MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC;
+ priv->params.rx_cq_moderation_pkts =
+ MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS;
+ priv->params.tx_cq_moderation_usec =
+ MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_USEC;
+ priv->params.tx_cq_moderation_pkts =
+ MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_PKTS;
+ priv->params.min_rx_wqes =
+ MLX5E_PARAMS_DEFAULT_MIN_RX_WQES;
+ priv->params.rx_hash_log_tbl_sz =
+ (order_base_2(num_comp_vectors) >
+ MLX5E_PARAMS_DEFAULT_RX_HASH_LOG_TBL_SZ) ?
+ order_base_2(num_comp_vectors) :
+ MLX5E_PARAMS_DEFAULT_RX_HASH_LOG_TBL_SZ;
+ priv->params.num_tc = 1;
+ priv->params.default_vlan_prio = 0;
+
+ priv->params.lro_en = false && !!MLX5_CAP_ETH(priv->mdev, lro_cap);
+ priv->params.lro_wqe_sz =
+ MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ;
+
+ priv->mdev = mdev;
+ priv->netdev = netdev;
+ priv->params.num_channels = num_comp_vectors;
+ priv->num_tc = priv->params.num_tc;
+ priv->default_vlan_prio = priv->params.default_vlan_prio;
+
+ spin_lock_init(&priv->async_events_spinlock);
+ mutex_init(&priv->state_lock);
+
+ INIT_WORK(&priv->update_carrier_work, mlx5e_update_carrier_work);
+ INIT_WORK(&priv->set_rx_mode_work, mlx5e_set_rx_mode_work);
+ INIT_DELAYED_WORK(&priv->update_stats_work, mlx5e_update_stats_work);
+}
+
+static void mlx5e_set_netdev_dev_addr(struct net_device *netdev)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+
+ mlx5_query_nic_vport_mac_address(priv->mdev, netdev->dev_addr);
+}
+
+static void mlx5e_build_netdev(struct net_device *netdev)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ struct mlx5_core_dev *mdev = priv->mdev;
+
+ SET_NETDEV_DEV(netdev, &mdev->pdev->dev);
+
+ if (priv->num_tc > 1) {
+ mlx5e_netdev_ops.ndo_select_queue = mlx5e_select_queue;
+ }
+
+ netdev->netdev_ops = &mlx5e_netdev_ops;
+ netdev->watchdog_timeo = 15 * HZ;
+
+ netdev->ethtool_ops = &mlx5e_ethtool_ops;
+
+ netdev->vlan_features |= NETIF_F_SG;
+ netdev->vlan_features |= NETIF_F_IP_CSUM;
+ netdev->vlan_features |= NETIF_F_IPV6_CSUM;
+ netdev->vlan_features |= NETIF_F_GRO;
+ netdev->vlan_features |= NETIF_F_TSO;
+ netdev->vlan_features |= NETIF_F_TSO6;
+ netdev->vlan_features |= NETIF_F_RXCSUM;
+ netdev->vlan_features |= NETIF_F_RXHASH;
+
+ if (!!MLX5_CAP_ETH(mdev, lro_cap))
+ netdev->vlan_features |= NETIF_F_LRO;
+
+ netdev->hw_features = netdev->vlan_features;
+ netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
+ netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+
+ netdev->features = netdev->hw_features;
+ if (!priv->params.lro_en)
+ netdev->features &= ~NETIF_F_LRO;
+
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ netdev->priv_flags |= IFF_UNICAST_FLT;
+
+ mlx5e_set_netdev_dev_addr(netdev);
+}
+
+static int mlx5e_create_mkey(struct mlx5e_priv *priv, u32 pdn,
+ struct mlx5_core_mr *mr)
+{
+ struct mlx5_core_dev *mdev = priv->mdev;
+ struct mlx5_create_mkey_mbox_in *in;
+ int err;
+
+ in = mlx5_vzalloc(sizeof(*in));
+ if (!in)
+ return -ENOMEM;
+
+ in->seg.flags = MLX5_PERM_LOCAL_WRITE |
+ MLX5_PERM_LOCAL_READ |
+ MLX5_ACCESS_MODE_PA;
+ in->seg.flags_pd = cpu_to_be32(pdn | MLX5_MKEY_LEN64);
+ in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
+
+ err = mlx5_core_create_mkey(mdev, mr, in, sizeof(*in), NULL, NULL,
+ NULL);
+
+ kvfree(in);
+
+ return err;
+}
+
+static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev)
+{
+ struct net_device *netdev;
+ struct mlx5e_priv *priv;
+ int ncv = mdev->priv.eq_table.num_comp_vectors;
+ int err;
+
+ if (mlx5e_check_required_hca_cap(mdev))
+ return NULL;
+
+ netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv), ncv, ncv);
+ if (!netdev) {
+ mlx5_core_err(mdev, "alloc_etherdev_mqs() failed\n");
+ return NULL;
+ }
+
+ mlx5e_build_netdev_priv(mdev, netdev, ncv);
+ mlx5e_build_netdev(netdev);
+
+ netif_carrier_off(netdev);
+
+ priv = netdev_priv(netdev);
+
+ err = mlx5_alloc_map_uar(mdev, &priv->cq_uar);
+ if (err) {
+ netdev_err(netdev, "%s: mlx5_alloc_map_uar failed, %d\n",
+ __func__, err);
+ goto err_free_netdev;
+ }
+
+ err = mlx5_core_alloc_pd(mdev, &priv->pdn);
+ if (err) {
+ netdev_err(netdev, "%s: mlx5_core_alloc_pd failed, %d\n",
+ __func__, err);
+ goto err_unmap_free_uar;
+ }
+
+ err = mlx5_alloc_transport_domain(mdev, &priv->tdn);
+ if (err) {
+ netdev_err(netdev, "%s: mlx5_alloc_transport_domain failed, %d\n",
+ __func__, err);
+ goto err_dealloc_pd;
+ }
+
+ err = mlx5e_create_mkey(priv, priv->pdn, &priv->mr);
+ if (err) {
+ netdev_err(netdev, "%s: mlx5e_create_mkey failed, %d\n",
+ __func__, err);
+ goto err_dealloc_transport_domain;
+ }
+
+ err = register_netdev(netdev);
+ if (err) {
+ netdev_err(netdev, "%s: register_netdev failed, %d\n",
+ __func__, err);
+ goto err_destroy_mkey;
+ }
+
+ mlx5e_enable_async_events(priv);
+
+ return priv;
+
+err_destroy_mkey:
+ mlx5_core_destroy_mkey(mdev, &priv->mr);
+
+err_dealloc_transport_domain:
+ mlx5_dealloc_transport_domain(mdev, priv->tdn);
+
+err_dealloc_pd:
+ mlx5_core_dealloc_pd(mdev, priv->pdn);
+
+err_unmap_free_uar:
+ mlx5_unmap_free_uar(mdev, &priv->cq_uar);
+
+err_free_netdev:
+ free_netdev(netdev);
+
+ return NULL;
+}
+
+static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv)
+{
+ struct mlx5e_priv *priv = vpriv;
+ struct net_device *netdev = priv->netdev;
+
+ unregister_netdev(netdev);
+ mlx5_core_destroy_mkey(priv->mdev, &priv->mr);
+ mlx5_dealloc_transport_domain(priv->mdev, priv->tdn);
+ mlx5_core_dealloc_pd(priv->mdev, priv->pdn);
+ mlx5_unmap_free_uar(priv->mdev, &priv->cq_uar);
+ mlx5e_disable_async_events(priv);
+ flush_scheduled_work();
+ free_netdev(netdev);
+}
+
+static void *mlx5e_get_netdev(void *vpriv)
+{
+ struct mlx5e_priv *priv = vpriv;
+
+ return priv->netdev;
+}
+
+static struct mlx5_interface mlx5e_interface = {
+ .add = mlx5e_create_netdev,
+ .remove = mlx5e_destroy_netdev,
+ .event = mlx5e_async_event,
+ .protocol = MLX5_INTERFACE_PROTOCOL_ETH,
+ .get_dev = mlx5e_get_netdev,
+};
+
+void mlx5e_init(void)
+{
+ mlx5_register_interface(&mlx5e_interface);
+}
+
+void mlx5e_cleanup(void)
+{
+ mlx5_unregister_interface(&mlx5e_interface);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
new file mode 100644
index 000000000000..9a9374131f5b
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ */
+
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include "en.h"
+
+static inline int mlx5e_alloc_rx_wqe(struct mlx5e_rq *rq,
+ struct mlx5e_rx_wqe *wqe, u16 ix)
+{
+ struct sk_buff *skb;
+ dma_addr_t dma_addr;
+
+ skb = netdev_alloc_skb(rq->netdev, rq->wqe_sz);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ dma_addr = dma_map_single(rq->pdev,
+ /* hw start padding */
+ skb->data,
+ /* hw end padding */
+ rq->wqe_sz,
+ DMA_FROM_DEVICE);
+
+ if (unlikely(dma_mapping_error(rq->pdev, dma_addr)))
+ goto err_free_skb;
+
+ skb_reserve(skb, MLX5E_NET_IP_ALIGN);
+
+ *((dma_addr_t *)skb->cb) = dma_addr;
+ wqe->data.addr = cpu_to_be64(dma_addr + MLX5E_NET_IP_ALIGN);
+
+ rq->skb[ix] = skb;
+
+ return 0;
+
+err_free_skb:
+ dev_kfree_skb(skb);
+
+ return -ENOMEM;
+}
+
+bool mlx5e_post_rx_wqes(struct mlx5e_rq *rq)
+{
+ struct mlx5_wq_ll *wq = &rq->wq;
+
+ if (unlikely(!test_bit(MLX5E_RQ_STATE_POST_WQES_ENABLE, &rq->state)))
+ return false;
+
+ while (!mlx5_wq_ll_is_full(wq)) {
+ struct mlx5e_rx_wqe *wqe = mlx5_wq_ll_get_wqe(wq, wq->head);
+
+ if (unlikely(mlx5e_alloc_rx_wqe(rq, wqe, wq->head)))
+ break;
+
+ mlx5_wq_ll_push(wq, be16_to_cpu(wqe->next.next_wqe_index));
+ }
+
+ /* ensure wqes are visible to device before updating doorbell record */
+ dma_wmb();
+
+ mlx5_wq_ll_update_db_record(wq);
+
+ return !mlx5_wq_ll_is_full(wq);
+}
+
+static void mlx5e_lro_update_hdr(struct sk_buff *skb, struct mlx5_cqe64 *cqe)
+{
+ struct ethhdr *eth = (struct ethhdr *)(skb->data);
+ struct iphdr *ipv4 = (struct iphdr *)(skb->data + ETH_HLEN);
+ struct ipv6hdr *ipv6 = (struct ipv6hdr *)(skb->data + ETH_HLEN);
+ struct tcphdr *tcp;
+
+ u8 l4_hdr_type = get_cqe_l4_hdr_type(cqe);
+ int tcp_ack = ((CQE_L4_HDR_TYPE_TCP_ACK_NO_DATA == l4_hdr_type) ||
+ (CQE_L4_HDR_TYPE_TCP_ACK_AND_DATA == l4_hdr_type));
+
+ u16 tot_len = be32_to_cpu(cqe->byte_cnt) - ETH_HLEN;
+
+ if (eth->h_proto == htons(ETH_P_IP)) {
+ tcp = (struct tcphdr *)(skb->data + ETH_HLEN +
+ sizeof(struct iphdr));
+ ipv6 = NULL;
+ } else {
+ tcp = (struct tcphdr *)(skb->data + ETH_HLEN +
+ sizeof(struct ipv6hdr));
+ ipv4 = NULL;
+ }
+
+ if (get_cqe_lro_tcppsh(cqe))
+ tcp->psh = 1;
+
+ if (tcp_ack) {
+ tcp->ack = 1;
+ tcp->ack_seq = cqe->lro_ack_seq_num;
+ tcp->window = cqe->lro_tcp_win;
+ }
+
+ if (ipv4) {
+ ipv4->ttl = cqe->lro_min_ttl;
+ ipv4->tot_len = cpu_to_be16(tot_len);
+ ipv4->check = 0;
+ ipv4->check = ip_fast_csum((unsigned char *)ipv4,
+ ipv4->ihl);
+ } else {
+ ipv6->hop_limit = cqe->lro_min_ttl;
+ ipv6->payload_len = cpu_to_be16(tot_len -
+ sizeof(struct ipv6hdr));
+ }
+}
+
+static inline void mlx5e_skb_set_hash(struct mlx5_cqe64 *cqe,
+ struct sk_buff *skb)
+{
+ u8 cht = cqe->rss_hash_type;
+ int ht = (cht & CQE_RSS_HTYPE_L4) ? PKT_HASH_TYPE_L4 :
+ (cht & CQE_RSS_HTYPE_IP) ? PKT_HASH_TYPE_L3 :
+ PKT_HASH_TYPE_NONE;
+ skb_set_hash(skb, be32_to_cpu(cqe->rss_hash_result), ht);
+}
+
+static inline void mlx5e_build_rx_skb(struct mlx5_cqe64 *cqe,
+ struct mlx5e_rq *rq,
+ struct sk_buff *skb)
+{
+ struct net_device *netdev = rq->netdev;
+ u32 cqe_bcnt = be32_to_cpu(cqe->byte_cnt);
+ int lro_num_seg;
+
+ skb_put(skb, cqe_bcnt);
+
+ lro_num_seg = be32_to_cpu(cqe->srqn) >> 24;
+ if (lro_num_seg > 1) {
+ mlx5e_lro_update_hdr(skb, cqe);
+ skb_shinfo(skb)->gso_size = MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ;
+ rq->stats.lro_packets++;
+ rq->stats.lro_bytes += cqe_bcnt;
+ }
+
+ if (likely(netdev->features & NETIF_F_RXCSUM) &&
+ (cqe->hds_ip_ext & CQE_L2_OK) &&
+ (cqe->hds_ip_ext & CQE_L3_OK) &&
+ (cqe->hds_ip_ext & CQE_L4_OK)) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ skb->ip_summed = CHECKSUM_NONE;
+ rq->stats.csum_none++;
+ }
+
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ skb_record_rx_queue(skb, rq->ix);
+
+ if (likely(netdev->features & NETIF_F_RXHASH))
+ mlx5e_skb_set_hash(cqe, skb);
+
+ if (cqe_has_vlan(cqe))
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+ be16_to_cpu(cqe->vlan_info));
+}
+
+bool mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
+{
+ struct mlx5e_rq *rq = container_of(cq, struct mlx5e_rq, cq);
+ int i;
+
+ /* avoid accessing cq (dma coherent memory) if not needed */
+ if (!test_and_clear_bit(MLX5E_CQ_HAS_CQES, &cq->flags))
+ return false;
+
+ for (i = 0; i < budget; i++) {
+ struct mlx5e_rx_wqe *wqe;
+ struct mlx5_cqe64 *cqe;
+ struct sk_buff *skb;
+ __be16 wqe_counter_be;
+ u16 wqe_counter;
+
+ cqe = mlx5e_get_cqe(cq);
+ if (!cqe)
+ break;
+
+ mlx5_cqwq_pop(&cq->wq);
+
+ wqe_counter_be = cqe->wqe_counter;
+ wqe_counter = be16_to_cpu(wqe_counter_be);
+ wqe = mlx5_wq_ll_get_wqe(&rq->wq, wqe_counter);
+ skb = rq->skb[wqe_counter];
+ prefetch(skb->data);
+ rq->skb[wqe_counter] = NULL;
+
+ dma_unmap_single(rq->pdev,
+ *((dma_addr_t *)skb->cb),
+ rq->wqe_sz,
+ DMA_FROM_DEVICE);
+
+ if (unlikely((cqe->op_own >> 4) != MLX5_CQE_RESP_SEND)) {
+ rq->stats.wqe_err++;
+ dev_kfree_skb(skb);
+ goto wq_ll_pop;
+ }
+
+ mlx5e_build_rx_skb(cqe, rq, skb);
+ rq->stats.packets++;
+ napi_gro_receive(cq->napi, skb);
+
+wq_ll_pop:
+ mlx5_wq_ll_pop(&rq->wq, wqe_counter_be,
+ &wqe->next.next_wqe_index);
+ }
+
+ mlx5_cqwq_update_db_record(&cq->wq);
+
+ /* ensure cq space is freed before enabling more cqes */
+ wmb();
+
+ if (i == budget) {
+ set_bit(MLX5E_CQ_HAS_CQES, &cq->flags);
+ return true;
+ }
+
+ return false;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
new file mode 100644
index 000000000000..03f28f438e55
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ */
+
+#include <linux/tcp.h>
+#include <linux/if_vlan.h>
+#include "en.h"
+
+#define MLX5E_SQ_NOPS_ROOM MLX5_SEND_WQE_MAX_WQEBBS
+#define MLX5E_SQ_STOP_ROOM (MLX5_SEND_WQE_MAX_WQEBBS +\
+ MLX5E_SQ_NOPS_ROOM)
+
+void mlx5e_send_nop(struct mlx5e_sq *sq, bool notify_hw)
+{
+ struct mlx5_wq_cyc *wq = &sq->wq;
+
+ u16 pi = sq->pc & wq->sz_m1;
+ struct mlx5e_tx_wqe *wqe = mlx5_wq_cyc_get_wqe(wq, pi);
+
+ struct mlx5_wqe_ctrl_seg *cseg = &wqe->ctrl;
+
+ memset(cseg, 0, sizeof(*cseg));
+
+ cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | MLX5_OPCODE_NOP);
+ cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | 0x01);
+
+ sq->skb[pi] = NULL;
+ sq->pc++;
+
+ if (notify_hw) {
+ cseg->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE;
+ mlx5e_tx_notify_hw(sq, wqe);
+ }
+}
+
+static void mlx5e_dma_pop_last_pushed(struct mlx5e_sq *sq, dma_addr_t *addr,
+ u32 *size)
+{
+ sq->dma_fifo_pc--;
+ *addr = sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].addr;
+ *size = sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].size;
+}
+
+static void mlx5e_dma_unmap_wqe_err(struct mlx5e_sq *sq, struct sk_buff *skb)
+{
+ dma_addr_t addr;
+ u32 size;
+ int i;
+
+ for (i = 0; i < MLX5E_TX_SKB_CB(skb)->num_dma; i++) {
+ mlx5e_dma_pop_last_pushed(sq, &addr, &size);
+ dma_unmap_single(sq->pdev, addr, size, DMA_TO_DEVICE);
+ }
+}
+
+static inline void mlx5e_dma_push(struct mlx5e_sq *sq, dma_addr_t addr,
+ u32 size)
+{
+ sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].addr = addr;
+ sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].size = size;
+ sq->dma_fifo_pc++;
+}
+
+static inline void mlx5e_dma_get(struct mlx5e_sq *sq, u32 i, dma_addr_t *addr,
+ u32 *size)
+{
+ *addr = sq->dma_fifo[i & sq->dma_fifo_mask].addr;
+ *size = sq->dma_fifo[i & sq->dma_fifo_mask].size;
+}
+
+u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb,
+ void *accel_priv, select_queue_fallback_t fallback)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+ int channel_ix = fallback(dev, skb);
+ int up = skb_vlan_tag_present(skb) ?
+ skb->vlan_tci >> VLAN_PRIO_SHIFT :
+ priv->default_vlan_prio;
+ int tc = netdev_get_prio_tc_map(dev, up);
+
+ return priv->channel[channel_ix]->tc_to_txq_map[tc];
+}
+
+static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq,
+ struct sk_buff *skb)
+{
+#define MLX5E_MIN_INLINE 16 /* eth header with vlan (w/o next ethertype) */
+ return MLX5E_MIN_INLINE;
+}
+
+static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)
+{
+ struct mlx5_wq_cyc *wq = &sq->wq;
+
+ u16 pi = sq->pc & wq->sz_m1;
+ struct mlx5e_tx_wqe *wqe = mlx5_wq_cyc_get_wqe(wq, pi);
+
+ struct mlx5_wqe_ctrl_seg *cseg = &wqe->ctrl;
+ struct mlx5_wqe_eth_seg *eseg = &wqe->eth;
+ struct mlx5_wqe_data_seg *dseg;
+
+ u8 opcode = MLX5_OPCODE_SEND;
+ dma_addr_t dma_addr = 0;
+ u16 headlen;
+ u16 ds_cnt;
+ u16 ihs;
+ int i;
+
+ memset(wqe, 0, sizeof(*wqe));
+
+ if (likely(skb->ip_summed == CHECKSUM_PARTIAL))
+ eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
+ else
+ sq->stats.csum_offload_none++;
+
+ if (skb_is_gso(skb)) {
+ u32 payload_len;
+
+ eseg->mss = cpu_to_be16(skb_shinfo(skb)->gso_size);
+ opcode = MLX5_OPCODE_LSO;
+ ihs = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ payload_len = skb->len - ihs;
+ MLX5E_TX_SKB_CB(skb)->num_bytes = skb->len +
+ (skb_shinfo(skb)->gso_segs - 1) * ihs;
+ sq->stats.tso_packets++;
+ sq->stats.tso_bytes += payload_len;
+ } else {
+ ihs = mlx5e_get_inline_hdr_size(sq, skb);
+ MLX5E_TX_SKB_CB(skb)->num_bytes = max_t(unsigned int, skb->len,
+ ETH_ZLEN);
+ }
+
+ skb_copy_from_linear_data(skb, eseg->inline_hdr_start, ihs);
+ skb_pull_inline(skb, ihs);
+
+ eseg->inline_hdr_sz = cpu_to_be16(ihs);
+
+ ds_cnt = sizeof(*wqe) / MLX5_SEND_WQE_DS;
+ ds_cnt += DIV_ROUND_UP(ihs - sizeof(eseg->inline_hdr_start),
+ MLX5_SEND_WQE_DS);
+ dseg = (struct mlx5_wqe_data_seg *)cseg + ds_cnt;
+
+ MLX5E_TX_SKB_CB(skb)->num_dma = 0;
+
+ headlen = skb_headlen(skb);
+ if (headlen) {
+ dma_addr = dma_map_single(sq->pdev, skb->data, headlen,
+ DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(sq->pdev, dma_addr)))
+ goto dma_unmap_wqe_err;
+
+ dseg->addr = cpu_to_be64(dma_addr);
+ dseg->lkey = sq->mkey_be;
+ dseg->byte_count = cpu_to_be32(headlen);
+
+ mlx5e_dma_push(sq, dma_addr, headlen);
+ MLX5E_TX_SKB_CB(skb)->num_dma++;
+
+ dseg++;
+ }
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
+ int fsz = skb_frag_size(frag);
+
+ dma_addr = skb_frag_dma_map(sq->pdev, frag, 0, fsz,
+ DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(sq->pdev, dma_addr)))
+ goto dma_unmap_wqe_err;
+
+ dseg->addr = cpu_to_be64(dma_addr);
+ dseg->lkey = sq->mkey_be;
+ dseg->byte_count = cpu_to_be32(fsz);
+
+ mlx5e_dma_push(sq, dma_addr, fsz);
+ MLX5E_TX_SKB_CB(skb)->num_dma++;
+
+ dseg++;
+ }
+
+ ds_cnt += MLX5E_TX_SKB_CB(skb)->num_dma;
+
+ cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | opcode);
+ cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | ds_cnt);
+
+ sq->skb[pi] = skb;
+
+ MLX5E_TX_SKB_CB(skb)->num_wqebbs = DIV_ROUND_UP(ds_cnt,
+ MLX5_SEND_WQEBB_NUM_DS);
+ sq->pc += MLX5E_TX_SKB_CB(skb)->num_wqebbs;
+
+ netdev_tx_sent_queue(sq->txq, MLX5E_TX_SKB_CB(skb)->num_bytes);
+
+ if (unlikely(!mlx5e_sq_has_room_for(sq, MLX5E_SQ_STOP_ROOM))) {
+ netif_tx_stop_queue(sq->txq);
+ sq->stats.stopped++;
+ }
+
+ if (!skb->xmit_more || netif_xmit_stopped(sq->txq)) {
+ cseg->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE;
+ mlx5e_tx_notify_hw(sq, wqe);
+ }
+
+ /* fill sq edge with nops to avoid wqe wrap around */
+ while ((sq->pc & wq->sz_m1) > sq->edge)
+ mlx5e_send_nop(sq, false);
+
+ sq->stats.packets++;
+ return NETDEV_TX_OK;
+
+dma_unmap_wqe_err:
+ sq->stats.dropped++;
+ mlx5e_dma_unmap_wqe_err(sq, skb);
+
+ dev_kfree_skb_any(skb);
+
+ return NETDEV_TX_OK;
+}
+
+netdev_tx_t mlx5e_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+ struct mlx5e_sq *sq = priv->txq_to_sq_map[skb_get_queue_mapping(skb)];
+
+ return mlx5e_sq_xmit(sq, skb);
+}
+
+bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq)
+{
+ struct mlx5e_sq *sq;
+ u32 dma_fifo_cc;
+ u32 nbytes;
+ u16 npkts;
+ u16 sqcc;
+ int i;
+
+ /* avoid accessing cq (dma coherent memory) if not needed */
+ if (!test_and_clear_bit(MLX5E_CQ_HAS_CQES, &cq->flags))
+ return false;
+
+ sq = container_of(cq, struct mlx5e_sq, cq);
+
+ npkts = 0;
+ nbytes = 0;
+
+ /* sq->cc must be updated only after mlx5_cqwq_update_db_record(),
+ * otherwise a cq overrun may occur
+ */
+ sqcc = sq->cc;
+
+ /* avoid dirtying sq cache line every cqe */
+ dma_fifo_cc = sq->dma_fifo_cc;
+
+ for (i = 0; i < MLX5E_TX_CQ_POLL_BUDGET; i++) {
+ struct mlx5_cqe64 *cqe;
+ u16 wqe_counter;
+ bool last_wqe;
+
+ cqe = mlx5e_get_cqe(cq);
+ if (!cqe)
+ break;
+
+ mlx5_cqwq_pop(&cq->wq);
+
+ wqe_counter = be16_to_cpu(cqe->wqe_counter);
+
+ do {
+ struct sk_buff *skb;
+ u16 ci;
+ int j;
+
+ last_wqe = (sqcc == wqe_counter);
+
+ ci = sqcc & sq->wq.sz_m1;
+ skb = sq->skb[ci];
+
+ if (unlikely(!skb)) { /* nop */
+ sq->stats.nop++;
+ sqcc++;
+ continue;
+ }
+
+ for (j = 0; j < MLX5E_TX_SKB_CB(skb)->num_dma; j++) {
+ dma_addr_t addr;
+ u32 size;
+
+ mlx5e_dma_get(sq, dma_fifo_cc, &addr, &size);
+ dma_fifo_cc++;
+ dma_unmap_single(sq->pdev, addr, size,
+ DMA_TO_DEVICE);
+ }
+
+ npkts++;
+ nbytes += MLX5E_TX_SKB_CB(skb)->num_bytes;
+ sqcc += MLX5E_TX_SKB_CB(skb)->num_wqebbs;
+ dev_kfree_skb(skb);
+ } while (!last_wqe);
+ }
+
+ mlx5_cqwq_update_db_record(&cq->wq);
+
+ /* ensure cq space is freed before enabling more cqes */
+ wmb();
+
+ sq->dma_fifo_cc = dma_fifo_cc;
+ sq->cc = sqcc;
+
+ netdev_tx_completed_queue(sq->txq, npkts, nbytes);
+
+ if (netif_tx_queue_stopped(sq->txq) &&
+ mlx5e_sq_has_room_for(sq, MLX5E_SQ_STOP_ROOM) &&
+ likely(test_bit(MLX5E_SQ_STATE_WAKE_TXQ_ENABLE, &sq->state))) {
+ netif_tx_wake_queue(sq->txq);
+ sq->stats.wake++;
+ }
+ if (i == MLX5E_TX_CQ_POLL_BUDGET) {
+ set_bit(MLX5E_CQ_HAS_CQES, &cq->flags);
+ return true;
+ }
+
+ return false;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
new file mode 100644
index 000000000000..2c7cb6755d1d
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ */
+
+#include "en.h"
+
+struct mlx5_cqe64 *mlx5e_get_cqe(struct mlx5e_cq *cq)
+{
+ struct mlx5_cqwq *wq = &cq->wq;
+ u32 ci = mlx5_cqwq_get_ci(wq);
+ struct mlx5_cqe64 *cqe = mlx5_cqwq_get_wqe(wq, ci);
+ int cqe_ownership_bit = cqe->op_own & MLX5_CQE_OWNER_MASK;
+ int sw_ownership_val = mlx5_cqwq_get_wrap_cnt(wq) & 1;
+
+ if (cqe_ownership_bit != sw_ownership_val)
+ return NULL;
+
+ /* ensure cqe content is read after cqe ownership bit */
+ rmb();
+
+ return cqe;
+}
+
+int mlx5e_napi_poll(struct napi_struct *napi, int budget)
+{
+ struct mlx5e_channel *c = container_of(napi, struct mlx5e_channel,
+ napi);
+ bool busy = false;
+ int i;
+
+ clear_bit(MLX5E_CHANNEL_NAPI_SCHED, &c->flags);
+
+ for (i = 0; i < c->num_tc; i++)
+ busy |= mlx5e_poll_tx_cq(&c->sq[i].cq);
+
+ busy |= mlx5e_poll_rx_cq(&c->rq.cq, budget);
+
+ busy |= mlx5e_post_rx_wqes(&c->rq);
+
+ if (busy)
+ return budget;
+
+ napi_complete(napi);
+
+ /* avoid losing completion event during/after polling cqs */
+ if (test_bit(MLX5E_CHANNEL_NAPI_SCHED, &c->flags)) {
+ napi_schedule(napi);
+ return 0;
+ }
+
+ for (i = 0; i < c->num_tc; i++)
+ mlx5e_cq_arm(&c->sq[i].cq);
+ mlx5e_cq_arm(&c->rq.cq);
+
+ return 0;
+}
+
+void mlx5e_completion_event(struct mlx5_core_cq *mcq)
+{
+ struct mlx5e_cq *cq = container_of(mcq, struct mlx5e_cq, mcq);
+
+ set_bit(MLX5E_CQ_HAS_CQES, &cq->flags);
+ set_bit(MLX5E_CHANNEL_NAPI_SCHED, &cq->channel->flags);
+ barrier();
+ napi_schedule(cq->napi);
+}
+
+void mlx5e_cq_error_event(struct mlx5_core_cq *mcq, enum mlx5_event event)
+{
+ struct mlx5e_cq *cq = container_of(mcq, struct mlx5e_cq, mcq);
+ struct mlx5e_channel *c = cq->channel;
+ struct mlx5e_priv *priv = c->priv;
+ struct net_device *netdev = priv->netdev;
+
+ netdev_err(netdev, "%s: cqn=0x%.6x event=0x%.2x\n",
+ __func__, mcq->cqn, event);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index 58800e4f3958..a40b96d4c662 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -339,15 +339,14 @@ static void init_eq_buf(struct mlx5_eq *eq)
int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx,
int nent, u64 mask, const char *name, struct mlx5_uar *uar)
{
- struct mlx5_eq_table *table = &dev->priv.eq_table;
+ struct mlx5_priv *priv = &dev->priv;
struct mlx5_create_eq_mbox_in *in;
struct mlx5_create_eq_mbox_out out;
int err;
int inlen;
eq->nent = roundup_pow_of_two(nent + MLX5_NUM_SPARE_EQE);
- err = mlx5_buf_alloc(dev, eq->nent * MLX5_EQE_SIZE, 2 * PAGE_SIZE,
- &eq->buf);
+ err = mlx5_buf_alloc(dev, eq->nent * MLX5_EQE_SIZE, &eq->buf);
if (err)
return err;
@@ -378,14 +377,15 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx,
goto err_in;
}
- snprintf(eq->name, MLX5_MAX_EQ_NAME, "%s@pci:%s",
+ snprintf(priv->irq_info[vecidx].name, MLX5_MAX_IRQ_NAME, "%s@pci:%s",
name, pci_name(dev->pdev));
+
eq->eqn = out.eq_number;
eq->irqn = vecidx;
eq->dev = dev;
eq->doorbell = uar->map + MLX5_EQ_DOORBEL_OFFSET;
- err = request_irq(table->msix_arr[vecidx].vector, mlx5_msix_handler, 0,
- eq->name, eq);
+ err = request_irq(priv->msix_arr[vecidx].vector, mlx5_msix_handler, 0,
+ priv->irq_info[vecidx].name, eq);
if (err)
goto err_eq;
@@ -401,7 +401,7 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx,
return 0;
err_irq:
- free_irq(table->msix_arr[vecidx].vector, eq);
+ free_irq(priv->msix_arr[vecidx].vector, eq);
err_eq:
mlx5_cmd_destroy_eq(dev, eq->eqn);
@@ -417,16 +417,15 @@ EXPORT_SYMBOL_GPL(mlx5_create_map_eq);
int mlx5_destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
{
- struct mlx5_eq_table *table = &dev->priv.eq_table;
int err;
mlx5_debug_eq_remove(dev, eq);
- free_irq(table->msix_arr[eq->irqn].vector, eq);
+ free_irq(dev->priv.msix_arr[eq->irqn].vector, eq);
err = mlx5_cmd_destroy_eq(dev, eq->eqn);
if (err)
mlx5_core_warn(dev, "failed to destroy a previously created eq: eqn %d\n",
eq->eqn);
- synchronize_irq(table->msix_arr[eq->irqn].vector);
+ synchronize_irq(dev->priv.msix_arr[eq->irqn].vector);
mlx5_buf_free(dev, &eq->buf);
return err;
@@ -456,7 +455,7 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev)
u32 async_event_mask = MLX5_ASYNC_EVENT_MASK;
int err;
- if (dev->caps.gen.flags & MLX5_DEV_CAP_FLAG_ON_DMND_PG)
+ if (MLX5_CAP_GEN(dev, pg))
async_event_mask |= (1ull << MLX5_EVENT_TYPE_PAGE_FAULT);
err = mlx5_create_map_eq(dev, &table->cmd_eq, MLX5_EQ_VEC_CMD,
@@ -479,7 +478,7 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev)
err = mlx5_create_map_eq(dev, &table->pages_eq,
MLX5_EQ_VEC_PAGES,
- dev->caps.gen.max_vf + 1,
+ /* TODO: sriov max_vf + */ 1,
1 << MLX5_EVENT_TYPE_PAGE_REQUEST, "mlx5_pages_eq",
&dev->priv.uuari.uars[0]);
if (err) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/flow_table.c b/drivers/net/ethernet/mellanox/mlx5/core/flow_table.c
new file mode 100644
index 000000000000..ca90b9bc3b95
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/flow_table.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ */
+
+#include <linux/export.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/flow_table.h>
+#include "mlx5_core.h"
+
+struct mlx5_ftg {
+ struct mlx5_flow_table_group g;
+ u32 id;
+ u32 start_ix;
+};
+
+struct mlx5_flow_table {
+ struct mlx5_core_dev *dev;
+ u8 level;
+ u8 type;
+ u32 id;
+ struct mutex mutex; /* sync bitmap alloc */
+ u16 num_groups;
+ struct mlx5_ftg *group;
+ unsigned long *bitmap;
+ u32 size;
+};
+
+static int mlx5_set_flow_entry_cmd(struct mlx5_flow_table *ft, u32 group_ix,
+ u32 flow_index, void *flow_context)
+{
+ u32 out[MLX5_ST_SZ_DW(set_fte_out)];
+ u32 *in;
+ void *in_flow_context;
+ int fcdls =
+ MLX5_GET(flow_context, flow_context, destination_list_size) *
+ MLX5_ST_SZ_BYTES(dest_format_struct);
+ int inlen = MLX5_ST_SZ_BYTES(set_fte_in) + fcdls;
+ int err;
+
+ in = mlx5_vzalloc(inlen);
+ if (!in) {
+ mlx5_core_warn(ft->dev, "failed to allocate inbox\n");
+ return -ENOMEM;
+ }
+
+ MLX5_SET(set_fte_in, in, table_type, ft->type);
+ MLX5_SET(set_fte_in, in, table_id, ft->id);
+ MLX5_SET(set_fte_in, in, flow_index, flow_index);
+ MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY);
+
+ in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context);
+ memcpy(in_flow_context, flow_context,
+ MLX5_ST_SZ_BYTES(flow_context) + fcdls);
+
+ MLX5_SET(flow_context, in_flow_context, group_id,
+ ft->group[group_ix].id);
+
+ memset(out, 0, sizeof(out));
+ err = mlx5_cmd_exec_check_status(ft->dev, in, inlen, out,
+ sizeof(out));
+ kvfree(in);
+
+ return err;
+}
+
+static void mlx5_del_flow_entry_cmd(struct mlx5_flow_table *ft, u32 flow_index)
+{
+ u32 in[MLX5_ST_SZ_DW(delete_fte_in)];
+ u32 out[MLX5_ST_SZ_DW(delete_fte_out)];
+
+ memset(in, 0, sizeof(in));
+ memset(out, 0, sizeof(out));
+
+#define MLX5_SET_DFTEI(p, x, v) MLX5_SET(delete_fte_in, p, x, v)
+ MLX5_SET_DFTEI(in, table_type, ft->type);
+ MLX5_SET_DFTEI(in, table_id, ft->id);
+ MLX5_SET_DFTEI(in, flow_index, flow_index);
+ MLX5_SET_DFTEI(in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY);
+
+ mlx5_cmd_exec_check_status(ft->dev, in, sizeof(in), out, sizeof(out));
+}
+
+static void mlx5_destroy_flow_group_cmd(struct mlx5_flow_table *ft, int i)
+{
+ u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)];
+ u32 out[MLX5_ST_SZ_DW(destroy_flow_group_out)];
+
+ memset(in, 0, sizeof(in));
+ memset(out, 0, sizeof(out));
+
+#define MLX5_SET_DFGI(p, x, v) MLX5_SET(destroy_flow_group_in, p, x, v)
+ MLX5_SET_DFGI(in, table_type, ft->type);
+ MLX5_SET_DFGI(in, table_id, ft->id);
+ MLX5_SET_DFGI(in, opcode, MLX5_CMD_OP_DESTROY_FLOW_GROUP);
+ MLX5_SET_DFGI(in, group_id, ft->group[i].id);
+ mlx5_cmd_exec_check_status(ft->dev, in, sizeof(in), out, sizeof(out));
+}
+
+static int mlx5_create_flow_group_cmd(struct mlx5_flow_table *ft, int i)
+{
+ u32 out[MLX5_ST_SZ_DW(create_flow_group_out)];
+ u32 *in;
+ void *in_match_criteria;
+ int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
+ struct mlx5_flow_table_group *g = &ft->group[i].g;
+ u32 start_ix = ft->group[i].start_ix;
+ u32 end_ix = start_ix + (1 << g->log_sz) - 1;
+ int err;
+
+ in = mlx5_vzalloc(inlen);
+ if (!in) {
+ mlx5_core_warn(ft->dev, "failed to allocate inbox\n");
+ return -ENOMEM;
+ }
+ in_match_criteria = MLX5_ADDR_OF(create_flow_group_in, in,
+ match_criteria);
+
+ memset(out, 0, sizeof(out));
+
+#define MLX5_SET_CFGI(p, x, v) MLX5_SET(create_flow_group_in, p, x, v)
+ MLX5_SET_CFGI(in, table_type, ft->type);
+ MLX5_SET_CFGI(in, table_id, ft->id);
+ MLX5_SET_CFGI(in, opcode, MLX5_CMD_OP_CREATE_FLOW_GROUP);
+ MLX5_SET_CFGI(in, start_flow_index, start_ix);
+ MLX5_SET_CFGI(in, end_flow_index, end_ix);
+ MLX5_SET_CFGI(in, match_criteria_enable, g->match_criteria_enable);
+
+ memcpy(in_match_criteria, g->match_criteria,
+ MLX5_ST_SZ_BYTES(fte_match_param));
+
+ err = mlx5_cmd_exec_check_status(ft->dev, in, inlen, out,
+ sizeof(out));
+ if (!err)
+ ft->group[i].id = MLX5_GET(create_flow_group_out, out,
+ group_id);
+
+ kvfree(in);
+
+ return err;
+}
+
+static void mlx5_destroy_flow_table_groups(struct mlx5_flow_table *ft)
+{
+ int i;
+
+ for (i = 0; i < ft->num_groups; i++)
+ mlx5_destroy_flow_group_cmd(ft, i);
+}
+
+static int mlx5_create_flow_table_groups(struct mlx5_flow_table *ft)
+{
+ int err;
+ int i;
+
+ for (i = 0; i < ft->num_groups; i++) {
+ err = mlx5_create_flow_group_cmd(ft, i);
+ if (err)
+ goto err_destroy_flow_table_groups;
+ }
+
+ return 0;
+
+err_destroy_flow_table_groups:
+ for (i--; i >= 0; i--)
+ mlx5_destroy_flow_group_cmd(ft, i);
+
+ return err;
+}
+
+static int mlx5_create_flow_table_cmd(struct mlx5_flow_table *ft)
+{
+ u32 in[MLX5_ST_SZ_DW(create_flow_table_in)];
+ u32 out[MLX5_ST_SZ_DW(create_flow_table_out)];
+ int err;
+
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(create_flow_table_in, in, table_type, ft->type);
+ MLX5_SET(create_flow_table_in, in, level, ft->level);
+ MLX5_SET(create_flow_table_in, in, log_size, order_base_2(ft->size));
+
+ MLX5_SET(create_flow_table_in, in, opcode,
+ MLX5_CMD_OP_CREATE_FLOW_TABLE);
+
+ memset(out, 0, sizeof(out));
+ err = mlx5_cmd_exec_check_status(ft->dev, in, sizeof(in), out,
+ sizeof(out));
+ if (err)
+ return err;
+
+ ft->id = MLX5_GET(create_flow_table_out, out, table_id);
+
+ return 0;
+}
+
+static void mlx5_destroy_flow_table_cmd(struct mlx5_flow_table *ft)
+{
+ u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)];
+ u32 out[MLX5_ST_SZ_DW(destroy_flow_table_out)];
+
+ memset(in, 0, sizeof(in));
+ memset(out, 0, sizeof(out));
+
+#define MLX5_SET_DFTI(p, x, v) MLX5_SET(destroy_flow_table_in, p, x, v)
+ MLX5_SET_DFTI(in, table_type, ft->type);
+ MLX5_SET_DFTI(in, table_id, ft->id);
+ MLX5_SET_DFTI(in, opcode, MLX5_CMD_OP_DESTROY_FLOW_TABLE);
+
+ mlx5_cmd_exec_check_status(ft->dev, in, sizeof(in), out, sizeof(out));
+}
+
+static int mlx5_find_group(struct mlx5_flow_table *ft, u8 match_criteria_enable,
+ u32 *match_criteria, int *group_ix)
+{
+ void *mc_outer = MLX5_ADDR_OF(fte_match_param, match_criteria,
+ outer_headers);
+ void *mc_misc = MLX5_ADDR_OF(fte_match_param, match_criteria,
+ misc_parameters);
+ void *mc_inner = MLX5_ADDR_OF(fte_match_param, match_criteria,
+ inner_headers);
+ int mc_outer_sz = MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4);
+ int mc_misc_sz = MLX5_ST_SZ_BYTES(fte_match_set_misc);
+ int mc_inner_sz = MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4);
+ int i;
+
+ for (i = 0; i < ft->num_groups; i++) {
+ struct mlx5_flow_table_group *g = &ft->group[i].g;
+ void *gmc_outer = MLX5_ADDR_OF(fte_match_param,
+ g->match_criteria,
+ outer_headers);
+ void *gmc_misc = MLX5_ADDR_OF(fte_match_param,
+ g->match_criteria,
+ misc_parameters);
+ void *gmc_inner = MLX5_ADDR_OF(fte_match_param,
+ g->match_criteria,
+ inner_headers);
+
+ if (g->match_criteria_enable != match_criteria_enable)
+ continue;
+
+ if (match_criteria_enable & MLX5_MATCH_OUTER_HEADERS)
+ if (memcmp(mc_outer, gmc_outer, mc_outer_sz))
+ continue;
+
+ if (match_criteria_enable & MLX5_MATCH_MISC_PARAMETERS)
+ if (memcmp(mc_misc, gmc_misc, mc_misc_sz))
+ continue;
+
+ if (match_criteria_enable & MLX5_MATCH_INNER_HEADERS)
+ if (memcmp(mc_inner, gmc_inner, mc_inner_sz))
+ continue;
+
+ *group_ix = i;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int alloc_flow_index(struct mlx5_flow_table *ft, int group_ix, u32 *ix)
+{
+ struct mlx5_ftg *g = &ft->group[group_ix];
+ int err = 0;
+
+ mutex_lock(&ft->mutex);
+
+ *ix = find_next_zero_bit(ft->bitmap, ft->size, g->start_ix);
+ if (*ix >= (g->start_ix + (1 << g->g.log_sz)))
+ err = -ENOSPC;
+ else
+ __set_bit(*ix, ft->bitmap);
+
+ mutex_unlock(&ft->mutex);
+
+ return err;
+}
+
+static void mlx5_free_flow_index(struct mlx5_flow_table *ft, u32 ix)
+{
+ __clear_bit(ix, ft->bitmap);
+}
+
+int mlx5_add_flow_table_entry(void *flow_table, u8 match_criteria_enable,
+ void *match_criteria, void *flow_context,
+ u32 *flow_index)
+{
+ struct mlx5_flow_table *ft = flow_table;
+ int group_ix;
+ int err;
+
+ err = mlx5_find_group(ft, match_criteria_enable, match_criteria,
+ &group_ix);
+ if (err) {
+ mlx5_core_warn(ft->dev, "mlx5_find_group failed\n");
+ return err;
+ }
+
+ err = alloc_flow_index(ft, group_ix, flow_index);
+ if (err) {
+ mlx5_core_warn(ft->dev, "alloc_flow_index failed\n");
+ return err;
+ }
+
+ return mlx5_set_flow_entry_cmd(ft, group_ix, *flow_index, flow_context);
+}
+EXPORT_SYMBOL(mlx5_add_flow_table_entry);
+
+void mlx5_del_flow_table_entry(void *flow_table, u32 flow_index)
+{
+ struct mlx5_flow_table *ft = flow_table;
+
+ mlx5_del_flow_entry_cmd(ft, flow_index);
+ mlx5_free_flow_index(ft, flow_index);
+}
+EXPORT_SYMBOL(mlx5_del_flow_table_entry);
+
+void *mlx5_create_flow_table(struct mlx5_core_dev *dev, u8 level, u8 table_type,
+ u16 num_groups,
+ struct mlx5_flow_table_group *group)
+{
+ struct mlx5_flow_table *ft;
+ u32 start_ix = 0;
+ u32 ft_size = 0;
+ void *gr;
+ void *bm;
+ int err;
+ int i;
+
+ for (i = 0; i < num_groups; i++)
+ ft_size += (1 << group[i].log_sz);
+
+ ft = kzalloc(sizeof(*ft), GFP_KERNEL);
+ gr = kcalloc(num_groups, sizeof(struct mlx5_ftg), GFP_KERNEL);
+ bm = kcalloc(BITS_TO_LONGS(ft_size), sizeof(uintptr_t), GFP_KERNEL);
+ if (!ft || !gr || !bm)
+ goto err_free_ft;
+
+ ft->group = gr;
+ ft->bitmap = bm;
+ ft->num_groups = num_groups;
+ ft->level = level;
+ ft->type = table_type;
+ ft->size = ft_size;
+ ft->dev = dev;
+ mutex_init(&ft->mutex);
+
+ for (i = 0; i < ft->num_groups; i++) {
+ memcpy(&ft->group[i].g, &group[i], sizeof(*group));
+ ft->group[i].start_ix = start_ix;
+ start_ix += 1 << group[i].log_sz;
+ }
+
+ err = mlx5_create_flow_table_cmd(ft);
+ if (err)
+ goto err_free_ft;
+
+ err = mlx5_create_flow_table_groups(ft);
+ if (err)
+ goto err_destroy_flow_table_cmd;
+
+ return ft;
+
+err_destroy_flow_table_cmd:
+ mlx5_destroy_flow_table_cmd(ft);
+
+err_free_ft:
+ mlx5_core_warn(dev, "failed to alloc flow table\n");
+ kfree(bm);
+ kfree(gr);
+ kfree(ft);
+
+ return NULL;
+}
+EXPORT_SYMBOL(mlx5_create_flow_table);
+
+void mlx5_destroy_flow_table(void *flow_table)
+{
+ struct mlx5_flow_table *ft = flow_table;
+
+ mlx5_destroy_flow_table_groups(ft);
+ mlx5_destroy_flow_table_cmd(ft);
+ kfree(ft->bitmap);
+ kfree(ft->group);
+ kfree(ft);
+}
+EXPORT_SYMBOL(mlx5_destroy_flow_table);
+
+u32 mlx5_get_flow_table_id(void *flow_table)
+{
+ struct mlx5_flow_table *ft = flow_table;
+
+ return ft->id;
+}
+EXPORT_SYMBOL(mlx5_get_flow_table_id);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
index 4b4cda3bcc5f..9335e5ae18cc 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
@@ -35,79 +35,133 @@
#include <linux/module.h>
#include "mlx5_core.h"
-int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev)
+static int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev, u32 *out,
+ int outlen)
{
- struct mlx5_cmd_query_adapter_mbox_out *out;
- struct mlx5_cmd_query_adapter_mbox_in in;
+ u32 in[MLX5_ST_SZ_DW(query_adapter_in)];
+
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(query_adapter_in, in, opcode, MLX5_CMD_OP_QUERY_ADAPTER);
+
+ return mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, outlen);
+}
+
+int mlx5_query_board_id(struct mlx5_core_dev *dev)
+{
+ u32 *out;
+ int outlen = MLX5_ST_SZ_BYTES(query_adapter_out);
int err;
- out = kzalloc(sizeof(*out), GFP_KERNEL);
+ out = kzalloc(outlen, GFP_KERNEL);
if (!out)
return -ENOMEM;
- memset(&in, 0, sizeof(in));
- in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_ADAPTER);
- err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out));
+ err = mlx5_cmd_query_adapter(dev, out, outlen);
if (err)
- goto out_out;
-
- if (out->hdr.status) {
- err = mlx5_cmd_status_to_err(&out->hdr);
- goto out_out;
- }
+ goto out;
- memcpy(dev->board_id, out->vsd_psid, sizeof(out->vsd_psid));
+ memcpy(dev->board_id,
+ MLX5_ADDR_OF(query_adapter_out, out,
+ query_adapter_struct.vsd_contd_psid),
+ MLX5_FLD_SZ_BYTES(query_adapter_out,
+ query_adapter_struct.vsd_contd_psid));
-out_out:
+out:
kfree(out);
-
return err;
}
-int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev, struct mlx5_caps *caps)
+int mlx5_core_query_vendor_id(struct mlx5_core_dev *mdev, u32 *vendor_id)
{
- return mlx5_core_get_caps(dev, caps, HCA_CAP_OPMOD_GET_CUR);
+ u32 *out;
+ int outlen = MLX5_ST_SZ_BYTES(query_adapter_out);
+ int err;
+
+ out = kzalloc(outlen, GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+ err = mlx5_cmd_query_adapter(mdev, out, outlen);
+ if (err)
+ goto out;
+
+ *vendor_id = MLX5_GET(query_adapter_out, out,
+ query_adapter_struct.ieee_vendor_id);
+out:
+ kfree(out);
+ return err;
}
+EXPORT_SYMBOL(mlx5_core_query_vendor_id);
-int mlx5_query_odp_caps(struct mlx5_core_dev *dev, struct mlx5_odp_caps *caps)
+int mlx5_query_hca_caps(struct mlx5_core_dev *dev)
{
- u8 in[MLX5_ST_SZ_BYTES(query_hca_cap_in)];
- int out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
- void *out;
int err;
- if (!(dev->caps.gen.flags & MLX5_DEV_CAP_FLAG_ON_DMND_PG))
- return -ENOTSUPP;
+ err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL, HCA_CAP_OPMOD_GET_CUR);
+ if (err)
+ return err;
- memset(in, 0, sizeof(in));
- out = kzalloc(out_sz, GFP_KERNEL);
- if (!out)
- return -ENOMEM;
- MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP);
- MLX5_SET(query_hca_cap_in, in, op_mod, HCA_CAP_OPMOD_GET_ODP_CUR);
- err = mlx5_cmd_exec(dev, in, sizeof(in), out, out_sz);
+ err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL, HCA_CAP_OPMOD_GET_MAX);
if (err)
- goto out;
+ return err;
- err = mlx5_cmd_status_to_err_v2(out);
- if (err) {
- mlx5_core_warn(dev, "query cur hca ODP caps failed, %d\n", err);
- goto out;
+ if (MLX5_CAP_GEN(dev, eth_net_offloads)) {
+ err = mlx5_core_get_caps(dev, MLX5_CAP_ETHERNET_OFFLOADS,
+ HCA_CAP_OPMOD_GET_CUR);
+ if (err)
+ return err;
+ err = mlx5_core_get_caps(dev, MLX5_CAP_ETHERNET_OFFLOADS,
+ HCA_CAP_OPMOD_GET_MAX);
+ if (err)
+ return err;
}
- memcpy(caps, MLX5_ADDR_OF(query_hca_cap_out, out, capability_struct),
- sizeof(*caps));
+ if (MLX5_CAP_GEN(dev, pg)) {
+ err = mlx5_core_get_caps(dev, MLX5_CAP_ODP,
+ HCA_CAP_OPMOD_GET_CUR);
+ if (err)
+ return err;
+ err = mlx5_core_get_caps(dev, MLX5_CAP_ODP,
+ HCA_CAP_OPMOD_GET_MAX);
+ if (err)
+ return err;
+ }
- mlx5_core_dbg(dev, "on-demand paging capabilities:\nrc: %08x\nuc: %08x\nud: %08x\n",
- be32_to_cpu(caps->per_transport_caps.rc_odp_caps),
- be32_to_cpu(caps->per_transport_caps.uc_odp_caps),
- be32_to_cpu(caps->per_transport_caps.ud_odp_caps));
+ if (MLX5_CAP_GEN(dev, atomic)) {
+ err = mlx5_core_get_caps(dev, MLX5_CAP_ATOMIC,
+ HCA_CAP_OPMOD_GET_CUR);
+ if (err)
+ return err;
+ err = mlx5_core_get_caps(dev, MLX5_CAP_ATOMIC,
+ HCA_CAP_OPMOD_GET_MAX);
+ if (err)
+ return err;
+ }
-out:
- kfree(out);
- return err;
+ if (MLX5_CAP_GEN(dev, roce)) {
+ err = mlx5_core_get_caps(dev, MLX5_CAP_ROCE,
+ HCA_CAP_OPMOD_GET_CUR);
+ if (err)
+ return err;
+ err = mlx5_core_get_caps(dev, MLX5_CAP_ROCE,
+ HCA_CAP_OPMOD_GET_MAX);
+ if (err)
+ return err;
+ }
+
+ if (MLX5_CAP_GEN(dev, nic_flow_table)) {
+ err = mlx5_core_get_caps(dev, MLX5_CAP_FLOW_TABLE,
+ HCA_CAP_OPMOD_GET_CUR);
+ if (err)
+ return err;
+ err = mlx5_core_get_caps(dev, MLX5_CAP_FLOW_TABLE,
+ HCA_CAP_OPMOD_GET_MAX);
+ if (err)
+ return err;
+ }
+ return 0;
}
-EXPORT_SYMBOL(mlx5_query_odp_caps);
int mlx5_cmd_init_hca(struct mlx5_core_dev *dev)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 28425e5ea91f..afad529838de 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -38,6 +38,7 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/io-mapping.h>
+#include <linux/interrupt.h>
#include <linux/mlx5/driver.h>
#include <linux/mlx5/cq.h>
#include <linux/mlx5/qp.h>
@@ -47,10 +48,6 @@
#include <linux/mlx5/mlx5_ifc.h>
#include "mlx5_core.h"
-#define DRIVER_NAME "mlx5_core"
-#define DRIVER_VERSION "3.0"
-#define DRIVER_RELDATE "January 2015"
-
MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
MODULE_DESCRIPTION("Mellanox Connect-IB, ConnectX-4 core driver");
MODULE_LICENSE("Dual BSD/GPL");
@@ -208,24 +205,28 @@ static void release_bar(struct pci_dev *pdev)
static int mlx5_enable_msix(struct mlx5_core_dev *dev)
{
- struct mlx5_eq_table *table = &dev->priv.eq_table;
- int num_eqs = 1 << dev->caps.gen.log_max_eq;
+ struct mlx5_priv *priv = &dev->priv;
+ struct mlx5_eq_table *table = &priv->eq_table;
+ int num_eqs = 1 << MLX5_CAP_GEN(dev, log_max_eq);
int nvec;
int i;
- nvec = dev->caps.gen.num_ports * num_online_cpus() + MLX5_EQ_VEC_COMP_BASE;
+ nvec = MLX5_CAP_GEN(dev, num_ports) * num_online_cpus() +
+ MLX5_EQ_VEC_COMP_BASE;
nvec = min_t(int, nvec, num_eqs);
if (nvec <= MLX5_EQ_VEC_COMP_BASE)
return -ENOMEM;
- table->msix_arr = kzalloc(nvec * sizeof(*table->msix_arr), GFP_KERNEL);
- if (!table->msix_arr)
- return -ENOMEM;
+ priv->msix_arr = kcalloc(nvec, sizeof(*priv->msix_arr), GFP_KERNEL);
+
+ priv->irq_info = kcalloc(nvec, sizeof(*priv->irq_info), GFP_KERNEL);
+ if (!priv->msix_arr || !priv->irq_info)
+ goto err_free_msix;
for (i = 0; i < nvec; i++)
- table->msix_arr[i].entry = i;
+ priv->msix_arr[i].entry = i;
- nvec = pci_enable_msix_range(dev->pdev, table->msix_arr,
+ nvec = pci_enable_msix_range(dev->pdev, priv->msix_arr,
MLX5_EQ_VEC_COMP_BASE + 1, nvec);
if (nvec < 0)
return nvec;
@@ -233,14 +234,20 @@ static int mlx5_enable_msix(struct mlx5_core_dev *dev)
table->num_comp_vectors = nvec - MLX5_EQ_VEC_COMP_BASE;
return 0;
+
+err_free_msix:
+ kfree(priv->irq_info);
+ kfree(priv->msix_arr);
+ return -ENOMEM;
}
static void mlx5_disable_msix(struct mlx5_core_dev *dev)
{
- struct mlx5_eq_table *table = &dev->priv.eq_table;
+ struct mlx5_priv *priv = &dev->priv;
pci_disable_msix(dev->pdev);
- kfree(table->msix_arr);
+ kfree(priv->irq_info);
+ kfree(priv->msix_arr);
}
struct mlx5_reg_host_endianess {
@@ -277,98 +284,20 @@ static u16 to_fw_pkey_sz(u32 size)
}
}
-/* selectively copy writable fields clearing any reserved area
- */
-static void copy_rw_fields(void *to, struct mlx5_caps *from)
-{
- __be64 *flags_off = (__be64 *)MLX5_ADDR_OF(cmd_hca_cap, to, reserved_22);
- u64 v64;
-
- MLX5_SET(cmd_hca_cap, to, log_max_qp, from->gen.log_max_qp);
- MLX5_SET(cmd_hca_cap, to, log_max_ra_req_qp, from->gen.log_max_ra_req_qp);
- MLX5_SET(cmd_hca_cap, to, log_max_ra_res_qp, from->gen.log_max_ra_res_qp);
- MLX5_SET(cmd_hca_cap, to, pkey_table_size, from->gen.pkey_table_size);
- MLX5_SET(cmd_hca_cap, to, pkey_table_size, to_fw_pkey_sz(from->gen.pkey_table_size));
- MLX5_SET(cmd_hca_cap, to, log_uar_page_sz, PAGE_SHIFT - 12);
- v64 = from->gen.flags & MLX5_CAP_BITS_RW_MASK;
- *flags_off = cpu_to_be64(v64);
-}
-
-static u16 get_pkey_table_size(int pkey)
-{
- if (pkey > MLX5_MAX_LOG_PKEY_TABLE)
- return 0;
-
- return MLX5_MIN_PKEY_TABLE_SIZE << pkey;
-}
-
-static void fw2drv_caps(struct mlx5_caps *caps, void *out)
-{
- struct mlx5_general_caps *gen = &caps->gen;
-
- gen->max_srq_wqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_srq_sz);
- gen->max_wqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_qp_sz);
- gen->log_max_qp = MLX5_GET_PR(cmd_hca_cap, out, log_max_qp);
- gen->log_max_strq = MLX5_GET_PR(cmd_hca_cap, out, log_max_strq_sz);
- gen->log_max_srq = MLX5_GET_PR(cmd_hca_cap, out, log_max_srqs);
- gen->max_cqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_cq_sz);
- gen->log_max_cq = MLX5_GET_PR(cmd_hca_cap, out, log_max_cq);
- gen->max_eqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_eq_sz);
- gen->log_max_mkey = MLX5_GET_PR(cmd_hca_cap, out, log_max_mkey);
- gen->log_max_eq = MLX5_GET_PR(cmd_hca_cap, out, log_max_eq);
- gen->max_indirection = MLX5_GET_PR(cmd_hca_cap, out, max_indirection);
- gen->log_max_mrw_sz = MLX5_GET_PR(cmd_hca_cap, out, log_max_mrw_sz);
- gen->log_max_bsf_list_size = MLX5_GET_PR(cmd_hca_cap, out, log_max_bsf_list_size);
- gen->log_max_klm_list_size = MLX5_GET_PR(cmd_hca_cap, out, log_max_klm_list_size);
- gen->log_max_ra_req_dc = MLX5_GET_PR(cmd_hca_cap, out, log_max_ra_req_dc);
- gen->log_max_ra_res_dc = MLX5_GET_PR(cmd_hca_cap, out, log_max_ra_res_dc);
- gen->log_max_ra_req_qp = MLX5_GET_PR(cmd_hca_cap, out, log_max_ra_req_qp);
- gen->log_max_ra_res_qp = MLX5_GET_PR(cmd_hca_cap, out, log_max_ra_res_qp);
- gen->max_qp_counters = MLX5_GET_PR(cmd_hca_cap, out, max_qp_cnt);
- gen->pkey_table_size = get_pkey_table_size(MLX5_GET_PR(cmd_hca_cap, out, pkey_table_size));
- gen->local_ca_ack_delay = MLX5_GET_PR(cmd_hca_cap, out, local_ca_ack_delay);
- gen->num_ports = MLX5_GET_PR(cmd_hca_cap, out, num_ports);
- gen->log_max_msg = MLX5_GET_PR(cmd_hca_cap, out, log_max_msg);
- gen->stat_rate_support = MLX5_GET_PR(cmd_hca_cap, out, stat_rate_support);
- gen->flags = be64_to_cpu(*(__be64 *)MLX5_ADDR_OF(cmd_hca_cap, out, reserved_22));
- pr_debug("flags = 0x%llx\n", gen->flags);
- gen->uar_sz = MLX5_GET_PR(cmd_hca_cap, out, uar_sz);
- gen->min_log_pg_sz = MLX5_GET_PR(cmd_hca_cap, out, log_pg_sz);
- gen->bf_reg_size = MLX5_GET_PR(cmd_hca_cap, out, bf);
- gen->bf_reg_size = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_bf_reg_size);
- gen->max_sq_desc_sz = MLX5_GET_PR(cmd_hca_cap, out, max_wqe_sz_sq);
- gen->max_rq_desc_sz = MLX5_GET_PR(cmd_hca_cap, out, max_wqe_sz_rq);
- gen->max_dc_sq_desc_sz = MLX5_GET_PR(cmd_hca_cap, out, max_wqe_sz_sq_dc);
- gen->max_qp_mcg = MLX5_GET_PR(cmd_hca_cap, out, max_qp_mcg);
- gen->log_max_pd = MLX5_GET_PR(cmd_hca_cap, out, log_max_pd);
- gen->log_max_xrcd = MLX5_GET_PR(cmd_hca_cap, out, log_max_xrcd);
- gen->log_uar_page_sz = MLX5_GET_PR(cmd_hca_cap, out, log_uar_page_sz);
-}
-
-static const char *caps_opmod_str(u16 opmod)
-{
- switch (opmod) {
- case HCA_CAP_OPMOD_GET_MAX:
- return "GET_MAX";
- case HCA_CAP_OPMOD_GET_CUR:
- return "GET_CUR";
- default:
- return "Invalid";
- }
-}
-
-int mlx5_core_get_caps(struct mlx5_core_dev *dev, struct mlx5_caps *caps,
- u16 opmod)
+int mlx5_core_get_caps(struct mlx5_core_dev *dev, enum mlx5_cap_type cap_type,
+ enum mlx5_cap_mode cap_mode)
{
u8 in[MLX5_ST_SZ_BYTES(query_hca_cap_in)];
int out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
- void *out;
+ void *out, *hca_caps;
+ u16 opmod = (cap_type << 1) | (cap_mode & 0x01);
int err;
memset(in, 0, sizeof(in));
out = kzalloc(out_sz, GFP_KERNEL);
if (!out)
return -ENOMEM;
+
MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP);
MLX5_SET(query_hca_cap_in, in, op_mod, opmod);
err = mlx5_cmd_exec(dev, in, sizeof(in), out, out_sz);
@@ -377,12 +306,30 @@ int mlx5_core_get_caps(struct mlx5_core_dev *dev, struct mlx5_caps *caps,
err = mlx5_cmd_status_to_err_v2(out);
if (err) {
- mlx5_core_warn(dev, "query max hca cap failed, %d\n", err);
+ mlx5_core_warn(dev,
+ "QUERY_HCA_CAP : type(%x) opmode(%x) Failed(%d)\n",
+ cap_type, cap_mode, err);
goto query_ex;
}
- mlx5_core_dbg(dev, "%s\n", caps_opmod_str(opmod));
- fw2drv_caps(caps, MLX5_ADDR_OF(query_hca_cap_out, out, capability_struct));
+ hca_caps = MLX5_ADDR_OF(query_hca_cap_out, out, capability);
+
+ switch (cap_mode) {
+ case HCA_CAP_OPMOD_GET_MAX:
+ memcpy(dev->hca_caps_max[cap_type], hca_caps,
+ MLX5_UN_SZ_BYTES(hca_cap_union));
+ break;
+ case HCA_CAP_OPMOD_GET_CUR:
+ memcpy(dev->hca_caps_cur[cap_type], hca_caps,
+ MLX5_UN_SZ_BYTES(hca_cap_union));
+ break;
+ default:
+ mlx5_core_warn(dev,
+ "Tried to query dev cap type(%x) with wrong opmode(%x)\n",
+ cap_type, cap_mode);
+ err = -EINVAL;
+ break;
+ }
query_ex:
kfree(out);
return err;
@@ -409,49 +356,45 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)
{
void *set_ctx = NULL;
struct mlx5_profile *prof = dev->profile;
- struct mlx5_caps *cur_caps = NULL;
- struct mlx5_caps *max_caps = NULL;
int err = -ENOMEM;
int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in);
+ void *set_hca_cap;
set_ctx = kzalloc(set_sz, GFP_KERNEL);
if (!set_ctx)
goto query_ex;
- max_caps = kzalloc(sizeof(*max_caps), GFP_KERNEL);
- if (!max_caps)
- goto query_ex;
-
- cur_caps = kzalloc(sizeof(*cur_caps), GFP_KERNEL);
- if (!cur_caps)
- goto query_ex;
-
- err = mlx5_core_get_caps(dev, max_caps, HCA_CAP_OPMOD_GET_MAX);
+ err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL, HCA_CAP_OPMOD_GET_MAX);
if (err)
goto query_ex;
- err = mlx5_core_get_caps(dev, cur_caps, HCA_CAP_OPMOD_GET_CUR);
+ err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL, HCA_CAP_OPMOD_GET_CUR);
if (err)
goto query_ex;
+ set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx,
+ capability);
+ memcpy(set_hca_cap, dev->hca_caps_cur[MLX5_CAP_GENERAL],
+ MLX5_ST_SZ_BYTES(cmd_hca_cap));
+
+ mlx5_core_dbg(dev, "Current Pkey table size %d Setting new size %d\n",
+ mlx5_to_sw_pkey_sz(MLX5_CAP_GEN(dev, pkey_table_size)),
+ 128);
/* we limit the size of the pkey table to 128 entries for now */
- cur_caps->gen.pkey_table_size = 128;
+ MLX5_SET(cmd_hca_cap, set_hca_cap, pkey_table_size,
+ to_fw_pkey_sz(128));
if (prof->mask & MLX5_PROF_MASK_QP_SIZE)
- cur_caps->gen.log_max_qp = prof->log_max_qp;
+ MLX5_SET(cmd_hca_cap, set_hca_cap, log_max_qp,
+ prof->log_max_qp);
- /* disable checksum */
- cur_caps->gen.flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM;
+ /* disable cmdif checksum */
+ MLX5_SET(cmd_hca_cap, set_hca_cap, cmdif_checksum, 0);
- copy_rw_fields(MLX5_ADDR_OF(set_hca_cap_in, set_ctx, hca_capability_struct),
- cur_caps);
err = set_caps(dev, set_ctx, set_sz);
query_ex:
- kfree(cur_caps);
- kfree(max_caps);
kfree(set_ctx);
-
return err;
}
@@ -507,6 +450,74 @@ static int mlx5_core_disable_hca(struct mlx5_core_dev *dev)
return 0;
}
+static int mlx5_irq_set_affinity_hint(struct mlx5_core_dev *mdev, int i)
+{
+ struct mlx5_priv *priv = &mdev->priv;
+ struct msix_entry *msix = priv->msix_arr;
+ int irq = msix[i + MLX5_EQ_VEC_COMP_BASE].vector;
+ int numa_node = dev_to_node(&mdev->pdev->dev);
+ int err;
+
+ if (!zalloc_cpumask_var(&priv->irq_info[i].mask, GFP_KERNEL)) {
+ mlx5_core_warn(mdev, "zalloc_cpumask_var failed");
+ return -ENOMEM;
+ }
+
+ cpumask_set_cpu(cpumask_local_spread(i, numa_node),
+ priv->irq_info[i].mask);
+
+ err = irq_set_affinity_hint(irq, priv->irq_info[i].mask);
+ if (err) {
+ mlx5_core_warn(mdev, "irq_set_affinity_hint failed,irq 0x%.4x",
+ irq);
+ goto err_clear_mask;
+ }
+
+ return 0;
+
+err_clear_mask:
+ free_cpumask_var(priv->irq_info[i].mask);
+ return err;
+}
+
+static void mlx5_irq_clear_affinity_hint(struct mlx5_core_dev *mdev, int i)
+{
+ struct mlx5_priv *priv = &mdev->priv;
+ struct msix_entry *msix = priv->msix_arr;
+ int irq = msix[i + MLX5_EQ_VEC_COMP_BASE].vector;
+
+ irq_set_affinity_hint(irq, NULL);
+ free_cpumask_var(priv->irq_info[i].mask);
+}
+
+static int mlx5_irq_set_affinity_hints(struct mlx5_core_dev *mdev)
+{
+ int err;
+ int i;
+
+ for (i = 0; i < mdev->priv.eq_table.num_comp_vectors; i++) {
+ err = mlx5_irq_set_affinity_hint(mdev, i);
+ if (err)
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ for (i--; i >= 0; i--)
+ mlx5_irq_clear_affinity_hint(mdev, i);
+
+ return err;
+}
+
+static void mlx5_irq_clear_affinity_hints(struct mlx5_core_dev *mdev)
+{
+ int i;
+
+ for (i = 0; i < mdev->priv.eq_table.num_comp_vectors; i++)
+ mlx5_irq_clear_affinity_hint(mdev, i);
+}
+
int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn, int *irqn)
{
struct mlx5_eq_table *table = &dev->priv.eq_table;
@@ -549,7 +560,7 @@ static void free_comp_eqs(struct mlx5_core_dev *dev)
static int alloc_comp_eqs(struct mlx5_core_dev *dev)
{
struct mlx5_eq_table *table = &dev->priv.eq_table;
- char name[MLX5_MAX_EQ_NAME];
+ char name[MLX5_MAX_IRQ_NAME];
struct mlx5_eq *eq;
int ncomp_vec;
int nent;
@@ -566,7 +577,7 @@ static int alloc_comp_eqs(struct mlx5_core_dev *dev)
goto clean;
}
- snprintf(name, MLX5_MAX_EQ_NAME, "mlx5_comp%d", i);
+ snprintf(name, MLX5_MAX_IRQ_NAME, "mlx5_comp%d", i);
err = mlx5_create_map_eq(dev, eq,
i + MLX5_EQ_VEC_COMP_BASE, nent, 0,
name, &dev->priv.uuari.uars[0]);
@@ -588,6 +599,61 @@ clean:
return err;
}
+#ifdef CONFIG_MLX5_CORE_EN
+static int mlx5_core_set_issi(struct mlx5_core_dev *dev)
+{
+ u32 query_in[MLX5_ST_SZ_DW(query_issi_in)];
+ u32 query_out[MLX5_ST_SZ_DW(query_issi_out)];
+ u32 set_in[MLX5_ST_SZ_DW(set_issi_in)];
+ u32 set_out[MLX5_ST_SZ_DW(set_issi_out)];
+ int err;
+ u32 sup_issi;
+
+ memset(query_in, 0, sizeof(query_in));
+ memset(query_out, 0, sizeof(query_out));
+
+ MLX5_SET(query_issi_in, query_in, opcode, MLX5_CMD_OP_QUERY_ISSI);
+
+ err = mlx5_cmd_exec_check_status(dev, query_in, sizeof(query_in),
+ query_out, sizeof(query_out));
+ if (err) {
+ if (((struct mlx5_outbox_hdr *)query_out)->status ==
+ MLX5_CMD_STAT_BAD_OP_ERR) {
+ pr_debug("Only ISSI 0 is supported\n");
+ return 0;
+ }
+
+ pr_err("failed to query ISSI\n");
+ return err;
+ }
+
+ sup_issi = MLX5_GET(query_issi_out, query_out, supported_issi_dw0);
+
+ if (sup_issi & (1 << 1)) {
+ memset(set_in, 0, sizeof(set_in));
+ memset(set_out, 0, sizeof(set_out));
+
+ MLX5_SET(set_issi_in, set_in, opcode, MLX5_CMD_OP_SET_ISSI);
+ MLX5_SET(set_issi_in, set_in, current_issi, 1);
+
+ err = mlx5_cmd_exec_check_status(dev, set_in, sizeof(set_in),
+ set_out, sizeof(set_out));
+ if (err) {
+ pr_err("failed to set ISSI=1\n");
+ return err;
+ }
+
+ dev->issi = 1;
+
+ return 0;
+ } else if (sup_issi & (1 << 0) || !sup_issi) {
+ return 0;
+ }
+
+ return -ENOTSUPP;
+}
+#endif
+
static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
{
struct mlx5_priv *priv = &dev->priv;
@@ -650,6 +716,14 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
goto err_pagealloc_cleanup;
}
+#ifdef CONFIG_MLX5_CORE_EN
+ err = mlx5_core_set_issi(dev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to set issi\n");
+ goto err_disable_hca;
+ }
+#endif
+
err = mlx5_satisfy_startup_pages(dev, 1);
if (err) {
dev_err(&pdev->dev, "failed to allocate boot pages\n");
@@ -688,15 +762,15 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
mlx5_start_health_poll(dev);
- err = mlx5_cmd_query_hca_cap(dev, &dev->caps);
+ err = mlx5_query_hca_caps(dev);
if (err) {
dev_err(&pdev->dev, "query hca failed\n");
goto err_stop_poll;
}
- err = mlx5_cmd_query_adapter(dev);
+ err = mlx5_query_board_id(dev);
if (err) {
- dev_err(&pdev->dev, "query adapter failed\n");
+ dev_err(&pdev->dev, "query board id failed\n");
goto err_stop_poll;
}
@@ -730,6 +804,12 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
goto err_stop_eqs;
}
+ err = mlx5_irq_set_affinity_hints(dev);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to alloc affinity hint cpumask\n");
+ goto err_free_comp_eqs;
+ }
+
MLX5_INIT_DOORBELL_LOCK(&priv->cq_uar_lock);
mlx5_init_cq_table(dev);
@@ -739,6 +819,9 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
return 0;
+err_free_comp_eqs:
+ free_comp_eqs(dev);
+
err_stop_eqs:
mlx5_stop_eqs(dev);
@@ -793,6 +876,7 @@ static void mlx5_dev_cleanup(struct mlx5_core_dev *dev)
mlx5_cleanup_srq_table(dev);
mlx5_cleanup_qp_table(dev);
mlx5_cleanup_cq_table(dev);
+ mlx5_irq_clear_affinity_hints(dev);
free_comp_eqs(dev);
mlx5_stop_eqs(dev);
mlx5_free_uuars(dev, &priv->uuari);
@@ -1048,6 +1132,10 @@ static int __init init(void)
if (err)
goto err_health;
+#ifdef CONFIG_MLX5_CORE_EN
+ mlx5e_init();
+#endif
+
return 0;
err_health:
@@ -1060,6 +1148,9 @@ err_debug:
static void __exit cleanup(void)
{
+#ifdef CONFIG_MLX5_CORE_EN
+ mlx5e_cleanup();
+#endif
pci_unregister_driver(&mlx5_core_driver);
mlx5_health_cleanup();
destroy_workqueue(mlx5_core_wq);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mcg.c b/drivers/net/ethernet/mellanox/mlx5/core/mcg.c
index d79fd85d1dd5..d5a0c2d61a18 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mcg.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mcg.c
@@ -91,7 +91,7 @@ int mlx5_core_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn)
memset(&in, 0, sizeof(in));
memset(&out, 0, sizeof(out));
- in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DETACH_FROM_MCG);
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DETTACH_FROM_MCG);
memcpy(in.gid, mgid, sizeof(*mgid));
in.qpn = cpu_to_be32(qpn);
err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index a051b906afdf..fc88ecaecb4b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -37,6 +37,10 @@
#include <linux/kernel.h>
#include <linux/sched.h>
+#define DRIVER_NAME "mlx5_core"
+#define DRIVER_VERSION "3.0-1"
+#define DRIVER_RELDATE "January 2015"
+
extern int mlx5_core_debug_mask;
#define mlx5_core_dbg(dev, format, ...) \
@@ -65,11 +69,20 @@ enum {
MLX5_CMD_TIME, /* print command execution time */
};
+static inline int mlx5_cmd_exec_check_status(struct mlx5_core_dev *dev, u32 *in,
+ int in_size, u32 *out,
+ int out_size)
+{
+ mlx5_cmd_exec(dev, in, in_size, out, out_size);
+ return mlx5_cmd_status_to_err((struct mlx5_outbox_hdr *)out);
+}
-int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev,
- struct mlx5_caps *caps);
-int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev);
+int mlx5_query_hca_caps(struct mlx5_core_dev *dev);
+int mlx5_query_board_id(struct mlx5_core_dev *dev);
int mlx5_cmd_init_hca(struct mlx5_core_dev *dev);
int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev);
+void mlx5e_init(void);
+void mlx5e_cleanup(void);
+
#endif /* __MLX5_CORE_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c
index 49e90f2612d8..70147999f657 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/port.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c
@@ -102,3 +102,229 @@ int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps)
return err;
}
EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
+
+int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
+ int ptys_size, int proto_mask, u8 local_port)
+{
+ u32 in[MLX5_ST_SZ_DW(ptys_reg)];
+ int err;
+
+ memset(in, 0, sizeof(in));
+ MLX5_SET(ptys_reg, in, local_port, local_port);
+ MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
+
+ err = mlx5_core_access_reg(dev, in, sizeof(in), ptys,
+ ptys_size, MLX5_REG_PTYS, 0, 0);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_port_ptys);
+
+int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev,
+ u32 *proto_cap, int proto_mask)
+{
+ u32 out[MLX5_ST_SZ_DW(ptys_reg)];
+ int err;
+
+ err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1);
+ if (err)
+ return err;
+
+ if (proto_mask == MLX5_PTYS_EN)
+ *proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability);
+ else
+ *proto_cap = MLX5_GET(ptys_reg, out, ib_proto_capability);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_port_proto_cap);
+
+int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev,
+ u32 *proto_admin, int proto_mask)
+{
+ u32 out[MLX5_ST_SZ_DW(ptys_reg)];
+ int err;
+
+ err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1);
+ if (err)
+ return err;
+
+ if (proto_mask == MLX5_PTYS_EN)
+ *proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin);
+ else
+ *proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_port_proto_admin);
+
+int mlx5_query_port_link_width_oper(struct mlx5_core_dev *dev,
+ u8 *link_width_oper, u8 local_port)
+{
+ u32 out[MLX5_ST_SZ_DW(ptys_reg)];
+ int err;
+
+ err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB, local_port);
+ if (err)
+ return err;
+
+ *link_width_oper = MLX5_GET(ptys_reg, out, ib_link_width_oper);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_port_link_width_oper);
+
+int mlx5_query_port_proto_oper(struct mlx5_core_dev *dev,
+ u8 *proto_oper, int proto_mask,
+ u8 local_port)
+{
+ u32 out[MLX5_ST_SZ_DW(ptys_reg)];
+ int err;
+
+ err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, local_port);
+ if (err)
+ return err;
+
+ if (proto_mask == MLX5_PTYS_EN)
+ *proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
+ else
+ *proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_port_proto_oper);
+
+int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin,
+ int proto_mask)
+{
+ u32 in[MLX5_ST_SZ_DW(ptys_reg)];
+ u32 out[MLX5_ST_SZ_DW(ptys_reg)];
+ int err;
+
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(ptys_reg, in, local_port, 1);
+ MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
+ if (proto_mask == MLX5_PTYS_EN)
+ MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin);
+ else
+ MLX5_SET(ptys_reg, in, ib_proto_admin, proto_admin);
+
+ err = mlx5_core_access_reg(dev, in, sizeof(in), out,
+ sizeof(out), MLX5_REG_PTYS, 0, 1);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_set_port_proto);
+
+int mlx5_set_port_status(struct mlx5_core_dev *dev,
+ enum mlx5_port_status status)
+{
+ u32 in[MLX5_ST_SZ_DW(paos_reg)];
+ u32 out[MLX5_ST_SZ_DW(paos_reg)];
+
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(paos_reg, in, admin_status, status);
+ MLX5_SET(paos_reg, in, ase, 1);
+
+ return mlx5_core_access_reg(dev, in, sizeof(in), out,
+ sizeof(out), MLX5_REG_PAOS, 0, 1);
+}
+
+int mlx5_query_port_status(struct mlx5_core_dev *dev, u8 *status)
+{
+ u32 in[MLX5_ST_SZ_DW(paos_reg)];
+ u32 out[MLX5_ST_SZ_DW(paos_reg)];
+ int err;
+
+ memset(in, 0, sizeof(in));
+
+ err = mlx5_core_access_reg(dev, in, sizeof(in), out,
+ sizeof(out), MLX5_REG_PAOS, 0, 0);
+ if (err)
+ return err;
+
+ *status = MLX5_GET(paos_reg, out, oper_status);
+ return err;
+}
+
+static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, int *admin_mtu,
+ int *max_mtu, int *oper_mtu, u8 port)
+{
+ u32 in[MLX5_ST_SZ_DW(pmtu_reg)];
+ u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
+
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(pmtu_reg, in, local_port, port);
+
+ mlx5_core_access_reg(dev, in, sizeof(in), out,
+ sizeof(out), MLX5_REG_PMTU, 0, 0);
+
+ if (max_mtu)
+ *max_mtu = MLX5_GET(pmtu_reg, out, max_mtu);
+ if (oper_mtu)
+ *oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu);
+ if (admin_mtu)
+ *admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu);
+}
+
+int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu, u8 port)
+{
+ u32 in[MLX5_ST_SZ_DW(pmtu_reg)];
+ u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
+
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(pmtu_reg, in, admin_mtu, mtu);
+ MLX5_SET(pmtu_reg, in, local_port, port);
+
+ return mlx5_core_access_reg(dev, in, sizeof(in), out,
+ sizeof(out), MLX5_REG_PMTU, 0, 1);
+}
+EXPORT_SYMBOL_GPL(mlx5_set_port_mtu);
+
+void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu,
+ u8 port)
+{
+ mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, port);
+}
+EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
+
+void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu,
+ u8 port)
+{
+ mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, port);
+}
+EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
+
+static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc,
+ int pvlc_size, u8 local_port)
+{
+ u32 in[MLX5_ST_SZ_DW(pvlc_reg)];
+ int err;
+
+ memset(in, 0, sizeof(in));
+ MLX5_SET(ptys_reg, in, local_port, local_port);
+
+ err = mlx5_core_access_reg(dev, in, sizeof(in), pvlc,
+ pvlc_size, MLX5_REG_PVLC, 0, 0);
+
+ return err;
+}
+
+int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev,
+ u8 *vl_hw_cap, u8 local_port)
+{
+ u32 out[MLX5_ST_SZ_DW(pvlc_reg)];
+ int err;
+
+ err = mlx5_query_port_pvlc(dev, out, sizeof(out), local_port);
+ if (err)
+ return err;
+
+ *vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c
index dc7dbf7e9d98..8b494b562263 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c
@@ -187,10 +187,17 @@ int mlx5_core_create_qp(struct mlx5_core_dev *dev,
struct mlx5_destroy_qp_mbox_in din;
struct mlx5_destroy_qp_mbox_out dout;
int err;
+ void *qpc;
memset(&out, 0, sizeof(out));
in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_QP);
+ if (dev->issi) {
+ qpc = MLX5_ADDR_OF(create_qp_in, in, qpc);
+ /* 0xffffff means we ask to work with cqe version 0 */
+ MLX5_SET(qpc, qpc, user_index, 0xffffff);
+ }
+
err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
if (err) {
mlx5_core_warn(dev, "ret %d\n", err);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/srq.c b/drivers/net/ethernet/mellanox/mlx5/core/srq.c
index f9d25dcd03c1..c48f504ccbeb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/srq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/srq.c
@@ -37,6 +37,7 @@
#include <linux/mlx5/srq.h>
#include <rdma/ib_verbs.h>
#include "mlx5_core.h"
+#include "transobj.h"
void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type)
{
@@ -62,6 +63,74 @@ void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type)
complete(&srq->free);
}
+static int get_pas_size(void *srqc)
+{
+ u32 log_page_size = MLX5_GET(srqc, srqc, log_page_size) + 12;
+ u32 log_srq_size = MLX5_GET(srqc, srqc, log_srq_size);
+ u32 log_rq_stride = MLX5_GET(srqc, srqc, log_rq_stride);
+ u32 page_offset = MLX5_GET(srqc, srqc, page_offset);
+ u32 po_quanta = 1 << (log_page_size - 6);
+ u32 rq_sz = 1 << (log_srq_size + 4 + log_rq_stride);
+ u32 page_size = 1 << log_page_size;
+ u32 rq_sz_po = rq_sz + (page_offset * po_quanta);
+ u32 rq_num_pas = (rq_sz_po + page_size - 1) / page_size;
+
+ return rq_num_pas * sizeof(u64);
+}
+
+static void rmpc_srqc_reformat(void *srqc, void *rmpc, bool srqc_to_rmpc)
+{
+ void *wq = MLX5_ADDR_OF(rmpc, rmpc, wq);
+
+ if (srqc_to_rmpc) {
+ switch (MLX5_GET(srqc, srqc, state)) {
+ case MLX5_SRQC_STATE_GOOD:
+ MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_RDY);
+ break;
+ case MLX5_SRQC_STATE_ERROR:
+ MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_ERR);
+ break;
+ default:
+ pr_warn("%s: %d: Unknown srq state = 0x%x\n", __func__,
+ __LINE__, MLX5_GET(srqc, srqc, state));
+ MLX5_SET(rmpc, rmpc, state, MLX5_GET(srqc, srqc, state));
+ }
+
+ MLX5_SET(wq, wq, wq_signature, MLX5_GET(srqc, srqc, wq_signature));
+ MLX5_SET(wq, wq, log_wq_pg_sz, MLX5_GET(srqc, srqc, log_page_size));
+ MLX5_SET(wq, wq, log_wq_stride, MLX5_GET(srqc, srqc, log_rq_stride) + 4);
+ MLX5_SET(wq, wq, log_wq_sz, MLX5_GET(srqc, srqc, log_srq_size));
+ MLX5_SET(wq, wq, page_offset, MLX5_GET(srqc, srqc, page_offset));
+ MLX5_SET(wq, wq, lwm, MLX5_GET(srqc, srqc, lwm));
+ MLX5_SET(wq, wq, pd, MLX5_GET(srqc, srqc, pd));
+ MLX5_SET64(wq, wq, dbr_addr, MLX5_GET64(srqc, srqc, dbr_addr));
+ } else {
+ switch (MLX5_GET(rmpc, rmpc, state)) {
+ case MLX5_RMPC_STATE_RDY:
+ MLX5_SET(srqc, srqc, state, MLX5_SRQC_STATE_GOOD);
+ break;
+ case MLX5_RMPC_STATE_ERR:
+ MLX5_SET(srqc, srqc, state, MLX5_SRQC_STATE_ERROR);
+ break;
+ default:
+ pr_warn("%s: %d: Unknown rmp state = 0x%x\n",
+ __func__, __LINE__,
+ MLX5_GET(rmpc, rmpc, state));
+ MLX5_SET(srqc, srqc, state,
+ MLX5_GET(rmpc, rmpc, state));
+ }
+
+ MLX5_SET(srqc, srqc, wq_signature, MLX5_GET(wq, wq, wq_signature));
+ MLX5_SET(srqc, srqc, log_page_size, MLX5_GET(wq, wq, log_wq_pg_sz));
+ MLX5_SET(srqc, srqc, log_rq_stride, MLX5_GET(wq, wq, log_wq_stride) - 4);
+ MLX5_SET(srqc, srqc, log_srq_size, MLX5_GET(wq, wq, log_wq_sz));
+ MLX5_SET(srqc, srqc, page_offset, MLX5_GET(wq, wq, page_offset));
+ MLX5_SET(srqc, srqc, lwm, MLX5_GET(wq, wq, lwm));
+ MLX5_SET(srqc, srqc, pd, MLX5_GET(wq, wq, pd));
+ MLX5_SET64(srqc, srqc, dbr_addr, MLX5_GET64(wq, wq, dbr_addr));
+ }
+}
+
struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn)
{
struct mlx5_srq_table *table = &dev->priv.srq_table;
@@ -79,26 +148,311 @@ struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn)
}
EXPORT_SYMBOL(mlx5_core_get_srq);
-int mlx5_core_create_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
- struct mlx5_create_srq_mbox_in *in, int inlen)
+static int create_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
+ struct mlx5_create_srq_mbox_in *in, int inlen)
{
struct mlx5_create_srq_mbox_out out;
- struct mlx5_srq_table *table = &dev->priv.srq_table;
- struct mlx5_destroy_srq_mbox_in din;
- struct mlx5_destroy_srq_mbox_out dout;
int err;
memset(&out, 0, sizeof(out));
+
in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_SRQ);
- err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
- if (err)
- return err;
- if (out.hdr.status)
- return mlx5_cmd_status_to_err(&out.hdr);
+ err = mlx5_cmd_exec_check_status(dev, (u32 *)in, inlen, (u32 *)(&out),
+ sizeof(out));
srq->srqn = be32_to_cpu(out.srqn) & 0xffffff;
+ return err;
+}
+
+static int destroy_srq_cmd(struct mlx5_core_dev *dev,
+ struct mlx5_core_srq *srq)
+{
+ struct mlx5_destroy_srq_mbox_in in;
+ struct mlx5_destroy_srq_mbox_out out;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_SRQ);
+ in.srqn = cpu_to_be32(srq->srqn);
+
+ return mlx5_cmd_exec_check_status(dev, (u32 *)(&in), sizeof(in),
+ (u32 *)(&out), sizeof(out));
+}
+
+static int arm_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
+ u16 lwm, int is_srq)
+{
+ struct mlx5_arm_srq_mbox_in in;
+ struct mlx5_arm_srq_mbox_out out;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ARM_RQ);
+ in.hdr.opmod = cpu_to_be16(!!is_srq);
+ in.srqn = cpu_to_be32(srq->srqn);
+ in.lwm = cpu_to_be16(lwm);
+
+ return mlx5_cmd_exec_check_status(dev, (u32 *)(&in),
+ sizeof(in), (u32 *)(&out),
+ sizeof(out));
+}
+
+static int query_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
+ struct mlx5_query_srq_mbox_out *out)
+{
+ struct mlx5_query_srq_mbox_in in;
+
+ memset(&in, 0, sizeof(in));
+
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SRQ);
+ in.srqn = cpu_to_be32(srq->srqn);
+
+ return mlx5_cmd_exec_check_status(dev, (u32 *)(&in), sizeof(in),
+ (u32 *)out, sizeof(*out));
+}
+
+static int create_xrc_srq_cmd(struct mlx5_core_dev *dev,
+ struct mlx5_core_srq *srq,
+ struct mlx5_create_srq_mbox_in *in,
+ int srq_inlen)
+{
+ u32 create_out[MLX5_ST_SZ_DW(create_xrc_srq_out)];
+ void *create_in;
+ void *srqc;
+ void *xrc_srqc;
+ void *pas;
+ int pas_size;
+ int inlen;
+ int err;
+
+ srqc = MLX5_ADDR_OF(create_srq_in, in, srq_context_entry);
+ pas_size = get_pas_size(srqc);
+ inlen = MLX5_ST_SZ_BYTES(create_xrc_srq_in) + pas_size;
+ create_in = mlx5_vzalloc(inlen);
+ if (!create_in)
+ return -ENOMEM;
+
+ xrc_srqc = MLX5_ADDR_OF(create_xrc_srq_in, create_in,
+ xrc_srq_context_entry);
+ pas = MLX5_ADDR_OF(create_xrc_srq_in, create_in, pas);
+
+ memcpy(xrc_srqc, srqc, MLX5_ST_SZ_BYTES(srqc));
+ memcpy(pas, in->pas, pas_size);
+ /* 0xffffff means we ask to work with cqe version 0 */
+ MLX5_SET(xrc_srqc, xrc_srqc, user_index, 0xffffff);
+ MLX5_SET(create_xrc_srq_in, create_in, opcode,
+ MLX5_CMD_OP_CREATE_XRC_SRQ);
+
+ memset(create_out, 0, sizeof(create_out));
+ err = mlx5_cmd_exec_check_status(dev, create_in, inlen, create_out,
+ sizeof(create_out));
+ if (err)
+ goto out;
+
+ srq->srqn = MLX5_GET(create_xrc_srq_out, create_out, xrc_srqn);
+out:
+ kvfree(create_in);
+ return err;
+}
+
+static int destroy_xrc_srq_cmd(struct mlx5_core_dev *dev,
+ struct mlx5_core_srq *srq)
+{
+ u32 xrcsrq_in[MLX5_ST_SZ_DW(destroy_xrc_srq_in)];
+ u32 xrcsrq_out[MLX5_ST_SZ_DW(destroy_xrc_srq_out)];
+
+ memset(xrcsrq_in, 0, sizeof(xrcsrq_in));
+ memset(xrcsrq_out, 0, sizeof(xrcsrq_out));
+
+ MLX5_SET(destroy_xrc_srq_in, xrcsrq_in, opcode,
+ MLX5_CMD_OP_DESTROY_XRC_SRQ);
+ MLX5_SET(destroy_xrc_srq_in, xrcsrq_in, xrc_srqn, srq->srqn);
+
+ return mlx5_cmd_exec_check_status(dev, xrcsrq_in, sizeof(xrcsrq_in),
+ xrcsrq_out, sizeof(xrcsrq_out));
+}
+
+static int arm_xrc_srq_cmd(struct mlx5_core_dev *dev,
+ struct mlx5_core_srq *srq, u16 lwm)
+{
+ u32 xrcsrq_in[MLX5_ST_SZ_DW(arm_xrc_srq_in)];
+ u32 xrcsrq_out[MLX5_ST_SZ_DW(arm_xrc_srq_out)];
+
+ memset(xrcsrq_in, 0, sizeof(xrcsrq_in));
+ memset(xrcsrq_out, 0, sizeof(xrcsrq_out));
+
+ MLX5_SET(arm_xrc_srq_in, xrcsrq_in, opcode, MLX5_CMD_OP_ARM_XRC_SRQ);
+ MLX5_SET(arm_xrc_srq_in, xrcsrq_in, op_mod, MLX5_ARM_XRC_SRQ_IN_OP_MOD_XRC_SRQ);
+ MLX5_SET(arm_xrc_srq_in, xrcsrq_in, xrc_srqn, srq->srqn);
+ MLX5_SET(arm_xrc_srq_in, xrcsrq_in, lwm, lwm);
+
+ return mlx5_cmd_exec_check_status(dev, xrcsrq_in, sizeof(xrcsrq_in),
+ xrcsrq_out, sizeof(xrcsrq_out));
+}
+
+static int query_xrc_srq_cmd(struct mlx5_core_dev *dev,
+ struct mlx5_core_srq *srq,
+ struct mlx5_query_srq_mbox_out *out)
+{
+ u32 xrcsrq_in[MLX5_ST_SZ_DW(query_xrc_srq_in)];
+ u32 *xrcsrq_out;
+ void *srqc;
+ void *xrc_srqc;
+ int err;
+
+ xrcsrq_out = mlx5_vzalloc(MLX5_ST_SZ_BYTES(query_xrc_srq_out));
+ if (!xrcsrq_out)
+ return -ENOMEM;
+ memset(xrcsrq_in, 0, sizeof(xrcsrq_in));
+
+ MLX5_SET(query_xrc_srq_in, xrcsrq_in, opcode,
+ MLX5_CMD_OP_QUERY_XRC_SRQ);
+ MLX5_SET(query_xrc_srq_in, xrcsrq_in, xrc_srqn, srq->srqn);
+ err = mlx5_cmd_exec_check_status(dev, xrcsrq_in, sizeof(xrcsrq_in),
+ xrcsrq_out,
+ MLX5_ST_SZ_BYTES(query_xrc_srq_out));
+ if (err)
+ goto out;
+
+ xrc_srqc = MLX5_ADDR_OF(query_xrc_srq_out, xrcsrq_out,
+ xrc_srq_context_entry);
+ srqc = MLX5_ADDR_OF(query_srq_out, out, srq_context_entry);
+ memcpy(srqc, xrc_srqc, MLX5_ST_SZ_BYTES(srqc));
+
+out:
+ kvfree(xrcsrq_out);
+ return err;
+}
+
+static int create_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
+ struct mlx5_create_srq_mbox_in *in, int srq_inlen)
+{
+ void *create_in;
+ void *rmpc;
+ void *srqc;
+ int pas_size;
+ int inlen;
+ int err;
+
+ srqc = MLX5_ADDR_OF(create_srq_in, in, srq_context_entry);
+ pas_size = get_pas_size(srqc);
+ inlen = MLX5_ST_SZ_BYTES(create_rmp_in) + pas_size;
+ create_in = mlx5_vzalloc(inlen);
+ if (!create_in)
+ return -ENOMEM;
+
+ rmpc = MLX5_ADDR_OF(create_rmp_in, create_in, ctx);
+
+ memcpy(MLX5_ADDR_OF(rmpc, rmpc, wq.pas), in->pas, pas_size);
+ rmpc_srqc_reformat(srqc, rmpc, true);
+
+ err = mlx5_core_create_rmp(dev, create_in, inlen, &srq->srqn);
+
+ kvfree(create_in);
+ return err;
+}
+
+static int destroy_rmp_cmd(struct mlx5_core_dev *dev,
+ struct mlx5_core_srq *srq)
+{
+ return mlx5_core_destroy_rmp(dev, srq->srqn);
+}
+
+static int arm_rmp_cmd(struct mlx5_core_dev *dev,
+ struct mlx5_core_srq *srq,
+ u16 lwm)
+{
+ void *in;
+ void *rmpc;
+ void *wq;
+ void *bitmask;
+ int err;
+
+ in = mlx5_vzalloc(MLX5_ST_SZ_BYTES(modify_rmp_in));
+ if (!in)
+ return -ENOMEM;
+
+ rmpc = MLX5_ADDR_OF(modify_rmp_in, in, ctx);
+ bitmask = MLX5_ADDR_OF(modify_rmp_in, in, bitmask);
+ wq = MLX5_ADDR_OF(rmpc, rmpc, wq);
+
+ MLX5_SET(modify_rmp_in, in, rmp_state, MLX5_RMPC_STATE_RDY);
+ MLX5_SET(modify_rmp_in, in, rmpn, srq->srqn);
+ MLX5_SET(wq, wq, lwm, lwm);
+ MLX5_SET(rmp_bitmask, bitmask, lwm, 1);
+ MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_RDY);
+
+ err = mlx5_core_modify_rmp(dev, in, MLX5_ST_SZ_BYTES(modify_rmp_in));
+
+ kvfree(in);
+ return err;
+}
+
+static int query_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
+ struct mlx5_query_srq_mbox_out *out)
+{
+ u32 *rmp_out;
+ void *rmpc;
+ void *srqc;
+ int err;
+
+ rmp_out = mlx5_vzalloc(MLX5_ST_SZ_BYTES(query_rmp_out));
+ if (!rmp_out)
+ return -ENOMEM;
+
+ err = mlx5_core_query_rmp(dev, srq->srqn, rmp_out);
+ if (err)
+ goto out;
+
+ srqc = MLX5_ADDR_OF(query_srq_out, out, srq_context_entry);
+ rmpc = MLX5_ADDR_OF(query_rmp_out, rmp_out, rmp_context);
+ rmpc_srqc_reformat(srqc, rmpc, false);
+
+out:
+ kvfree(rmp_out);
+ return err;
+}
+
+static int create_srq_split(struct mlx5_core_dev *dev,
+ struct mlx5_core_srq *srq,
+ struct mlx5_create_srq_mbox_in *in,
+ int inlen, int is_xrc)
+{
+ if (!dev->issi)
+ return create_srq_cmd(dev, srq, in, inlen);
+ else if (srq->common.res == MLX5_RES_XSRQ)
+ return create_xrc_srq_cmd(dev, srq, in, inlen);
+ else
+ return create_rmp_cmd(dev, srq, in, inlen);
+}
+
+static int destroy_srq_split(struct mlx5_core_dev *dev,
+ struct mlx5_core_srq *srq)
+{
+ if (!dev->issi)
+ return destroy_srq_cmd(dev, srq);
+ else if (srq->common.res == MLX5_RES_XSRQ)
+ return destroy_xrc_srq_cmd(dev, srq);
+ else
+ return destroy_rmp_cmd(dev, srq);
+}
+
+int mlx5_core_create_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
+ struct mlx5_create_srq_mbox_in *in, int inlen,
+ int is_xrc)
+{
+ int err;
+ struct mlx5_srq_table *table = &dev->priv.srq_table;
+
+ srq->common.res = is_xrc ? MLX5_RES_XSRQ : MLX5_RES_SRQ;
+
+ err = create_srq_split(dev, srq, in, inlen, is_xrc);
+ if (err)
+ return err;
+
atomic_set(&srq->refcount, 1);
init_completion(&srq->free);
@@ -107,25 +461,20 @@ int mlx5_core_create_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
spin_unlock_irq(&table->lock);
if (err) {
mlx5_core_warn(dev, "err %d, srqn 0x%x\n", err, srq->srqn);
- goto err_cmd;
+ goto err_destroy_srq_split;
}
return 0;
-err_cmd:
- memset(&din, 0, sizeof(din));
- memset(&dout, 0, sizeof(dout));
- din.srqn = cpu_to_be32(srq->srqn);
- din.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_SRQ);
- mlx5_cmd_exec(dev, &din, sizeof(din), &dout, sizeof(dout));
+err_destroy_srq_split:
+ destroy_srq_split(dev, srq);
+
return err;
}
EXPORT_SYMBOL(mlx5_core_create_srq);
int mlx5_core_destroy_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq)
{
- struct mlx5_destroy_srq_mbox_in in;
- struct mlx5_destroy_srq_mbox_out out;
struct mlx5_srq_table *table = &dev->priv.srq_table;
struct mlx5_core_srq *tmp;
int err;
@@ -142,17 +491,10 @@ int mlx5_core_destroy_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq)
return -EINVAL;
}
- memset(&in, 0, sizeof(in));
- memset(&out, 0, sizeof(out));
- in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_SRQ);
- in.srqn = cpu_to_be32(srq->srqn);
- err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+ err = destroy_srq_split(dev, srq);
if (err)
return err;
- if (out.hdr.status)
- return mlx5_cmd_status_to_err(&out.hdr);
-
if (atomic_dec_and_test(&srq->refcount))
complete(&srq->free);
wait_for_completion(&srq->free);
@@ -164,48 +506,24 @@ EXPORT_SYMBOL(mlx5_core_destroy_srq);
int mlx5_core_query_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
struct mlx5_query_srq_mbox_out *out)
{
- struct mlx5_query_srq_mbox_in in;
- int err;
-
- memset(&in, 0, sizeof(in));
- memset(out, 0, sizeof(*out));
-
- in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SRQ);
- in.srqn = cpu_to_be32(srq->srqn);
- err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out));
- if (err)
- return err;
-
- if (out->hdr.status)
- return mlx5_cmd_status_to_err(&out->hdr);
-
- return err;
+ if (!dev->issi)
+ return query_srq_cmd(dev, srq, out);
+ else if (srq->common.res == MLX5_RES_XSRQ)
+ return query_xrc_srq_cmd(dev, srq, out);
+ else
+ return query_rmp_cmd(dev, srq, out);
}
EXPORT_SYMBOL(mlx5_core_query_srq);
int mlx5_core_arm_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
u16 lwm, int is_srq)
{
- struct mlx5_arm_srq_mbox_in in;
- struct mlx5_arm_srq_mbox_out out;
- int err;
-
- memset(&in, 0, sizeof(in));
- memset(&out, 0, sizeof(out));
-
- in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ARM_RQ);
- in.hdr.opmod = cpu_to_be16(!!is_srq);
- in.srqn = cpu_to_be32(srq->srqn);
- in.lwm = cpu_to_be16(lwm);
-
- err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
- if (err)
- return err;
-
- if (out.hdr.status)
- return mlx5_cmd_status_to_err(&out.hdr);
-
- return err;
+ if (!dev->issi)
+ return arm_srq_cmd(dev, srq, lwm, is_srq);
+ else if (srq->common.res == MLX5_RES_XSRQ)
+ return arm_xrc_srq_cmd(dev, srq, lwm);
+ else
+ return arm_rmp_cmd(dev, srq, lwm);
}
EXPORT_SYMBOL(mlx5_core_arm_srq);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c
new file mode 100644
index 000000000000..8d98b03026d5
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ */
+
+#include <linux/mlx5/driver.h>
+#include "mlx5_core.h"
+#include "transobj.h"
+
+int mlx5_alloc_transport_domain(struct mlx5_core_dev *dev, u32 *tdn)
+{
+ u32 in[MLX5_ST_SZ_DW(alloc_transport_domain_in)];
+ u32 out[MLX5_ST_SZ_DW(alloc_transport_domain_out)];
+ int err;
+
+ memset(in, 0, sizeof(in));
+ memset(out, 0, sizeof(out));
+
+ MLX5_SET(alloc_transport_domain_in, in, opcode,
+ MLX5_CMD_OP_ALLOC_TRANSPORT_DOMAIN);
+
+ err = mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));
+ if (!err)
+ *tdn = MLX5_GET(alloc_transport_domain_out, out,
+ transport_domain);
+
+ return err;
+}
+
+void mlx5_dealloc_transport_domain(struct mlx5_core_dev *dev, u32 tdn)
+{
+ u32 in[MLX5_ST_SZ_DW(dealloc_transport_domain_in)];
+ u32 out[MLX5_ST_SZ_DW(dealloc_transport_domain_out)];
+
+ memset(in, 0, sizeof(in));
+ memset(out, 0, sizeof(out));
+
+ MLX5_SET(dealloc_transport_domain_in, in, opcode,
+ MLX5_CMD_OP_DEALLOC_TRANSPORT_DOMAIN);
+ MLX5_SET(dealloc_transport_domain_in, in, transport_domain, tdn);
+
+ mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));
+}
+
+int mlx5_core_create_rq(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *rqn)
+{
+ u32 out[MLX5_ST_SZ_DW(create_rq_out)];
+ int err;
+
+ MLX5_SET(create_rq_in, in, opcode, MLX5_CMD_OP_CREATE_RQ);
+
+ memset(out, 0, sizeof(out));
+ err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out));
+ if (!err)
+ *rqn = MLX5_GET(create_rq_out, out, rqn);
+
+ return err;
+}
+
+int mlx5_core_modify_rq(struct mlx5_core_dev *dev, u32 rqn, u32 *in, int inlen)
+{
+ u32 out[MLX5_ST_SZ_DW(modify_rq_out)];
+
+ MLX5_SET(modify_rq_in, in, rqn, rqn);
+ MLX5_SET(modify_rq_in, in, opcode, MLX5_CMD_OP_MODIFY_RQ);
+
+ memset(out, 0, sizeof(out));
+ return mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out));
+}
+
+void mlx5_core_destroy_rq(struct mlx5_core_dev *dev, u32 rqn)
+{
+ u32 in[MLX5_ST_SZ_DW(destroy_rq_in)];
+ u32 out[MLX5_ST_SZ_DW(destroy_rq_out)];
+
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(destroy_rq_in, in, opcode, MLX5_CMD_OP_DESTROY_RQ);
+ MLX5_SET(destroy_rq_in, in, rqn, rqn);
+
+ mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));
+}
+
+int mlx5_core_create_sq(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *sqn)
+{
+ u32 out[MLX5_ST_SZ_DW(create_sq_out)];
+ int err;
+
+ MLX5_SET(create_sq_in, in, opcode, MLX5_CMD_OP_CREATE_SQ);
+
+ memset(out, 0, sizeof(out));
+ err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out));
+ if (!err)
+ *sqn = MLX5_GET(create_sq_out, out, sqn);
+
+ return err;
+}
+
+int mlx5_core_modify_sq(struct mlx5_core_dev *dev, u32 sqn, u32 *in, int inlen)
+{
+ u32 out[MLX5_ST_SZ_DW(modify_sq_out)];
+
+ MLX5_SET(modify_sq_in, in, sqn, sqn);
+ MLX5_SET(modify_sq_in, in, opcode, MLX5_CMD_OP_MODIFY_SQ);
+
+ memset(out, 0, sizeof(out));
+ return mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out));
+}
+
+void mlx5_core_destroy_sq(struct mlx5_core_dev *dev, u32 sqn)
+{
+ u32 in[MLX5_ST_SZ_DW(destroy_sq_in)];
+ u32 out[MLX5_ST_SZ_DW(destroy_sq_out)];
+
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(destroy_sq_in, in, opcode, MLX5_CMD_OP_DESTROY_SQ);
+ MLX5_SET(destroy_sq_in, in, sqn, sqn);
+
+ mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));
+}
+
+int mlx5_core_create_tir(struct mlx5_core_dev *dev, u32 *in, int inlen,
+ u32 *tirn)
+{
+ u32 out[MLX5_ST_SZ_DW(create_tir_out)];
+ int err;
+
+ MLX5_SET(create_tir_in, in, opcode, MLX5_CMD_OP_CREATE_TIR);
+
+ memset(out, 0, sizeof(out));
+ err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out));
+ if (!err)
+ *tirn = MLX5_GET(create_tir_out, out, tirn);
+
+ return err;
+}
+
+void mlx5_core_destroy_tir(struct mlx5_core_dev *dev, u32 tirn)
+{
+ u32 in[MLX5_ST_SZ_DW(destroy_tir_out)];
+ u32 out[MLX5_ST_SZ_DW(destroy_tir_out)];
+
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(destroy_tir_in, in, opcode, MLX5_CMD_OP_DESTROY_TIR);
+ MLX5_SET(destroy_tir_in, in, tirn, tirn);
+
+ mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));
+}
+
+int mlx5_core_create_tis(struct mlx5_core_dev *dev, u32 *in, int inlen,
+ u32 *tisn)
+{
+ u32 out[MLX5_ST_SZ_DW(create_tis_out)];
+ int err;
+
+ MLX5_SET(create_tis_in, in, opcode, MLX5_CMD_OP_CREATE_TIS);
+
+ memset(out, 0, sizeof(out));
+ err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out));
+ if (!err)
+ *tisn = MLX5_GET(create_tis_out, out, tisn);
+
+ return err;
+}
+
+void mlx5_core_destroy_tis(struct mlx5_core_dev *dev, u32 tisn)
+{
+ u32 in[MLX5_ST_SZ_DW(destroy_tis_out)];
+ u32 out[MLX5_ST_SZ_DW(destroy_tis_out)];
+
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(destroy_tis_in, in, opcode, MLX5_CMD_OP_DESTROY_TIS);
+ MLX5_SET(destroy_tis_in, in, tisn, tisn);
+
+ mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));
+}
+
+int mlx5_core_create_rmp(struct mlx5_core_dev *dev, u32 *in, int inlen,
+ u32 *rmpn)
+{
+ u32 out[MLX5_ST_SZ_DW(create_rmp_out)];
+ int err;
+
+ MLX5_SET(create_rmp_in, in, opcode, MLX5_CMD_OP_CREATE_RMP);
+
+ memset(out, 0, sizeof(out));
+ err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out));
+ if (!err)
+ *rmpn = MLX5_GET(create_rmp_out, out, rmpn);
+
+ return err;
+}
+
+int mlx5_core_modify_rmp(struct mlx5_core_dev *dev, u32 *in, int inlen)
+{
+ u32 out[MLX5_ST_SZ_DW(modify_rmp_out)];
+
+ MLX5_SET(modify_rmp_in, in, opcode, MLX5_CMD_OP_MODIFY_RMP);
+
+ memset(out, 0, sizeof(out));
+ return mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out));
+}
+
+int mlx5_core_destroy_rmp(struct mlx5_core_dev *dev, u32 rmpn)
+{
+ u32 in[MLX5_ST_SZ_DW(destroy_rmp_in)];
+ u32 out[MLX5_ST_SZ_DW(destroy_rmp_out)];
+
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(destroy_rmp_in, in, opcode, MLX5_CMD_OP_DESTROY_RMP);
+ MLX5_SET(destroy_rmp_in, in, rmpn, rmpn);
+
+ return mlx5_cmd_exec_check_status(dev, in, sizeof(in), out,
+ sizeof(out));
+}
+
+int mlx5_core_query_rmp(struct mlx5_core_dev *dev, u32 rmpn, u32 *out)
+{
+ u32 in[MLX5_ST_SZ_DW(query_rmp_in)];
+ int outlen = MLX5_ST_SZ_BYTES(query_rmp_out);
+
+ memset(in, 0, sizeof(in));
+ MLX5_SET(query_rmp_in, in, opcode, MLX5_CMD_OP_QUERY_RMP);
+ MLX5_SET(query_rmp_in, in, rmpn, rmpn);
+
+ return mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, outlen);
+}
+
+int mlx5_core_arm_rmp(struct mlx5_core_dev *dev, u32 rmpn, u16 lwm)
+{
+ void *in;
+ void *rmpc;
+ void *wq;
+ void *bitmask;
+ int err;
+
+ in = mlx5_vzalloc(MLX5_ST_SZ_BYTES(modify_rmp_in));
+ if (!in)
+ return -ENOMEM;
+
+ rmpc = MLX5_ADDR_OF(modify_rmp_in, in, ctx);
+ bitmask = MLX5_ADDR_OF(modify_rmp_in, in, bitmask);
+ wq = MLX5_ADDR_OF(rmpc, rmpc, wq);
+
+ MLX5_SET(modify_rmp_in, in, rmp_state, MLX5_RMPC_STATE_RDY);
+ MLX5_SET(modify_rmp_in, in, rmpn, rmpn);
+ MLX5_SET(wq, wq, lwm, lwm);
+ MLX5_SET(rmp_bitmask, bitmask, lwm, 1);
+ MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_RDY);
+
+ err = mlx5_core_modify_rmp(dev, in, MLX5_ST_SZ_BYTES(modify_rmp_in));
+
+ kvfree(in);
+
+ return err;
+}
+
+int mlx5_core_create_xsrq(struct mlx5_core_dev *dev, u32 *in, int inlen,
+ u32 *xsrqn)
+{
+ u32 out[MLX5_ST_SZ_DW(create_xrc_srq_out)];
+ int err;
+
+ MLX5_SET(create_xrc_srq_in, in, opcode, MLX5_CMD_OP_CREATE_XRC_SRQ);
+
+ memset(out, 0, sizeof(out));
+ err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out));
+ if (!err)
+ *xsrqn = MLX5_GET(create_xrc_srq_out, out, xrc_srqn);
+
+ return err;
+}
+
+int mlx5_core_destroy_xsrq(struct mlx5_core_dev *dev, u32 xsrqn)
+{
+ u32 in[MLX5_ST_SZ_DW(destroy_xrc_srq_in)];
+ u32 out[MLX5_ST_SZ_DW(destroy_xrc_srq_out)];
+
+ memset(in, 0, sizeof(in));
+ memset(out, 0, sizeof(out));
+
+ MLX5_SET(destroy_xrc_srq_in, in, opcode, MLX5_CMD_OP_DESTROY_XRC_SRQ);
+ MLX5_SET(destroy_xrc_srq_in, in, xrc_srqn, xsrqn);
+
+ return mlx5_cmd_exec_check_status(dev, in, sizeof(in), out,
+ sizeof(out));
+}
+
+int mlx5_core_query_xsrq(struct mlx5_core_dev *dev, u32 xsrqn, u32 *out)
+{
+ u32 in[MLX5_ST_SZ_DW(query_xrc_srq_in)];
+ void *srqc;
+ void *xrc_srqc;
+ int err;
+
+ memset(in, 0, sizeof(in));
+ MLX5_SET(query_xrc_srq_in, in, opcode, MLX5_CMD_OP_QUERY_XRC_SRQ);
+ MLX5_SET(query_xrc_srq_in, in, xrc_srqn, xsrqn);
+
+ err = mlx5_cmd_exec_check_status(dev, in, sizeof(in),
+ out,
+ MLX5_ST_SZ_BYTES(query_xrc_srq_out));
+ if (!err) {
+ xrc_srqc = MLX5_ADDR_OF(query_xrc_srq_out, out,
+ xrc_srq_context_entry);
+ srqc = MLX5_ADDR_OF(query_srq_out, out, srq_context_entry);
+ memcpy(srqc, xrc_srqc, MLX5_ST_SZ_BYTES(srqc));
+ }
+
+ return err;
+}
+
+int mlx5_core_arm_xsrq(struct mlx5_core_dev *dev, u32 xsrqn, u16 lwm)
+{
+ u32 in[MLX5_ST_SZ_DW(arm_xrc_srq_in)];
+ u32 out[MLX5_ST_SZ_DW(arm_xrc_srq_out)];
+
+ memset(in, 0, sizeof(in));
+ memset(out, 0, sizeof(out));
+
+ MLX5_SET(arm_xrc_srq_in, in, opcode, MLX5_CMD_OP_ARM_XRC_SRQ);
+ MLX5_SET(arm_xrc_srq_in, in, xrc_srqn, xsrqn);
+ MLX5_SET(arm_xrc_srq_in, in, lwm, lwm);
+ MLX5_SET(arm_xrc_srq_in, in, op_mod,
+ MLX5_ARM_XRC_SRQ_IN_OP_MOD_XRC_SRQ);
+
+ return mlx5_cmd_exec_check_status(dev, in, sizeof(in), out,
+ sizeof(out));
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.h b/drivers/net/ethernet/mellanox/mlx5/core/transobj.h
new file mode 100644
index 000000000000..f9ef244710d5
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ */
+
+#ifndef __TRANSOBJ_H__
+#define __TRANSOBJ_H__
+
+int mlx5_alloc_transport_domain(struct mlx5_core_dev *dev, u32 *tdn);
+void mlx5_dealloc_transport_domain(struct mlx5_core_dev *dev, u32 tdn);
+int mlx5_core_create_rq(struct mlx5_core_dev *dev, u32 *in, int inlen,
+ u32 *rqn);
+int mlx5_core_modify_rq(struct mlx5_core_dev *dev, u32 rqn, u32 *in, int inlen);
+void mlx5_core_destroy_rq(struct mlx5_core_dev *dev, u32 rqn);
+int mlx5_core_create_sq(struct mlx5_core_dev *dev, u32 *in, int inlen,
+ u32 *sqn);
+int mlx5_core_modify_sq(struct mlx5_core_dev *dev, u32 sqn, u32 *in, int inlen);
+void mlx5_core_destroy_sq(struct mlx5_core_dev *dev, u32 sqn);
+int mlx5_core_create_tir(struct mlx5_core_dev *dev, u32 *in, int inlen,
+ u32 *tirn);
+void mlx5_core_destroy_tir(struct mlx5_core_dev *dev, u32 tirn);
+int mlx5_core_create_tis(struct mlx5_core_dev *dev, u32 *in, int inlen,
+ u32 *tisn);
+void mlx5_core_destroy_tis(struct mlx5_core_dev *dev, u32 tisn);
+int mlx5_core_create_rmp(struct mlx5_core_dev *dev, u32 *in, int inlen,
+ u32 *rmpn);
+int mlx5_core_modify_rmp(struct mlx5_core_dev *dev, u32 *in, int inlen);
+int mlx5_core_destroy_rmp(struct mlx5_core_dev *dev, u32 rmpn);
+int mlx5_core_query_rmp(struct mlx5_core_dev *dev, u32 rmpn, u32 *out);
+int mlx5_core_arm_rmp(struct mlx5_core_dev *dev, u32 rmpn, u16 lwm);
+int mlx5_core_create_xsrq(struct mlx5_core_dev *dev, u32 *in, int inlen,
+ u32 *rmpn);
+int mlx5_core_destroy_xsrq(struct mlx5_core_dev *dev, u32 rmpn);
+int mlx5_core_query_xsrq(struct mlx5_core_dev *dev, u32 rmpn, u32 *out);
+int mlx5_core_arm_xsrq(struct mlx5_core_dev *dev, u32 rmpn, u16 lwm);
+
+#endif /* __TRANSOBJ_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/uar.c b/drivers/net/ethernet/mellanox/mlx5/core/uar.c
index 5a89bb1d678a..9ef85873ceea 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/uar.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/uar.c
@@ -175,12 +175,13 @@ int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari)
for (i = 0; i < tot_uuars; i++) {
bf = &uuari->bfs[i];
- bf->buf_size = dev->caps.gen.bf_reg_size / 2;
+ bf->buf_size = (1 << MLX5_CAP_GEN(dev, log_bf_reg_size)) / 2;
bf->uar = &uuari->uars[i / MLX5_BF_REGS_PER_PAGE];
bf->regreg = uuari->uars[i / MLX5_BF_REGS_PER_PAGE].map;
bf->reg = NULL; /* Add WC support */
- bf->offset = (i % MLX5_BF_REGS_PER_PAGE) * dev->caps.gen.bf_reg_size +
- MLX5_BF_OFFSET;
+ bf->offset = (i % MLX5_BF_REGS_PER_PAGE) *
+ (1 << MLX5_CAP_GEN(dev, log_bf_reg_size)) +
+ MLX5_BF_OFFSET;
bf->need_lock = need_uuar_lock(i);
spin_lock_init(&bf->lock);
spin_lock_init(&bf->lock32);
@@ -223,3 +224,40 @@ int mlx5_free_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari)
return 0;
}
+
+int mlx5_alloc_map_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar)
+{
+ phys_addr_t pfn;
+ phys_addr_t uar_bar_start;
+ int err;
+
+ err = mlx5_cmd_alloc_uar(mdev, &uar->index);
+ if (err) {
+ mlx5_core_warn(mdev, "mlx5_cmd_alloc_uar() failed, %d\n", err);
+ return err;
+ }
+
+ uar_bar_start = pci_resource_start(mdev->pdev, 0);
+ pfn = (uar_bar_start >> PAGE_SHIFT) + uar->index;
+ uar->map = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE);
+ if (!uar->map) {
+ mlx5_core_warn(mdev, "ioremap() failed, %d\n", err);
+ err = -ENOMEM;
+ goto err_free_uar;
+ }
+
+ return 0;
+
+err_free_uar:
+ mlx5_cmd_free_uar(mdev, uar->index);
+
+ return err;
+}
+EXPORT_SYMBOL(mlx5_alloc_map_uar);
+
+void mlx5_unmap_free_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar)
+{
+ iounmap(uar->map);
+ mlx5_cmd_free_uar(mdev, uar->index);
+}
+EXPORT_SYMBOL(mlx5_unmap_free_uar);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
new file mode 100644
index 000000000000..b94177ebcf3a
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ */
+
+#include <linux/export.h>
+#include <linux/etherdevice.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/vport.h>
+#include "mlx5_core.h"
+
+u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod)
+{
+ u32 in[MLX5_ST_SZ_DW(query_vport_state_in)];
+ u32 out[MLX5_ST_SZ_DW(query_vport_state_out)];
+ int err;
+
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(query_vport_state_in, in, opcode,
+ MLX5_CMD_OP_QUERY_VPORT_STATE);
+ MLX5_SET(query_vport_state_in, in, op_mod, opmod);
+
+ err = mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out,
+ sizeof(out));
+ if (err)
+ mlx5_core_warn(mdev, "MLX5_CMD_OP_QUERY_VPORT_STATE failed\n");
+
+ return MLX5_GET(query_vport_state_out, out, state);
+}
+EXPORT_SYMBOL(mlx5_query_vport_state);
+
+void mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev, u8 *addr)
+{
+ u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)];
+ u32 *out;
+ int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out);
+ u8 *out_addr;
+
+ out = mlx5_vzalloc(outlen);
+ if (!out)
+ return;
+
+ out_addr = MLX5_ADDR_OF(query_nic_vport_context_out, out,
+ nic_vport_context.permanent_address);
+
+ memset(in, 0, sizeof(in));
+
+ MLX5_SET(query_nic_vport_context_in, in, opcode,
+ MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT);
+
+ memset(out, 0, outlen);
+ mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out, outlen);
+
+ ether_addr_copy(addr, &out_addr[2]);
+
+ kvfree(out);
+}
+EXPORT_SYMBOL(mlx5_query_nic_vport_mac_address);
+
+int mlx5_query_hca_vport_gid(struct mlx5_core_dev *dev, u8 other_vport,
+ u8 port_num, u16 vf_num, u16 gid_index,
+ union ib_gid *gid)
+{
+ int in_sz = MLX5_ST_SZ_BYTES(query_hca_vport_gid_in);
+ int out_sz = MLX5_ST_SZ_BYTES(query_hca_vport_gid_out);
+ int is_group_manager;
+ void *out = NULL;
+ void *in = NULL;
+ union ib_gid *tmp;
+ int tbsz;
+ int nout;
+ int err;
+
+ is_group_manager = MLX5_CAP_GEN(dev, vport_group_manager);
+ tbsz = mlx5_get_gid_table_len(MLX5_CAP_GEN(dev, gid_table_size));
+ mlx5_core_dbg(dev, "vf_num %d, index %d, gid_table_size %d\n",
+ vf_num, gid_index, tbsz);
+
+ if (gid_index > tbsz && gid_index != 0xffff)
+ return -EINVAL;
+
+ if (gid_index == 0xffff)
+ nout = tbsz;
+ else
+ nout = 1;
+
+ out_sz += nout * sizeof(*gid);
+
+ in = kzalloc(in_sz, GFP_KERNEL);
+ out = kzalloc(out_sz, GFP_KERNEL);
+ if (!in || !out) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ MLX5_SET(query_hca_vport_gid_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_VPORT_GID);
+ if (other_vport) {
+ if (is_group_manager) {
+ MLX5_SET(query_hca_vport_gid_in, in, vport_number, vf_num);
+ MLX5_SET(query_hca_vport_gid_in, in, other_vport, 1);
+ } else {
+ err = -EPERM;
+ goto out;
+ }
+ }
+ MLX5_SET(query_hca_vport_gid_in, in, gid_index, gid_index);
+
+ if (MLX5_CAP_GEN(dev, num_ports) == 2)
+ MLX5_SET(query_hca_vport_gid_in, in, port_num, port_num);
+
+ err = mlx5_cmd_exec(dev, in, in_sz, out, out_sz);
+ if (err)
+ goto out;
+
+ err = mlx5_cmd_status_to_err_v2(out);
+ if (err)
+ goto out;
+
+ tmp = out + MLX5_ST_SZ_BYTES(query_hca_vport_gid_out);
+ gid->global.subnet_prefix = tmp->global.subnet_prefix;
+ gid->global.interface_id = tmp->global.interface_id;
+
+out:
+ kfree(in);
+ kfree(out);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_hca_vport_gid);
+
+int mlx5_query_hca_vport_pkey(struct mlx5_core_dev *dev, u8 other_vport,
+ u8 port_num, u16 vf_num, u16 pkey_index,
+ u16 *pkey)
+{
+ int in_sz = MLX5_ST_SZ_BYTES(query_hca_vport_pkey_in);
+ int out_sz = MLX5_ST_SZ_BYTES(query_hca_vport_pkey_out);
+ int is_group_manager;
+ void *out = NULL;
+ void *in = NULL;
+ void *pkarr;
+ int nout;
+ int tbsz;
+ int err;
+ int i;
+
+ is_group_manager = MLX5_CAP_GEN(dev, vport_group_manager);
+
+ tbsz = mlx5_to_sw_pkey_sz(MLX5_CAP_GEN(dev, pkey_table_size));
+ if (pkey_index > tbsz && pkey_index != 0xffff)
+ return -EINVAL;
+
+ if (pkey_index == 0xffff)
+ nout = tbsz;
+ else
+ nout = 1;
+
+ out_sz += nout * MLX5_ST_SZ_BYTES(pkey);
+
+ in = kzalloc(in_sz, GFP_KERNEL);
+ out = kzalloc(out_sz, GFP_KERNEL);
+ if (!in || !out) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ MLX5_SET(query_hca_vport_pkey_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_VPORT_PKEY);
+ if (other_vport) {
+ if (is_group_manager) {
+ MLX5_SET(query_hca_vport_pkey_in, in, vport_number, vf_num);
+ MLX5_SET(query_hca_vport_pkey_in, in, other_vport, 1);
+ } else {
+ err = -EPERM;
+ goto out;
+ }
+ }
+ MLX5_SET(query_hca_vport_pkey_in, in, pkey_index, pkey_index);
+
+ if (MLX5_CAP_GEN(dev, num_ports) == 2)
+ MLX5_SET(query_hca_vport_pkey_in, in, port_num, port_num);
+
+ err = mlx5_cmd_exec(dev, in, in_sz, out, out_sz);
+ if (err)
+ goto out;
+
+ err = mlx5_cmd_status_to_err_v2(out);
+ if (err)
+ goto out;
+
+ pkarr = MLX5_ADDR_OF(query_hca_vport_pkey_out, out, pkey);
+ for (i = 0; i < nout; i++, pkey++, pkarr += MLX5_ST_SZ_BYTES(pkey))
+ *pkey = MLX5_GET_PR(pkey, pkarr, pkey);
+
+out:
+ kfree(in);
+ kfree(out);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_hca_vport_pkey);
+
+int mlx5_query_hca_vport_context(struct mlx5_core_dev *dev,
+ u8 other_vport, u8 port_num,
+ u16 vf_num,
+ struct mlx5_hca_vport_context *rep)
+{
+ int out_sz = MLX5_ST_SZ_BYTES(query_hca_vport_context_out);
+ int in[MLX5_ST_SZ_DW(query_hca_vport_context_in)];
+ int is_group_manager;
+ void *out;
+ void *ctx;
+ int err;
+
+ is_group_manager = MLX5_CAP_GEN(dev, vport_group_manager);
+
+ memset(in, 0, sizeof(in));
+ out = kzalloc(out_sz, GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+ MLX5_SET(query_hca_vport_context_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_VPORT_CONTEXT);
+
+ if (other_vport) {
+ if (is_group_manager) {
+ MLX5_SET(query_hca_vport_context_in, in, other_vport, 1);
+ MLX5_SET(query_hca_vport_context_in, in, vport_number, vf_num);
+ } else {
+ err = -EPERM;
+ goto ex;
+ }
+ }
+
+ if (MLX5_CAP_GEN(dev, num_ports) == 2)
+ MLX5_SET(query_hca_vport_context_in, in, port_num, port_num);
+
+ err = mlx5_cmd_exec(dev, in, sizeof(in), out, out_sz);
+ if (err)
+ goto ex;
+ err = mlx5_cmd_status_to_err_v2(out);
+ if (err)
+ goto ex;
+
+ ctx = MLX5_ADDR_OF(query_hca_vport_context_out, out, hca_vport_context);
+ rep->field_select = MLX5_GET_PR(hca_vport_context, ctx, field_select);
+ rep->sm_virt_aware = MLX5_GET_PR(hca_vport_context, ctx, sm_virt_aware);
+ rep->has_smi = MLX5_GET_PR(hca_vport_context, ctx, has_smi);
+ rep->has_raw = MLX5_GET_PR(hca_vport_context, ctx, has_raw);
+ rep->policy = MLX5_GET_PR(hca_vport_context, ctx, vport_state_policy);
+ rep->phys_state = MLX5_GET_PR(hca_vport_context, ctx,
+ port_physical_state);
+ rep->vport_state = MLX5_GET_PR(hca_vport_context, ctx, vport_state);
+ rep->port_physical_state = MLX5_GET_PR(hca_vport_context, ctx,
+ port_physical_state);
+ rep->port_guid = MLX5_GET64_PR(hca_vport_context, ctx, port_guid);
+ rep->node_guid = MLX5_GET64_PR(hca_vport_context, ctx, node_guid);
+ rep->cap_mask1 = MLX5_GET_PR(hca_vport_context, ctx, cap_mask1);
+ rep->cap_mask1_perm = MLX5_GET_PR(hca_vport_context, ctx,
+ cap_mask1_field_select);
+ rep->cap_mask2 = MLX5_GET_PR(hca_vport_context, ctx, cap_mask2);
+ rep->cap_mask2_perm = MLX5_GET_PR(hca_vport_context, ctx,
+ cap_mask2_field_select);
+ rep->lid = MLX5_GET_PR(hca_vport_context, ctx, lid);
+ rep->init_type_reply = MLX5_GET_PR(hca_vport_context, ctx,
+ init_type_reply);
+ rep->lmc = MLX5_GET_PR(hca_vport_context, ctx, lmc);
+ rep->subnet_timeout = MLX5_GET_PR(hca_vport_context, ctx,
+ subnet_timeout);
+ rep->sm_lid = MLX5_GET_PR(hca_vport_context, ctx, sm_lid);
+ rep->sm_sl = MLX5_GET_PR(hca_vport_context, ctx, sm_sl);
+ rep->qkey_violation_counter = MLX5_GET_PR(hca_vport_context, ctx,
+ qkey_violation_counter);
+ rep->pkey_violation_counter = MLX5_GET_PR(hca_vport_context, ctx,
+ pkey_violation_counter);
+ rep->grh_required = MLX5_GET_PR(hca_vport_context, ctx, grh_required);
+ rep->sys_image_guid = MLX5_GET64_PR(hca_vport_context, ctx,
+ system_image_guid);
+
+ex:
+ kfree(out);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_hca_vport_context);
+
+int mlx5_query_hca_vport_system_image_guid(struct mlx5_core_dev *dev,
+ u64 *sys_image_guid)
+{
+ struct mlx5_hca_vport_context *rep;
+ int err;
+
+ rep = kzalloc(sizeof(*rep), GFP_KERNEL);
+ if (!rep)
+ return -ENOMEM;
+
+ err = mlx5_query_hca_vport_context(dev, 0, 1, 0, rep);
+ if (!err)
+ *sys_image_guid = rep->sys_image_guid;
+
+ kfree(rep);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_hca_vport_system_image_guid);
+
+int mlx5_query_hca_vport_node_guid(struct mlx5_core_dev *dev,
+ u64 *node_guid)
+{
+ struct mlx5_hca_vport_context *rep;
+ int err;
+
+ rep = kzalloc(sizeof(*rep), GFP_KERNEL);
+ if (!rep)
+ return -ENOMEM;
+
+ err = mlx5_query_hca_vport_context(dev, 0, 1, 0, rep);
+ if (!err)
+ *node_guid = rep->node_guid;
+
+ kfree(rep);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_hca_vport_node_guid);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.c b/drivers/net/ethernet/mellanox/mlx5/core/wq.c
new file mode 100644
index 000000000000..8388411582cf
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ */
+
+#include <linux/mlx5/driver.h>
+#include "wq.h"
+#include "mlx5_core.h"
+
+u32 mlx5_wq_cyc_get_size(struct mlx5_wq_cyc *wq)
+{
+ return (u32)wq->sz_m1 + 1;
+}
+
+u32 mlx5_cqwq_get_size(struct mlx5_cqwq *wq)
+{
+ return wq->sz_m1 + 1;
+}
+
+u32 mlx5_wq_ll_get_size(struct mlx5_wq_ll *wq)
+{
+ return (u32)wq->sz_m1 + 1;
+}
+
+static u32 mlx5_wq_cyc_get_byte_size(struct mlx5_wq_cyc *wq)
+{
+ return mlx5_wq_cyc_get_size(wq) << wq->log_stride;
+}
+
+static u32 mlx5_cqwq_get_byte_size(struct mlx5_cqwq *wq)
+{
+ return mlx5_cqwq_get_size(wq) << wq->log_stride;
+}
+
+static u32 mlx5_wq_ll_get_byte_size(struct mlx5_wq_ll *wq)
+{
+ return mlx5_wq_ll_get_size(wq) << wq->log_stride;
+}
+
+int mlx5_wq_cyc_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
+ void *wqc, struct mlx5_wq_cyc *wq,
+ struct mlx5_wq_ctrl *wq_ctrl)
+{
+ int err;
+
+ wq->log_stride = MLX5_GET(wq, wqc, log_wq_stride);
+ wq->sz_m1 = (1 << MLX5_GET(wq, wqc, log_wq_sz)) - 1;
+
+ err = mlx5_db_alloc(mdev, &wq_ctrl->db);
+ if (err) {
+ mlx5_core_warn(mdev, "mlx5_db_alloc() failed, %d\n", err);
+ return err;
+ }
+
+ err = mlx5_buf_alloc(mdev, mlx5_wq_cyc_get_byte_size(wq), &wq_ctrl->buf);
+ if (err) {
+ mlx5_core_warn(mdev, "mlx5_buf_alloc() failed, %d\n", err);
+ goto err_db_free;
+ }
+
+ wq->buf = wq_ctrl->buf.direct.buf;
+ wq->db = wq_ctrl->db.db;
+
+ wq_ctrl->mdev = mdev;
+
+ return 0;
+
+err_db_free:
+ mlx5_db_free(mdev, &wq_ctrl->db);
+
+ return err;
+}
+
+int mlx5_cqwq_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
+ void *cqc, struct mlx5_cqwq *wq,
+ struct mlx5_wq_ctrl *wq_ctrl)
+{
+ int err;
+
+ wq->log_stride = 6 + MLX5_GET(cqc, cqc, cqe_sz);
+ wq->log_sz = MLX5_GET(cqc, cqc, log_cq_size);
+ wq->sz_m1 = (1 << wq->log_sz) - 1;
+
+ err = mlx5_db_alloc(mdev, &wq_ctrl->db);
+ if (err) {
+ mlx5_core_warn(mdev, "mlx5_db_alloc() failed, %d\n", err);
+ return err;
+ }
+
+ err = mlx5_buf_alloc(mdev, mlx5_cqwq_get_byte_size(wq), &wq_ctrl->buf);
+ if (err) {
+ mlx5_core_warn(mdev, "mlx5_buf_alloc() failed, %d\n", err);
+ goto err_db_free;
+ }
+
+ wq->buf = wq_ctrl->buf.direct.buf;
+ wq->db = wq_ctrl->db.db;
+
+ wq_ctrl->mdev = mdev;
+
+ return 0;
+
+err_db_free:
+ mlx5_db_free(mdev, &wq_ctrl->db);
+
+ return err;
+}
+
+int mlx5_wq_ll_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
+ void *wqc, struct mlx5_wq_ll *wq,
+ struct mlx5_wq_ctrl *wq_ctrl)
+{
+ struct mlx5_wqe_srq_next_seg *next_seg;
+ int err;
+ int i;
+
+ wq->log_stride = MLX5_GET(wq, wqc, log_wq_stride);
+ wq->sz_m1 = (1 << MLX5_GET(wq, wqc, log_wq_sz)) - 1;
+
+ err = mlx5_db_alloc(mdev, &wq_ctrl->db);
+ if (err) {
+ mlx5_core_warn(mdev, "mlx5_db_alloc() failed, %d\n", err);
+ return err;
+ }
+
+ err = mlx5_buf_alloc(mdev, mlx5_wq_ll_get_byte_size(wq), &wq_ctrl->buf);
+ if (err) {
+ mlx5_core_warn(mdev, "mlx5_buf_alloc() failed, %d\n", err);
+ goto err_db_free;
+ }
+
+ wq->buf = wq_ctrl->buf.direct.buf;
+ wq->db = wq_ctrl->db.db;
+
+ for (i = 0; i < wq->sz_m1; i++) {
+ next_seg = mlx5_wq_ll_get_wqe(wq, i);
+ next_seg->next_wqe_index = cpu_to_be16(i + 1);
+ }
+ next_seg = mlx5_wq_ll_get_wqe(wq, i);
+ wq->tail_next = &next_seg->next_wqe_index;
+
+ wq_ctrl->mdev = mdev;
+
+ return 0;
+
+err_db_free:
+ mlx5_db_free(mdev, &wq_ctrl->db);
+
+ return err;
+}
+
+void mlx5_wq_destroy(struct mlx5_wq_ctrl *wq_ctrl)
+{
+ mlx5_buf_free(wq_ctrl->mdev, &wq_ctrl->buf);
+ mlx5_db_free(wq_ctrl->mdev, &wq_ctrl->db);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.h b/drivers/net/ethernet/mellanox/mlx5/core/wq.h
new file mode 100644
index 000000000000..e0ddd69fb429
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 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.
+ */
+
+#ifndef __MLX5_WQ_H__
+#define __MLX5_WQ_H__
+
+#include <linux/mlx5/mlx5_ifc.h>
+
+struct mlx5_wq_param {
+ int linear;
+ int numa;
+};
+
+struct mlx5_wq_ctrl {
+ struct mlx5_core_dev *mdev;
+ struct mlx5_buf buf;
+ struct mlx5_db db;
+};
+
+struct mlx5_wq_cyc {
+ void *buf;
+ __be32 *db;
+ u16 sz_m1;
+ u8 log_stride;
+};
+
+struct mlx5_cqwq {
+ void *buf;
+ __be32 *db;
+ u32 sz_m1;
+ u32 cc; /* consumer counter */
+ u8 log_sz;
+ u8 log_stride;
+};
+
+struct mlx5_wq_ll {
+ void *buf;
+ __be32 *db;
+ __be16 *tail_next;
+ u16 sz_m1;
+ u16 head;
+ u16 wqe_ctr;
+ u16 cur_sz;
+ u8 log_stride;
+};
+
+int mlx5_wq_cyc_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
+ void *wqc, struct mlx5_wq_cyc *wq,
+ struct mlx5_wq_ctrl *wq_ctrl);
+u32 mlx5_wq_cyc_get_size(struct mlx5_wq_cyc *wq);
+
+int mlx5_cqwq_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
+ void *cqc, struct mlx5_cqwq *wq,
+ struct mlx5_wq_ctrl *wq_ctrl);
+u32 mlx5_cqwq_get_size(struct mlx5_cqwq *wq);
+
+int mlx5_wq_ll_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
+ void *wqc, struct mlx5_wq_ll *wq,
+ struct mlx5_wq_ctrl *wq_ctrl);
+u32 mlx5_wq_ll_get_size(struct mlx5_wq_ll *wq);
+
+void mlx5_wq_destroy(struct mlx5_wq_ctrl *wq_ctrl);
+
+static inline u16 mlx5_wq_cyc_ctr2ix(struct mlx5_wq_cyc *wq, u16 ctr)
+{
+ return ctr & wq->sz_m1;
+}
+
+static inline void *mlx5_wq_cyc_get_wqe(struct mlx5_wq_cyc *wq, u16 ix)
+{
+ return wq->buf + (ix << wq->log_stride);
+}
+
+static inline int mlx5_wq_cyc_cc_bigger(u16 cc1, u16 cc2)
+{
+ int equal = (cc1 == cc2);
+ int smaller = 0x8000 & (cc1 - cc2);
+
+ return !equal && !smaller;
+}
+
+static inline u32 mlx5_cqwq_get_ci(struct mlx5_cqwq *wq)
+{
+ return wq->cc & wq->sz_m1;
+}
+
+static inline void *mlx5_cqwq_get_wqe(struct mlx5_cqwq *wq, u32 ix)
+{
+ return wq->buf + (ix << wq->log_stride);
+}
+
+static inline u32 mlx5_cqwq_get_wrap_cnt(struct mlx5_cqwq *wq)
+{
+ return wq->cc >> wq->log_sz;
+}
+
+static inline void mlx5_cqwq_pop(struct mlx5_cqwq *wq)
+{
+ wq->cc++;
+}
+
+static inline void mlx5_cqwq_update_db_record(struct mlx5_cqwq *wq)
+{
+ *wq->db = cpu_to_be32(wq->cc & 0xffffff);
+}
+
+static inline int mlx5_wq_ll_is_full(struct mlx5_wq_ll *wq)
+{
+ return wq->cur_sz == wq->sz_m1;
+}
+
+static inline int mlx5_wq_ll_is_empty(struct mlx5_wq_ll *wq)
+{
+ return !wq->cur_sz;
+}
+
+static inline void *mlx5_wq_ll_get_wqe(struct mlx5_wq_ll *wq, u16 ix)
+{
+ return wq->buf + (ix << wq->log_stride);
+}
+
+static inline void mlx5_wq_ll_push(struct mlx5_wq_ll *wq, u16 head_next)
+{
+ wq->head = head_next;
+ wq->wqe_ctr++;
+ wq->cur_sz++;
+}
+
+static inline void mlx5_wq_ll_pop(struct mlx5_wq_ll *wq, __be16 ix,
+ __be16 *next_tail_next)
+{
+ *wq->tail_next = ix;
+ wq->tail_next = next_tail_next;
+ wq->cur_sz--;
+}
+
+static inline void mlx5_wq_ll_update_db_record(struct mlx5_wq_ll *wq)
+{
+ *wq->db = cpu_to_be32(wq->wqe_ctr);
+}
+
+#endif /* __MLX5_WQ_H__ */
diff --git a/drivers/net/ethernet/micrel/Kconfig b/drivers/net/ethernet/micrel/Kconfig
index d16b11ed2e52..b7e2f49696b7 100644
--- a/drivers/net/ethernet/micrel/Kconfig
+++ b/drivers/net/ethernet/micrel/Kconfig
@@ -8,9 +8,7 @@ config NET_VENDOR_MICREL
depends on (HAS_IOMEM && DMA_ENGINE) || SPI || PCI || HAS_IOMEM || \
(ARM && ARCH_KS8695)
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c
index 6f332ebdf3b5..75dc46c5fca2 100644
--- a/drivers/net/ethernet/micrel/ksz884x.c
+++ b/drivers/net/ethernet/micrel/ksz884x.c
@@ -6664,7 +6664,7 @@ static void mib_read_work(struct work_struct *work)
wake_up_interruptible(
&hw_priv->counter[i].counter);
}
- } else if (jiffies >= hw_priv->counter[i].time) {
+ } else if (time_after_eq(jiffies, hw_priv->counter[i].time)) {
/* Only read MIB counters when the port is connected. */
if (media_connected == mib->state)
hw_priv->counter[i].read = 1;
@@ -6689,7 +6689,7 @@ static void mib_monitor(unsigned long ptr)
/* This is used to verify Wake-on-LAN is working. */
if (hw_priv->pme_wait) {
- if (hw_priv->pme_wait <= jiffies) {
+ if (time_is_before_eq_jiffies(hw_priv->pme_wait)) {
hw_clr_wol_pme_status(&hw_priv->hw);
hw_priv->pme_wait = 0;
}
diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
index afaf0c07f37f..3fd8ca6d4e7c 100644
--- a/drivers/net/ethernet/microchip/Kconfig
+++ b/drivers/net/ethernet/microchip/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_MICROCHIP
default y
depends on SPI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/moxa/Kconfig b/drivers/net/ethernet/moxa/Kconfig
index 1731e050fa27..5b531da36933 100644
--- a/drivers/net/ethernet/moxa/Kconfig
+++ b/drivers/net/ethernet/moxa/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_MOXART
default y
depends on (ARM && ARCH_MOXART)
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c
index 81d0f1c86d6d..becbb5f1f5a7 100644
--- a/drivers/net/ethernet/moxa/moxart_ether.c
+++ b/drivers/net/ethernet/moxa/moxart_ether.c
@@ -244,7 +244,6 @@ static int moxart_rx_poll(struct napi_struct *napi, int budget)
napi_gro_receive(&priv->napi, skb);
rx++;
- ndev->last_rx = jiffies;
priv->stats.rx_packets++;
priv->stats.rx_bytes += len;
if (desc0 & RX_DESC0_MULTICAST)
diff --git a/drivers/net/ethernet/myricom/Kconfig b/drivers/net/ethernet/myricom/Kconfig
index 3932d081fa21..9645c7245bbf 100644
--- a/drivers/net/ethernet/myricom/Kconfig
+++ b/drivers/net/ethernet/myricom/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_MYRI
default y
depends on PCI && INET
---help---
- If you have a network (Ethernet) card belonging to this class, say
- Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/natsemi/Kconfig b/drivers/net/ethernet/natsemi/Kconfig
index a100860d45e6..a10ef50e4f12 100644
--- a/drivers/net/ethernet/natsemi/Kconfig
+++ b/drivers/net/ethernet/natsemi/Kconfig
@@ -6,9 +6,7 @@ config NET_VENDOR_NATSEMI
bool "National Semi-conductor devices"
default y
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
@@ -24,8 +22,7 @@ config MACSONIC
Support for NatSemi SONIC based Ethernet devices. This includes
the onboard Ethernet in many Quadras as well as some LC-PDS,
a few Nubus and all known Comm Slot Ethernet cards. If you have
- one of these say Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ one of these say Y here.
To compile this driver as a module, choose M here. This module will
be called macsonic.
diff --git a/drivers/net/ethernet/neterion/Kconfig b/drivers/net/ethernet/neterion/Kconfig
index 87abb4f10c43..71899009c468 100644
--- a/drivers/net/ethernet/neterion/Kconfig
+++ b/drivers/net/ethernet/neterion/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_EXAR
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say
- Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index 1e0f72b65459..c28111749e1f 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -5308,7 +5308,8 @@ static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr)
/**
* s2io_ethtool_sset - Sets different link parameters.
- * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure.
+ * @sp : private member of the device structure, which is a pointer to the
+ * s2io_nic structure.
* @info: pointer to the structure with parameters given by ethtool to set
* link information.
* Description:
@@ -5793,7 +5794,8 @@ static void s2io_vpd_read(struct s2io_nic *nic)
/**
* s2io_ethtool_geeprom - reads the value stored in the Eeprom.
- * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure.
+ * @sp : private member of the device structure, which is a pointer to the
+ * s2io_nic structure.
* @eeprom : pointer to the user level structure provided by ethtool,
* containing all relevant information.
* @data_buf : user defined value to be written into Eeprom.
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-traffic.c b/drivers/net/ethernet/neterion/vxge/vxge-traffic.c
index 9e1aaa7f36bb..5f630a24e491 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-traffic.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-traffic.c
@@ -1004,8 +1004,6 @@ void vxge_hw_device_clear_tx_rx(struct __vxge_hw_device *hldev)
static enum vxge_hw_status
vxge_hw_channel_dtr_alloc(struct __vxge_hw_channel *channel, void **dtrh)
{
- void **tmp_arr;
-
if (channel->reserve_ptr - channel->reserve_top > 0) {
_alloc_after_swap:
*dtrh = channel->reserve_arr[--channel->reserve_ptr];
@@ -1020,10 +1018,7 @@ _alloc_after_swap:
* i.e. no additional lock need to be done when we free a resource */
if (channel->length - channel->free_ptr > 0) {
-
- tmp_arr = channel->reserve_arr;
- channel->reserve_arr = channel->free_arr;
- channel->free_arr = tmp_arr;
+ swap(channel->reserve_arr, channel->free_arr);
channel->reserve_ptr = channel->length;
channel->reserve_top = channel->free_ptr;
channel->free_ptr = channel->length;
diff --git a/drivers/net/ethernet/nuvoton/Kconfig b/drivers/net/ethernet/nuvoton/Kconfig
index 01182b559473..71c973f8e50f 100644
--- a/drivers/net/ethernet/nuvoton/Kconfig
+++ b/drivers/net/ethernet/nuvoton/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_NUVOTON
default y
depends on ARM && ARCH_W90X900
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/nvidia/Kconfig b/drivers/net/ethernet/nvidia/Kconfig
index ace19e7f6d13..4efc9fe84785 100644
--- a/drivers/net/ethernet/nvidia/Kconfig
+++ b/drivers/net/ethernet/nvidia/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_NVIDIA
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
@@ -22,9 +20,7 @@ config FORCEDETH
tristate "nForce Ethernet support"
depends on PCI
---help---
- If you have a network (Ethernet) controller of this type, say Y and
- read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) controller of this type, say Y here.
To compile this driver as a module, choose M here. The module
will be called forcedeth.
diff --git a/drivers/net/ethernet/oki-semi/Kconfig b/drivers/net/ethernet/oki-semi/Kconfig
index ecd45f9ea9d9..5a975af4824b 100644
--- a/drivers/net/ethernet/oki-semi/Kconfig
+++ b/drivers/net/ethernet/oki-semi/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_OKI
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/packetengines/Kconfig b/drivers/net/ethernet/packetengines/Kconfig
index 8d5180043c70..b5ea2a56106e 100644
--- a/drivers/net/ethernet/packetengines/Kconfig
+++ b/drivers/net/ethernet/packetengines/Kconfig
@@ -7,9 +7,7 @@ config NET_PACKET_ENGINE
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
@@ -23,9 +21,7 @@ config HAMACHI
depends on PCI
select MII
---help---
- If you have a Gigabit Ethernet card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a Gigabit Ethernet card of this type, say Y here.
To compile this driver as a module, choose M here. The module will be
called hamachi.
diff --git a/drivers/net/ethernet/pasemi/Kconfig b/drivers/net/ethernet/pasemi/Kconfig
index 01e6c329d78c..db19c6f49859 100644
--- a/drivers/net/ethernet/pasemi/Kconfig
+++ b/drivers/net/ethernet/pasemi/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_PASEMI
default y
depends on PPC_PASEMI && PCI && INET
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig
index d49cba129081..f1f0108c275d 100644
--- a/drivers/net/ethernet/qlogic/Kconfig
+++ b/drivers/net/ethernet/qlogic/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_QLOGIC
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index f221126a5c4e..055f3763e577 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -1326,9 +1326,6 @@ struct qlcnic_eswitch {
};
-/* Return codes for Error handling */
-#define QL_STATUS_INVALID_PARAM -1
-
#define MAX_BW 100 /* % of link speed */
#define MIN_BW 1 /* % of link speed */
#define MAX_VLAN_ID 4095
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 367f3976df56..2f6cc423ab1d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -1031,7 +1031,7 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
pfn = pci_info[i].id;
if (pfn >= ahw->max_vnic_func) {
- ret = QL_STATUS_INVALID_PARAM;
+ ret = -EINVAL;
dev_err(&adapter->pdev->dev, "%s: Invalid function 0x%x, max 0x%x\n",
__func__, pfn, ahw->max_vnic_func);
goto err_eswitch;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
index 59a721fba018..05c28f2c6df7 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
@@ -24,8 +24,6 @@
#include <linux/hwmon-sysfs.h>
#endif
-#define QLC_STATUS_UNSUPPORTED_CMD -2
-
int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
{
return -EOPNOTSUPP;
@@ -166,7 +164,7 @@ static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter,
u8 b_state, b_rate;
if (len != sizeof(u16))
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
memcpy(&beacon, buf, sizeof(u16));
err = qlcnic_validate_beacon(adapter, beacon, &b_state, &b_rate);
@@ -383,17 +381,17 @@ static int validate_pm_config(struct qlcnic_adapter *adapter,
dest_pci_func = pm_cfg[i].dest_npar;
src_index = qlcnic_is_valid_nic_func(adapter, src_pci_func);
if (src_index < 0)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
dest_index = qlcnic_is_valid_nic_func(adapter, dest_pci_func);
if (dest_index < 0)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
s_esw_id = adapter->npars[src_index].phy_port;
d_esw_id = adapter->npars[dest_index].phy_port;
if (s_esw_id != d_esw_id)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
}
return 0;
@@ -414,7 +412,7 @@ static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp,
count = size / sizeof(struct qlcnic_pm_func_cfg);
rem = size % sizeof(struct qlcnic_pm_func_cfg);
if (rem)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
pm_cfg = (struct qlcnic_pm_func_cfg *)buf;
@@ -427,7 +425,7 @@ static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp,
action = !!pm_cfg[i].action;
index = qlcnic_is_valid_nic_func(adapter, pci_func);
if (index < 0)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
id = adapter->npars[index].phy_port;
ret = qlcnic_config_port_mirroring(adapter, id,
@@ -440,7 +438,7 @@ static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp,
pci_func = pm_cfg[i].pci_func;
index = qlcnic_is_valid_nic_func(adapter, pci_func);
if (index < 0)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
id = adapter->npars[index].phy_port;
adapter->npars[index].enable_pm = !!pm_cfg[i].action;
adapter->npars[index].dest_npar = id;
@@ -499,11 +497,11 @@ static int validate_esw_config(struct qlcnic_adapter *adapter,
for (i = 0; i < count; i++) {
pci_func = esw_cfg[i].pci_func;
if (pci_func >= ahw->max_vnic_func)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
switch (esw_cfg[i].op_mode) {
case QLCNIC_PORT_DEFAULTS:
@@ -517,25 +515,25 @@ static int validate_esw_config(struct qlcnic_adapter *adapter,
if (ret != QLCNIC_NON_PRIV_FUNC) {
if (esw_cfg[i].mac_anti_spoof != 0)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
if (esw_cfg[i].mac_override != 1)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
if (esw_cfg[i].promisc_mode != 1)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
}
break;
case QLCNIC_ADD_VLAN:
if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
if (!esw_cfg[i].op_type)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
break;
case QLCNIC_DEL_VLAN:
if (!esw_cfg[i].op_type)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
break;
default:
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
}
}
@@ -559,7 +557,7 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file,
count = size / sizeof(struct qlcnic_esw_func_cfg);
rem = size % sizeof(struct qlcnic_esw_func_cfg);
if (rem)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
esw_cfg = (struct qlcnic_esw_func_cfg *)buf;
@@ -570,7 +568,7 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file,
for (i = 0; i < count; i++) {
if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
if (adapter->ahw->pci_func != esw_cfg[i].pci_func)
continue;
@@ -604,7 +602,7 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file,
pci_func = esw_cfg[i].pci_func;
index = qlcnic_is_valid_nic_func(adapter, pci_func);
if (index < 0)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
npar = &adapter->npars[index];
switch (esw_cfg[i].op_mode) {
case QLCNIC_PORT_DEFAULTS:
@@ -654,7 +652,7 @@ static ssize_t qlcnic_sysfs_read_esw_config(struct file *file,
esw_cfg[pci_func].pci_func = pci_func;
if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[pci_func]))
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
}
qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
return size;
@@ -669,11 +667,11 @@ static int validate_npar_config(struct qlcnic_adapter *adapter,
for (i = 0; i < count; i++) {
pci_func = np_cfg[i].pci_func;
if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
if (!IS_VALID_BW(np_cfg[i].min_bw) ||
!IS_VALID_BW(np_cfg[i].max_bw))
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
}
return 0;
}
@@ -694,7 +692,7 @@ static ssize_t qlcnic_sysfs_write_npar_config(struct file *file,
count = size / sizeof(struct qlcnic_npar_func_cfg);
rem = size % sizeof(struct qlcnic_npar_func_cfg);
if (rem)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
np_cfg = (struct qlcnic_npar_func_cfg *)buf;
@@ -717,7 +715,7 @@ static ssize_t qlcnic_sysfs_write_npar_config(struct file *file,
return ret;
index = qlcnic_is_valid_nic_func(adapter, pci_func);
if (index < 0)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
adapter->npars[index].min_bw = nic_info.min_tx_bw;
adapter->npars[index].max_bw = nic_info.max_tx_bw;
}
@@ -784,13 +782,13 @@ static ssize_t qlcnic_sysfs_get_port_stats(struct file *file,
int ret;
if (qlcnic_83xx_check(adapter))
- return QLC_STATUS_UNSUPPORTED_CMD;
+ return -EOPNOTSUPP;
if (size != sizeof(struct qlcnic_esw_statistics))
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
if (offset >= adapter->ahw->max_vnic_func)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
memset(&port_stats, 0, size);
ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
@@ -819,13 +817,13 @@ static ssize_t qlcnic_sysfs_get_esw_stats(struct file *file,
int ret;
if (qlcnic_83xx_check(adapter))
- return QLC_STATUS_UNSUPPORTED_CMD;
+ return -EOPNOTSUPP;
if (size != sizeof(struct qlcnic_esw_statistics))
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
memset(&esw_stats, 0, size);
ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
@@ -853,10 +851,10 @@ static ssize_t qlcnic_sysfs_clear_esw_stats(struct file *file,
int ret;
if (qlcnic_83xx_check(adapter))
- return QLC_STATUS_UNSUPPORTED_CMD;
+ return -EOPNOTSUPP;
if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
QLCNIC_QUERY_RX_COUNTER);
@@ -883,10 +881,10 @@ static ssize_t qlcnic_sysfs_clear_port_stats(struct file *file,
int ret;
if (qlcnic_83xx_check(adapter))
- return QLC_STATUS_UNSUPPORTED_CMD;
+ return -EOPNOTSUPP;
if (offset >= adapter->ahw->max_vnic_func)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
QLCNIC_QUERY_RX_COUNTER);
@@ -953,9 +951,7 @@ static ssize_t qlcnic_83xx_sysfs_flash_read_handler(struct file *filp,
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
if (!size)
- return QL_STATUS_INVALID_PARAM;
- if (!buf)
- return QL_STATUS_INVALID_PARAM;
+ return -EINVAL;
count = size / sizeof(u32);
@@ -1132,9 +1128,6 @@ static ssize_t qlcnic_83xx_sysfs_flash_write_handler(struct file *filp,
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- if (!buf)
- return QL_STATUS_INVALID_PARAM;
-
ret = kstrtoul(buf, 16, &data);
switch (data) {
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
index 25800a1dedcb..02b7115b6aaa 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
@@ -3871,9 +3871,6 @@ static int ql_adapter_reset(struct ql_adapter *qdev)
return status;
}
- end_jiffies = jiffies +
- max((unsigned long)1, usecs_to_jiffies(30));
-
/* Check if bit is set then skip the mailbox command and
* clear the bit, else we are in normal reset process.
*/
@@ -3888,6 +3885,7 @@ static int ql_adapter_reset(struct ql_adapter *qdev)
ql_write32(qdev, RST_FO, (RST_FO_FR << 16) | RST_FO_FR);
+ end_jiffies = jiffies + usecs_to_jiffies(30);
do {
value = ql_read32(qdev, RST_FO);
if ((value & RST_FO_FR) == 0)
diff --git a/drivers/net/ethernet/qualcomm/Kconfig b/drivers/net/ethernet/qualcomm/Kconfig
index 9a49f42ac2ba..a76e380cf89a 100644
--- a/drivers/net/ethernet/qualcomm/Kconfig
+++ b/drivers/net/ethernet/qualcomm/Kconfig
@@ -6,9 +6,7 @@ config NET_VENDOR_QUALCOMM
bool "Qualcomm devices"
default y
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index 6af028d5f9bc..2f87909f5186 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -839,7 +839,7 @@ static const struct of_device_id qca_spi_of_match[] = {
MODULE_DEVICE_TABLE(of, qca_spi_of_match);
static int
-qca_spi_probe(struct spi_device *spi_device)
+qca_spi_probe(struct spi_device *spi)
{
struct qcaspi *qca = NULL;
struct net_device *qcaspi_devs = NULL;
@@ -847,52 +847,52 @@ qca_spi_probe(struct spi_device *spi_device)
u16 signature;
const char *mac;
- if (!spi_device->dev.of_node) {
- dev_err(&spi_device->dev, "Missing device tree\n");
+ if (!spi->dev.of_node) {
+ dev_err(&spi->dev, "Missing device tree\n");
return -EINVAL;
}
- legacy_mode = of_property_read_bool(spi_device->dev.of_node,
+ legacy_mode = of_property_read_bool(spi->dev.of_node,
"qca,legacy-mode");
if (qcaspi_clkspeed == 0) {
- if (spi_device->max_speed_hz)
- qcaspi_clkspeed = spi_device->max_speed_hz;
+ if (spi->max_speed_hz)
+ qcaspi_clkspeed = spi->max_speed_hz;
else
qcaspi_clkspeed = QCASPI_CLK_SPEED;
}
if ((qcaspi_clkspeed < QCASPI_CLK_SPEED_MIN) ||
(qcaspi_clkspeed > QCASPI_CLK_SPEED_MAX)) {
- dev_info(&spi_device->dev, "Invalid clkspeed: %d\n",
+ dev_info(&spi->dev, "Invalid clkspeed: %d\n",
qcaspi_clkspeed);
return -EINVAL;
}
if ((qcaspi_burst_len < QCASPI_BURST_LEN_MIN) ||
(qcaspi_burst_len > QCASPI_BURST_LEN_MAX)) {
- dev_info(&spi_device->dev, "Invalid burst len: %d\n",
+ dev_info(&spi->dev, "Invalid burst len: %d\n",
qcaspi_burst_len);
return -EINVAL;
}
if ((qcaspi_pluggable < QCASPI_PLUGGABLE_MIN) ||
(qcaspi_pluggable > QCASPI_PLUGGABLE_MAX)) {
- dev_info(&spi_device->dev, "Invalid pluggable: %d\n",
+ dev_info(&spi->dev, "Invalid pluggable: %d\n",
qcaspi_pluggable);
return -EINVAL;
}
- dev_info(&spi_device->dev, "ver=%s, clkspeed=%d, burst_len=%d, pluggable=%d\n",
+ dev_info(&spi->dev, "ver=%s, clkspeed=%d, burst_len=%d, pluggable=%d\n",
QCASPI_DRV_VERSION,
qcaspi_clkspeed,
qcaspi_burst_len,
qcaspi_pluggable);
- spi_device->mode = SPI_MODE_3;
- spi_device->max_speed_hz = qcaspi_clkspeed;
- if (spi_setup(spi_device) < 0) {
- dev_err(&spi_device->dev, "Unable to setup SPI device\n");
+ spi->mode = SPI_MODE_3;
+ spi->max_speed_hz = qcaspi_clkspeed;
+ if (spi_setup(spi) < 0) {
+ dev_err(&spi->dev, "Unable to setup SPI device\n");
return -EFAULT;
}
@@ -905,23 +905,23 @@ qca_spi_probe(struct spi_device *spi_device)
qca = netdev_priv(qcaspi_devs);
if (!qca) {
free_netdev(qcaspi_devs);
- dev_err(&spi_device->dev, "Fail to retrieve private structure\n");
+ dev_err(&spi->dev, "Fail to retrieve private structure\n");
return -ENOMEM;
}
qca->net_dev = qcaspi_devs;
- qca->spi_dev = spi_device;
+ qca->spi_dev = spi;
qca->legacy_mode = legacy_mode;
- spi_set_drvdata(spi_device, qcaspi_devs);
+ spi_set_drvdata(spi, qcaspi_devs);
- mac = of_get_mac_address(spi_device->dev.of_node);
+ mac = of_get_mac_address(spi->dev.of_node);
if (mac)
ether_addr_copy(qca->net_dev->dev_addr, mac);
if (!is_valid_ether_addr(qca->net_dev->dev_addr)) {
eth_hw_addr_random(qca->net_dev);
- dev_info(&spi_device->dev, "Using random MAC address: %pM\n",
+ dev_info(&spi->dev, "Using random MAC address: %pM\n",
qca->net_dev->dev_addr);
}
@@ -932,7 +932,7 @@ qca_spi_probe(struct spi_device *spi_device)
qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature);
if (signature != QCASPI_GOOD_SIGNATURE) {
- dev_err(&spi_device->dev, "Invalid signature (0x%04X)\n",
+ dev_err(&spi->dev, "Invalid signature (0x%04X)\n",
signature);
free_netdev(qcaspi_devs);
return -EFAULT;
@@ -940,7 +940,7 @@ qca_spi_probe(struct spi_device *spi_device)
}
if (register_netdev(qcaspi_devs)) {
- dev_info(&spi_device->dev, "Unable to register net device %s\n",
+ dev_info(&spi->dev, "Unable to register net device %s\n",
qcaspi_devs->name);
free_netdev(qcaspi_devs);
return -EFAULT;
@@ -952,9 +952,9 @@ qca_spi_probe(struct spi_device *spi_device)
}
static int
-qca_spi_remove(struct spi_device *spi_device)
+qca_spi_remove(struct spi_device *spi)
{
- struct net_device *qcaspi_devs = spi_get_drvdata(spi_device);
+ struct net_device *qcaspi_devs = spi_get_drvdata(spi);
struct qcaspi *qca = netdev_priv(qcaspi_devs);
qcaspi_remove_device_debugfs(qca);
diff --git a/drivers/net/ethernet/rdc/Kconfig b/drivers/net/ethernet/rdc/Kconfig
index 2055f7eb2ba9..a9c4e990d29b 100644
--- a/drivers/net/ethernet/rdc/Kconfig
+++ b/drivers/net/ethernet/rdc/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_RDC
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig
index ae5d027096ed..7c69f4c8134d 100644
--- a/drivers/net/ethernet/realtek/Kconfig
+++ b/drivers/net/ethernet/realtek/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_REALTEK
default y
depends on PCI || (PARPORT && X86)
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
@@ -24,8 +22,7 @@ config ATP
select CRC32
---help---
This is a network (Ethernet) device which attaches to your parallel
- port. Read <file:drivers/net/ethernet/realtek/atp.c> as well as the
- Ethernet-HOWTO, available from <http://www.tldp.org/docs.html#howto>,
+ port. Read the file <file:drivers/net/ethernet/realtek/atp.c>
if you want to use this. If you intend to use this driver, you
should have said N to the "Parallel printer support", because the two
drivers don't like each other.
@@ -40,9 +37,7 @@ config 8139CP
select MII
---help---
This is a driver for the Fast Ethernet PCI network cards based on
- the RTL8139C+ chips. If you have one of those, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ the RTL8139C+ chips. If you have one of those, say Y here.
To compile this driver as a module, choose M here: the module
will be called 8139cp. This is recommended.
@@ -54,8 +49,7 @@ config 8139TOO
select MII
---help---
This is a driver for the Fast Ethernet PCI network cards based on
- the RTL 8129/8130/8139 chips. If you have one of those, say Y and
- read the Ethernet-HOWTO <http://www.tldp.org/docs.html#howto>.
+ the RTL 8129/8130/8139 chips. If you have one of those, say Y here.
To compile this driver as a module, choose M here: the module
will be called 8139too. This is recommended.
diff --git a/drivers/net/ethernet/renesas/Kconfig b/drivers/net/ethernet/renesas/Kconfig
index 196e98a2d93b..270c4c9cac7f 100644
--- a/drivers/net/ethernet/renesas/Kconfig
+++ b/drivers/net/ethernet/renesas/Kconfig
@@ -2,6 +2,19 @@
# Renesas device configuration
#
+config NET_VENDOR_RENESAS
+ bool "Renesas devices"
+ default y
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Renesas devices. If you say Y, you will be asked
+ for your specific device in the following questions.
+
+if NET_VENDOR_RENESAS
+
config SH_ETH
tristate "Renesas SuperH Ethernet support"
depends on HAS_DMA
@@ -15,3 +28,19 @@ config SH_ETH
This driver supporting CPUs are:
- SH7619, SH7710, SH7712, SH7724, SH7734, SH7763, SH7757,
R8A7740, R8A777x and R8A779x.
+
+config RAVB
+ tristate "Renesas Ethernet AVB support"
+ depends on HAS_DMA
+ depends on ARCH_SHMOBILE || COMPILE_TEST
+ select CRC32
+ select MII
+ select MDIO_BITBANG
+ select PHYLIB
+ select PTP_1588_CLOCK
+ help
+ Renesas Ethernet AVB device driver.
+ This driver supports the following SoCs:
+ - R8A779x.
+
+endif # NET_VENDOR_RENESAS
diff --git a/drivers/net/ethernet/renesas/Makefile b/drivers/net/ethernet/renesas/Makefile
index 1c278a8e066a..a05102a7df02 100644
--- a/drivers/net/ethernet/renesas/Makefile
+++ b/drivers/net/ethernet/renesas/Makefile
@@ -3,3 +3,7 @@
#
obj-$(CONFIG_SH_ETH) += sh_eth.o
+
+ravb-objs := ravb_main.o ravb_ptp.o
+
+obj-$(CONFIG_RAVB) += ravb.o
diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
new file mode 100644
index 000000000000..8aa50ac4e2d6
--- /dev/null
+++ b/drivers/net/ethernet/renesas/ravb.h
@@ -0,0 +1,832 @@
+/* Renesas Ethernet AVB device driver
+ *
+ * Copyright (C) 2014-2015 Renesas Electronics Corporation
+ * Copyright (C) 2015 Renesas Solutions Corp.
+ * Copyright (C) 2015 Cogent Embedded, Inc. <source@cogentembedded.com>
+ *
+ * Based on the SuperH Ethernet driver
+ *
+ * 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.
+ */
+
+#ifndef __RAVB_H__
+#define __RAVB_H__
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mdio-bitbang.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ptp_clock_kernel.h>
+
+#define BE_TX_RING_SIZE 64 /* TX ring size for Best Effort */
+#define BE_RX_RING_SIZE 1024 /* RX ring size for Best Effort */
+#define NC_TX_RING_SIZE 64 /* TX ring size for Network Control */
+#define NC_RX_RING_SIZE 64 /* RX ring size for Network Control */
+#define BE_TX_RING_MIN 64
+#define BE_RX_RING_MIN 64
+#define BE_TX_RING_MAX 1024
+#define BE_RX_RING_MAX 2048
+
+#define PKT_BUF_SZ 1538
+
+/* Driver's parameters */
+#define RAVB_ALIGN 128
+
+/* Hardware time stamp */
+#define RAVB_TXTSTAMP_VALID 0x00000001 /* TX timestamp valid */
+#define RAVB_TXTSTAMP_ENABLED 0x00000010 /* Enable TX timestamping */
+
+#define RAVB_RXTSTAMP_VALID 0x00000001 /* RX timestamp valid */
+#define RAVB_RXTSTAMP_TYPE 0x00000006 /* RX type mask */
+#define RAVB_RXTSTAMP_TYPE_V2_L2_EVENT 0x00000002
+#define RAVB_RXTSTAMP_TYPE_ALL 0x00000006
+#define RAVB_RXTSTAMP_ENABLED 0x00000010 /* Enable RX timestamping */
+
+enum ravb_reg {
+ /* AVB-DMAC registers */
+ CCC = 0x0000,
+ DBAT = 0x0004,
+ DLR = 0x0008,
+ CSR = 0x000C,
+ CDAR0 = 0x0010,
+ CDAR1 = 0x0014,
+ CDAR2 = 0x0018,
+ CDAR3 = 0x001C,
+ CDAR4 = 0x0020,
+ CDAR5 = 0x0024,
+ CDAR6 = 0x0028,
+ CDAR7 = 0x002C,
+ CDAR8 = 0x0030,
+ CDAR9 = 0x0034,
+ CDAR10 = 0x0038,
+ CDAR11 = 0x003C,
+ CDAR12 = 0x0040,
+ CDAR13 = 0x0044,
+ CDAR14 = 0x0048,
+ CDAR15 = 0x004C,
+ CDAR16 = 0x0050,
+ CDAR17 = 0x0054,
+ CDAR18 = 0x0058,
+ CDAR19 = 0x005C,
+ CDAR20 = 0x0060,
+ CDAR21 = 0x0064,
+ ESR = 0x0088,
+ RCR = 0x0090,
+ RQC0 = 0x0094,
+ RQC1 = 0x0098,
+ RQC2 = 0x009C,
+ RQC3 = 0x00A0,
+ RQC4 = 0x00A4,
+ RPC = 0x00B0,
+ UFCW = 0x00BC,
+ UFCS = 0x00C0,
+ UFCV0 = 0x00C4,
+ UFCV1 = 0x00C8,
+ UFCV2 = 0x00CC,
+ UFCV3 = 0x00D0,
+ UFCV4 = 0x00D4,
+ UFCD0 = 0x00E0,
+ UFCD1 = 0x00E4,
+ UFCD2 = 0x00E8,
+ UFCD3 = 0x00EC,
+ UFCD4 = 0x00F0,
+ SFO = 0x00FC,
+ SFP0 = 0x0100,
+ SFP1 = 0x0104,
+ SFP2 = 0x0108,
+ SFP3 = 0x010C,
+ SFP4 = 0x0110,
+ SFP5 = 0x0114,
+ SFP6 = 0x0118,
+ SFP7 = 0x011C,
+ SFP8 = 0x0120,
+ SFP9 = 0x0124,
+ SFP10 = 0x0128,
+ SFP11 = 0x012C,
+ SFP12 = 0x0130,
+ SFP13 = 0x0134,
+ SFP14 = 0x0138,
+ SFP15 = 0x013C,
+ SFP16 = 0x0140,
+ SFP17 = 0x0144,
+ SFP18 = 0x0148,
+ SFP19 = 0x014C,
+ SFP20 = 0x0150,
+ SFP21 = 0x0154,
+ SFP22 = 0x0158,
+ SFP23 = 0x015C,
+ SFP24 = 0x0160,
+ SFP25 = 0x0164,
+ SFP26 = 0x0168,
+ SFP27 = 0x016C,
+ SFP28 = 0x0170,
+ SFP29 = 0x0174,
+ SFP30 = 0x0178,
+ SFP31 = 0x017C,
+ SFM0 = 0x01C0,
+ SFM1 = 0x01C4,
+ TGC = 0x0300,
+ TCCR = 0x0304,
+ TSR = 0x0308,
+ TFA0 = 0x0310,
+ TFA1 = 0x0314,
+ TFA2 = 0x0318,
+ CIVR0 = 0x0320,
+ CIVR1 = 0x0324,
+ CDVR0 = 0x0328,
+ CDVR1 = 0x032C,
+ CUL0 = 0x0330,
+ CUL1 = 0x0334,
+ CLL0 = 0x0338,
+ CLL1 = 0x033C,
+ DIC = 0x0350,
+ DIS = 0x0354,
+ EIC = 0x0358,
+ EIS = 0x035C,
+ RIC0 = 0x0360,
+ RIS0 = 0x0364,
+ RIC1 = 0x0368,
+ RIS1 = 0x036C,
+ RIC2 = 0x0370,
+ RIS2 = 0x0374,
+ TIC = 0x0378,
+ TIS = 0x037C,
+ ISS = 0x0380,
+ GCCR = 0x0390,
+ GMTT = 0x0394,
+ GPTC = 0x0398,
+ GTI = 0x039C,
+ GTO0 = 0x03A0,
+ GTO1 = 0x03A4,
+ GTO2 = 0x03A8,
+ GIC = 0x03AC,
+ GIS = 0x03B0,
+ GCPT = 0x03B4, /* Undocumented? */
+ GCT0 = 0x03B8,
+ GCT1 = 0x03BC,
+ GCT2 = 0x03C0,
+
+ /* E-MAC registers */
+ ECMR = 0x0500,
+ RFLR = 0x0508,
+ ECSR = 0x0510,
+ ECSIPR = 0x0518,
+ PIR = 0x0520,
+ PSR = 0x0528,
+ PIPR = 0x052c,
+ MPR = 0x0558,
+ PFTCR = 0x055c,
+ PFRCR = 0x0560,
+ GECMR = 0x05b0,
+ MAHR = 0x05c0,
+ MALR = 0x05c8,
+ TROCR = 0x0700, /* Undocumented? */
+ CDCR = 0x0708, /* Undocumented? */
+ LCCR = 0x0710, /* Undocumented? */
+ CEFCR = 0x0740,
+ FRECR = 0x0748,
+ TSFRCR = 0x0750,
+ TLFRCR = 0x0758,
+ RFCR = 0x0760,
+ CERCR = 0x0768, /* Undocumented? */
+ CEECR = 0x0770, /* Undocumented? */
+ MAFCR = 0x0778,
+};
+
+
+/* Register bits of the Ethernet AVB */
+/* CCC */
+enum CCC_BIT {
+ CCC_OPC = 0x00000003,
+ CCC_OPC_RESET = 0x00000000,
+ CCC_OPC_CONFIG = 0x00000001,
+ CCC_OPC_OPERATION = 0x00000002,
+ CCC_DTSR = 0x00000100,
+ CCC_CSEL = 0x00030000,
+ CCC_CSEL_HPB = 0x00010000,
+ CCC_CSEL_ETH_TX = 0x00020000,
+ CCC_CSEL_GMII_REF = 0x00030000,
+ CCC_BOC = 0x00100000, /* Undocumented? */
+ CCC_LBME = 0x01000000,
+};
+
+/* CSR */
+enum CSR_BIT {
+ CSR_OPS = 0x0000000F,
+ CSR_OPS_RESET = 0x00000001,
+ CSR_OPS_CONFIG = 0x00000002,
+ CSR_OPS_OPERATION = 0x00000004,
+ CSR_OPS_STANDBY = 0x00000008, /* Undocumented? */
+ CSR_DTS = 0x00000100,
+ CSR_TPO0 = 0x00010000,
+ CSR_TPO1 = 0x00020000,
+ CSR_TPO2 = 0x00040000,
+ CSR_TPO3 = 0x00080000,
+ CSR_RPO = 0x00100000,
+};
+
+/* ESR */
+enum ESR_BIT {
+ ESR_EQN = 0x0000001F,
+ ESR_ET = 0x00000F00,
+ ESR_EIL = 0x00001000,
+};
+
+/* RCR */
+enum RCR_BIT {
+ RCR_EFFS = 0x00000001,
+ RCR_ENCF = 0x00000002,
+ RCR_ESF = 0x0000000C,
+ RCR_ETS0 = 0x00000010,
+ RCR_ETS2 = 0x00000020,
+ RCR_RFCL = 0x1FFF0000,
+};
+
+/* RQC0/1/2/3/4 */
+enum RQC_BIT {
+ RQC_RSM0 = 0x00000003,
+ RQC_UFCC0 = 0x00000030,
+ RQC_RSM1 = 0x00000300,
+ RQC_UFCC1 = 0x00003000,
+ RQC_RSM2 = 0x00030000,
+ RQC_UFCC2 = 0x00300000,
+ RQC_RSM3 = 0x03000000,
+ RQC_UFCC3 = 0x30000000,
+};
+
+/* RPC */
+enum RPC_BIT {
+ RPC_PCNT = 0x00000700,
+ RPC_DCNT = 0x00FF0000,
+};
+
+/* UFCW */
+enum UFCW_BIT {
+ UFCW_WL0 = 0x0000003F,
+ UFCW_WL1 = 0x00003F00,
+ UFCW_WL2 = 0x003F0000,
+ UFCW_WL3 = 0x3F000000,
+};
+
+/* UFCS */
+enum UFCS_BIT {
+ UFCS_SL0 = 0x0000003F,
+ UFCS_SL1 = 0x00003F00,
+ UFCS_SL2 = 0x003F0000,
+ UFCS_SL3 = 0x3F000000,
+};
+
+/* UFCV0/1/2/3/4 */
+enum UFCV_BIT {
+ UFCV_CV0 = 0x0000003F,
+ UFCV_CV1 = 0x00003F00,
+ UFCV_CV2 = 0x003F0000,
+ UFCV_CV3 = 0x3F000000,
+};
+
+/* UFCD0/1/2/3/4 */
+enum UFCD_BIT {
+ UFCD_DV0 = 0x0000003F,
+ UFCD_DV1 = 0x00003F00,
+ UFCD_DV2 = 0x003F0000,
+ UFCD_DV3 = 0x3F000000,
+};
+
+/* SFO */
+enum SFO_BIT {
+ SFO_FPB = 0x0000003F,
+};
+
+/* RTC */
+enum RTC_BIT {
+ RTC_MFL0 = 0x00000FFF,
+ RTC_MFL1 = 0x0FFF0000,
+};
+
+/* TGC */
+enum TGC_BIT {
+ TGC_TSM0 = 0x00000001,
+ TGC_TSM1 = 0x00000002,
+ TGC_TSM2 = 0x00000004,
+ TGC_TSM3 = 0x00000008,
+ TGC_TQP = 0x00000030,
+ TGC_TQP_NONAVB = 0x00000000,
+ TGC_TQP_AVBMODE1 = 0x00000010,
+ TGC_TQP_AVBMODE2 = 0x00000030,
+ TGC_TBD0 = 0x00000300,
+ TGC_TBD1 = 0x00003000,
+ TGC_TBD2 = 0x00030000,
+ TGC_TBD3 = 0x00300000,
+};
+
+/* TCCR */
+enum TCCR_BIT {
+ TCCR_TSRQ0 = 0x00000001,
+ TCCR_TSRQ1 = 0x00000002,
+ TCCR_TSRQ2 = 0x00000004,
+ TCCR_TSRQ3 = 0x00000008,
+ TCCR_TFEN = 0x00000100,
+ TCCR_TFR = 0x00000200,
+};
+
+/* TSR */
+enum TSR_BIT {
+ TSR_CCS0 = 0x00000003,
+ TSR_CCS1 = 0x0000000C,
+ TSR_TFFL = 0x00000700,
+};
+
+/* TFA2 */
+enum TFA2_BIT {
+ TFA2_TSV = 0x0000FFFF,
+ TFA2_TST = 0x03FF0000,
+};
+
+/* DIC */
+enum DIC_BIT {
+ DIC_DPE1 = 0x00000002,
+ DIC_DPE2 = 0x00000004,
+ DIC_DPE3 = 0x00000008,
+ DIC_DPE4 = 0x00000010,
+ DIC_DPE5 = 0x00000020,
+ DIC_DPE6 = 0x00000040,
+ DIC_DPE7 = 0x00000080,
+ DIC_DPE8 = 0x00000100,
+ DIC_DPE9 = 0x00000200,
+ DIC_DPE10 = 0x00000400,
+ DIC_DPE11 = 0x00000800,
+ DIC_DPE12 = 0x00001000,
+ DIC_DPE13 = 0x00002000,
+ DIC_DPE14 = 0x00004000,
+ DIC_DPE15 = 0x00008000,
+};
+
+/* DIS */
+enum DIS_BIT {
+ DIS_DPF1 = 0x00000002,
+ DIS_DPF2 = 0x00000004,
+ DIS_DPF3 = 0x00000008,
+ DIS_DPF4 = 0x00000010,
+ DIS_DPF5 = 0x00000020,
+ DIS_DPF6 = 0x00000040,
+ DIS_DPF7 = 0x00000080,
+ DIS_DPF8 = 0x00000100,
+ DIS_DPF9 = 0x00000200,
+ DIS_DPF10 = 0x00000400,
+ DIS_DPF11 = 0x00000800,
+ DIS_DPF12 = 0x00001000,
+ DIS_DPF13 = 0x00002000,
+ DIS_DPF14 = 0x00004000,
+ DIS_DPF15 = 0x00008000,
+};
+
+/* EIC */
+enum EIC_BIT {
+ EIC_MREE = 0x00000001,
+ EIC_MTEE = 0x00000002,
+ EIC_QEE = 0x00000004,
+ EIC_SEE = 0x00000008,
+ EIC_CLLE0 = 0x00000010,
+ EIC_CLLE1 = 0x00000020,
+ EIC_CULE0 = 0x00000040,
+ EIC_CULE1 = 0x00000080,
+ EIC_TFFE = 0x00000100,
+};
+
+/* EIS */
+enum EIS_BIT {
+ EIS_MREF = 0x00000001,
+ EIS_MTEF = 0x00000002,
+ EIS_QEF = 0x00000004,
+ EIS_SEF = 0x00000008,
+ EIS_CLLF0 = 0x00000010,
+ EIS_CLLF1 = 0x00000020,
+ EIS_CULF0 = 0x00000040,
+ EIS_CULF1 = 0x00000080,
+ EIS_TFFF = 0x00000100,
+ EIS_QFS = 0x00010000,
+};
+
+/* RIC0 */
+enum RIC0_BIT {
+ RIC0_FRE0 = 0x00000001,
+ RIC0_FRE1 = 0x00000002,
+ RIC0_FRE2 = 0x00000004,
+ RIC0_FRE3 = 0x00000008,
+ RIC0_FRE4 = 0x00000010,
+ RIC0_FRE5 = 0x00000020,
+ RIC0_FRE6 = 0x00000040,
+ RIC0_FRE7 = 0x00000080,
+ RIC0_FRE8 = 0x00000100,
+ RIC0_FRE9 = 0x00000200,
+ RIC0_FRE10 = 0x00000400,
+ RIC0_FRE11 = 0x00000800,
+ RIC0_FRE12 = 0x00001000,
+ RIC0_FRE13 = 0x00002000,
+ RIC0_FRE14 = 0x00004000,
+ RIC0_FRE15 = 0x00008000,
+ RIC0_FRE16 = 0x00010000,
+ RIC0_FRE17 = 0x00020000,
+};
+
+/* RIC0 */
+enum RIS0_BIT {
+ RIS0_FRF0 = 0x00000001,
+ RIS0_FRF1 = 0x00000002,
+ RIS0_FRF2 = 0x00000004,
+ RIS0_FRF3 = 0x00000008,
+ RIS0_FRF4 = 0x00000010,
+ RIS0_FRF5 = 0x00000020,
+ RIS0_FRF6 = 0x00000040,
+ RIS0_FRF7 = 0x00000080,
+ RIS0_FRF8 = 0x00000100,
+ RIS0_FRF9 = 0x00000200,
+ RIS0_FRF10 = 0x00000400,
+ RIS0_FRF11 = 0x00000800,
+ RIS0_FRF12 = 0x00001000,
+ RIS0_FRF13 = 0x00002000,
+ RIS0_FRF14 = 0x00004000,
+ RIS0_FRF15 = 0x00008000,
+ RIS0_FRF16 = 0x00010000,
+ RIS0_FRF17 = 0x00020000,
+};
+
+/* RIC1 */
+enum RIC1_BIT {
+ RIC1_RFWE = 0x80000000,
+};
+
+/* RIS1 */
+enum RIS1_BIT {
+ RIS1_RFWF = 0x80000000,
+};
+
+/* RIC2 */
+enum RIC2_BIT {
+ RIC2_QFE0 = 0x00000001,
+ RIC2_QFE1 = 0x00000002,
+ RIC2_QFE2 = 0x00000004,
+ RIC2_QFE3 = 0x00000008,
+ RIC2_QFE4 = 0x00000010,
+ RIC2_QFE5 = 0x00000020,
+ RIC2_QFE6 = 0x00000040,
+ RIC2_QFE7 = 0x00000080,
+ RIC2_QFE8 = 0x00000100,
+ RIC2_QFE9 = 0x00000200,
+ RIC2_QFE10 = 0x00000400,
+ RIC2_QFE11 = 0x00000800,
+ RIC2_QFE12 = 0x00001000,
+ RIC2_QFE13 = 0x00002000,
+ RIC2_QFE14 = 0x00004000,
+ RIC2_QFE15 = 0x00008000,
+ RIC2_QFE16 = 0x00010000,
+ RIC2_QFE17 = 0x00020000,
+ RIC2_RFFE = 0x80000000,
+};
+
+/* RIS2 */
+enum RIS2_BIT {
+ RIS2_QFF0 = 0x00000001,
+ RIS2_QFF1 = 0x00000002,
+ RIS2_QFF2 = 0x00000004,
+ RIS2_QFF3 = 0x00000008,
+ RIS2_QFF4 = 0x00000010,
+ RIS2_QFF5 = 0x00000020,
+ RIS2_QFF6 = 0x00000040,
+ RIS2_QFF7 = 0x00000080,
+ RIS2_QFF8 = 0x00000100,
+ RIS2_QFF9 = 0x00000200,
+ RIS2_QFF10 = 0x00000400,
+ RIS2_QFF11 = 0x00000800,
+ RIS2_QFF12 = 0x00001000,
+ RIS2_QFF13 = 0x00002000,
+ RIS2_QFF14 = 0x00004000,
+ RIS2_QFF15 = 0x00008000,
+ RIS2_QFF16 = 0x00010000,
+ RIS2_QFF17 = 0x00020000,
+ RIS2_RFFF = 0x80000000,
+};
+
+/* TIC */
+enum TIC_BIT {
+ TIC_FTE0 = 0x00000001, /* Undocumented? */
+ TIC_FTE1 = 0x00000002, /* Undocumented? */
+ TIC_TFUE = 0x00000100,
+ TIC_TFWE = 0x00000200,
+};
+
+/* TIS */
+enum TIS_BIT {
+ TIS_FTF0 = 0x00000001, /* Undocumented? */
+ TIS_FTF1 = 0x00000002, /* Undocumented? */
+ TIS_TFUF = 0x00000100,
+ TIS_TFWF = 0x00000200,
+};
+
+/* ISS */
+enum ISS_BIT {
+ ISS_FRS = 0x00000001, /* Undocumented? */
+ ISS_FTS = 0x00000004, /* Undocumented? */
+ ISS_ES = 0x00000040,
+ ISS_MS = 0x00000080,
+ ISS_TFUS = 0x00000100,
+ ISS_TFWS = 0x00000200,
+ ISS_RFWS = 0x00001000,
+ ISS_CGIS = 0x00002000,
+ ISS_DPS1 = 0x00020000,
+ ISS_DPS2 = 0x00040000,
+ ISS_DPS3 = 0x00080000,
+ ISS_DPS4 = 0x00100000,
+ ISS_DPS5 = 0x00200000,
+ ISS_DPS6 = 0x00400000,
+ ISS_DPS7 = 0x00800000,
+ ISS_DPS8 = 0x01000000,
+ ISS_DPS9 = 0x02000000,
+ ISS_DPS10 = 0x04000000,
+ ISS_DPS11 = 0x08000000,
+ ISS_DPS12 = 0x10000000,
+ ISS_DPS13 = 0x20000000,
+ ISS_DPS14 = 0x40000000,
+ ISS_DPS15 = 0x80000000,
+};
+
+/* GCCR */
+enum GCCR_BIT {
+ GCCR_TCR = 0x00000003,
+ GCCR_TCR_NOREQ = 0x00000000, /* No request */
+ GCCR_TCR_RESET = 0x00000001, /* gPTP/AVTP presentation timer reset */
+ GCCR_TCR_CAPTURE = 0x00000003, /* Capture value set in GCCR.TCSS */
+ GCCR_LTO = 0x00000004,
+ GCCR_LTI = 0x00000008,
+ GCCR_LPTC = 0x00000010,
+ GCCR_LMTT = 0x00000020,
+ GCCR_TCSS = 0x00000300,
+ GCCR_TCSS_GPTP = 0x00000000, /* gPTP timer value */
+ GCCR_TCSS_ADJGPTP = 0x00000100, /* Adjusted gPTP timer value */
+ GCCR_TCSS_AVTP = 0x00000200, /* AVTP presentation time value */
+};
+
+/* GTI */
+enum GTI_BIT {
+ GTI_TIV = 0x0FFFFFFF,
+};
+
+/* GIC */
+enum GIC_BIT {
+ GIC_PTCE = 0x00000001, /* Undocumented? */
+ GIC_PTME = 0x00000004,
+};
+
+/* GIS */
+enum GIS_BIT {
+ GIS_PTCF = 0x00000001, /* Undocumented? */
+ GIS_PTMF = 0x00000004,
+};
+
+/* ECMR */
+enum ECMR_BIT {
+ ECMR_PRM = 0x00000001,
+ ECMR_DM = 0x00000002,
+ ECMR_TE = 0x00000020,
+ ECMR_RE = 0x00000040,
+ ECMR_MPDE = 0x00000200,
+ ECMR_TXF = 0x00010000, /* Undocumented? */
+ ECMR_RXF = 0x00020000,
+ ECMR_PFR = 0x00040000,
+ ECMR_ZPF = 0x00080000, /* Undocumented? */
+ ECMR_RZPF = 0x00100000,
+ ECMR_DPAD = 0x00200000,
+ ECMR_RCSC = 0x00800000,
+ ECMR_TRCCM = 0x04000000,
+};
+
+/* ECSR */
+enum ECSR_BIT {
+ ECSR_ICD = 0x00000001,
+ ECSR_MPD = 0x00000002,
+ ECSR_LCHNG = 0x00000004,
+ ECSR_PHYI = 0x00000008,
+};
+
+/* ECSIPR */
+enum ECSIPR_BIT {
+ ECSIPR_ICDIP = 0x00000001,
+ ECSIPR_MPDIP = 0x00000002,
+ ECSIPR_LCHNGIP = 0x00000004, /* Undocumented? */
+};
+
+/* PIR */
+enum PIR_BIT {
+ PIR_MDC = 0x00000001,
+ PIR_MMD = 0x00000002,
+ PIR_MDO = 0x00000004,
+ PIR_MDI = 0x00000008,
+};
+
+/* PSR */
+enum PSR_BIT {
+ PSR_LMON = 0x00000001,
+};
+
+/* PIPR */
+enum PIPR_BIT {
+ PIPR_PHYIP = 0x00000001,
+};
+
+/* MPR */
+enum MPR_BIT {
+ MPR_MP = 0x0000ffff,
+};
+
+/* GECMR */
+enum GECMR_BIT {
+ GECMR_SPEED = 0x00000001,
+ GECMR_SPEED_100 = 0x00000000,
+ GECMR_SPEED_1000 = 0x00000001,
+};
+
+/* The Ethernet AVB descriptor definitions. */
+struct ravb_desc {
+ __le16 ds; /* Descriptor size */
+ u8 cc; /* Content control MSBs (reserved) */
+ u8 die_dt; /* Descriptor interrupt enable and type */
+ __le32 dptr; /* Descriptor pointer */
+};
+
+enum DIE_DT {
+ /* Frame data */
+ DT_FMID = 0x40,
+ DT_FSTART = 0x50,
+ DT_FEND = 0x60,
+ DT_FSINGLE = 0x70,
+ /* Chain control */
+ DT_LINK = 0x80,
+ DT_LINKFIX = 0x90,
+ DT_EOS = 0xa0,
+ /* HW/SW arbitration */
+ DT_FEMPTY = 0xc0,
+ DT_FEMPTY_IS = 0xd0,
+ DT_FEMPTY_IC = 0xe0,
+ DT_FEMPTY_ND = 0xf0,
+ DT_LEMPTY = 0x20,
+ DT_EEMPTY = 0x30,
+};
+
+struct ravb_rx_desc {
+ __le16 ds_cc; /* Descriptor size and content control LSBs */
+ u8 msc; /* MAC status code */
+ u8 die_dt; /* Descriptor interrupt enable and type */
+ __le32 dptr; /* Descpriptor pointer */
+};
+
+struct ravb_ex_rx_desc {
+ __le16 ds_cc; /* Descriptor size and content control lower bits */
+ u8 msc; /* MAC status code */
+ u8 die_dt; /* Descriptor interrupt enable and type */
+ __le32 dptr; /* Descpriptor pointer */
+ __le32 ts_n; /* Timestampe nsec */
+ __le32 ts_sl; /* Timestamp low */
+ __le16 ts_sh; /* Timestamp high */
+ __le16 res; /* Reserved bits */
+};
+
+enum RX_DS_CC_BIT {
+ RX_DS = 0x0fff, /* Data size */
+ RX_TR = 0x1000, /* Truncation indication */
+ RX_EI = 0x2000, /* Error indication */
+ RX_PS = 0xc000, /* Padding selection */
+};
+
+/* E-MAC status code */
+enum MSC_BIT {
+ MSC_CRC = 0x01, /* Frame CRC error */
+ MSC_RFE = 0x02, /* Frame reception error (flagged by PHY) */
+ MSC_RTSF = 0x04, /* Frame length error (frame too short) */
+ MSC_RTLF = 0x08, /* Frame length error (frame too long) */
+ MSC_FRE = 0x10, /* Fraction error (not a multiple of 8 bits) */
+ MSC_CRL = 0x20, /* Carrier lost */
+ MSC_CEEF = 0x40, /* Carrier extension error */
+ MSC_MC = 0x80, /* Multicast frame reception */
+};
+
+struct ravb_tx_desc {
+ __le16 ds_tagl; /* Descriptor size and frame tag LSBs */
+ u8 tagh_tsr; /* Frame tag MSBs and timestamp storage request bit */
+ u8 die_dt; /* Descriptor interrupt enable and type */
+ __le32 dptr; /* Descpriptor pointer */
+};
+
+enum TX_DS_TAGL_BIT {
+ TX_DS = 0x0fff, /* Data size */
+ TX_TAGL = 0xf000, /* Frame tag LSBs */
+};
+
+enum TX_TAGH_TSR_BIT {
+ TX_TAGH = 0x3f, /* Frame tag MSBs */
+ TX_TSR = 0x40, /* Timestamp storage request */
+};
+enum RAVB_QUEUE {
+ RAVB_BE = 0, /* Best Effort Queue */
+ RAVB_NC, /* Network Control Queue */
+};
+
+#define DBAT_ENTRY_NUM 22
+#define RX_QUEUE_OFFSET 4
+#define NUM_RX_QUEUE 2
+#define NUM_TX_QUEUE 2
+
+struct ravb_tstamp_skb {
+ struct list_head list;
+ struct sk_buff *skb;
+ u16 tag;
+};
+
+struct ravb_ptp_perout {
+ u32 target;
+ u32 period;
+};
+
+#define N_EXT_TS 1
+#define N_PER_OUT 1
+
+struct ravb_ptp {
+ struct ptp_clock *clock;
+ struct ptp_clock_info info;
+ u32 default_addend;
+ u32 current_addend;
+ int extts[N_EXT_TS];
+ struct ravb_ptp_perout perout[N_PER_OUT];
+};
+
+struct ravb_private {
+ struct net_device *ndev;
+ struct platform_device *pdev;
+ void __iomem *addr;
+ struct mdiobb_ctrl mdiobb;
+ u32 num_rx_ring[NUM_RX_QUEUE];
+ u32 num_tx_ring[NUM_TX_QUEUE];
+ u32 desc_bat_size;
+ dma_addr_t desc_bat_dma;
+ struct ravb_desc *desc_bat;
+ dma_addr_t rx_desc_dma[NUM_RX_QUEUE];
+ dma_addr_t tx_desc_dma[NUM_TX_QUEUE];
+ struct ravb_ex_rx_desc *rx_ring[NUM_RX_QUEUE];
+ struct ravb_tx_desc *tx_ring[NUM_TX_QUEUE];
+ struct sk_buff **rx_skb[NUM_RX_QUEUE];
+ struct sk_buff **tx_skb[NUM_TX_QUEUE];
+ void **tx_buffers[NUM_TX_QUEUE];
+ u32 rx_over_errors;
+ u32 rx_fifo_errors;
+ struct net_device_stats stats[NUM_RX_QUEUE];
+ u32 tstamp_tx_ctrl;
+ u32 tstamp_rx_ctrl;
+ struct list_head ts_skb_list;
+ u32 ts_skb_tag;
+ struct ravb_ptp ptp;
+ spinlock_t lock; /* Register access lock */
+ u32 cur_rx[NUM_RX_QUEUE]; /* Consumer ring indices */
+ u32 dirty_rx[NUM_RX_QUEUE]; /* Producer ring indices */
+ u32 cur_tx[NUM_TX_QUEUE];
+ u32 dirty_tx[NUM_TX_QUEUE];
+ struct napi_struct napi[NUM_RX_QUEUE];
+ struct work_struct work;
+ /* MII transceiver section. */
+ struct mii_bus *mii_bus; /* MDIO bus control */
+ struct phy_device *phydev; /* PHY device control */
+ int link;
+ phy_interface_t phy_interface;
+ int msg_enable;
+ int speed;
+ int duplex;
+
+ unsigned no_avb_link:1;
+ unsigned avb_link_active_low:1;
+};
+
+static inline u32 ravb_read(struct net_device *ndev, enum ravb_reg reg)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+
+ return ioread32(priv->addr + reg);
+}
+
+static inline void ravb_write(struct net_device *ndev, u32 data,
+ enum ravb_reg reg)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+
+ iowrite32(data, priv->addr + reg);
+}
+
+int ravb_wait(struct net_device *ndev, enum ravb_reg reg, u32 mask, u32 value);
+
+irqreturn_t ravb_ptp_interrupt(struct net_device *ndev);
+void ravb_ptp_init(struct net_device *ndev, struct platform_device *pdev);
+void ravb_ptp_stop(struct net_device *ndev);
+
+#endif /* #ifndef __RAVB_H__ */
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
new file mode 100644
index 000000000000..fd9745714d90
--- /dev/null
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -0,0 +1,1824 @@
+/* Renesas Ethernet AVB device driver
+ *
+ * Copyright (C) 2014-2015 Renesas Electronics Corporation
+ * Copyright (C) 2015 Renesas Solutions Corp.
+ * Copyright (C) 2015 Cogent Embedded, Inc. <source@cogentembedded.com>
+ *
+ * Based on the SuperH Ethernet driver
+ *
+ * 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.
+ */
+
+#include <linux/cache.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/net_tstamp.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "ravb.h"
+
+#define RAVB_DEF_MSG_ENABLE \
+ (NETIF_MSG_LINK | \
+ NETIF_MSG_TIMER | \
+ NETIF_MSG_RX_ERR | \
+ NETIF_MSG_TX_ERR)
+
+int ravb_wait(struct net_device *ndev, enum ravb_reg reg, u32 mask, u32 value)
+{
+ int i;
+
+ for (i = 0; i < 10000; i++) {
+ if ((ravb_read(ndev, reg) & mask) == value)
+ return 0;
+ udelay(10);
+ }
+ return -ETIMEDOUT;
+}
+
+static int ravb_config(struct net_device *ndev)
+{
+ int error;
+
+ /* Set config mode */
+ ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_OPC) | CCC_OPC_CONFIG,
+ CCC);
+ /* Check if the operating mode is changed to the config mode */
+ error = ravb_wait(ndev, CSR, CSR_OPS, CSR_OPS_CONFIG);
+ if (error)
+ netdev_err(ndev, "failed to switch device to config mode\n");
+
+ return error;
+}
+
+static void ravb_set_duplex(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ u32 ecmr = ravb_read(ndev, ECMR);
+
+ if (priv->duplex) /* Full */
+ ecmr |= ECMR_DM;
+ else /* Half */
+ ecmr &= ~ECMR_DM;
+ ravb_write(ndev, ecmr, ECMR);
+}
+
+static void ravb_set_rate(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+
+ switch (priv->speed) {
+ case 100: /* 100BASE */
+ ravb_write(ndev, GECMR_SPEED_100, GECMR);
+ break;
+ case 1000: /* 1000BASE */
+ ravb_write(ndev, GECMR_SPEED_1000, GECMR);
+ break;
+ default:
+ break;
+ }
+}
+
+static void ravb_set_buffer_align(struct sk_buff *skb)
+{
+ u32 reserve = (unsigned long)skb->data & (RAVB_ALIGN - 1);
+
+ if (reserve)
+ skb_reserve(skb, RAVB_ALIGN - reserve);
+}
+
+/* Get MAC address from the MAC address registers
+ *
+ * Ethernet AVB device doesn't have ROM for MAC address.
+ * This function gets the MAC address that was used by a bootloader.
+ */
+static void ravb_read_mac_address(struct net_device *ndev, const u8 *mac)
+{
+ if (mac) {
+ ether_addr_copy(ndev->dev_addr, mac);
+ } else {
+ ndev->dev_addr[0] = (ravb_read(ndev, MAHR) >> 24);
+ ndev->dev_addr[1] = (ravb_read(ndev, MAHR) >> 16) & 0xFF;
+ ndev->dev_addr[2] = (ravb_read(ndev, MAHR) >> 8) & 0xFF;
+ ndev->dev_addr[3] = (ravb_read(ndev, MAHR) >> 0) & 0xFF;
+ ndev->dev_addr[4] = (ravb_read(ndev, MALR) >> 8) & 0xFF;
+ ndev->dev_addr[5] = (ravb_read(ndev, MALR) >> 0) & 0xFF;
+ }
+}
+
+static void ravb_mdio_ctrl(struct mdiobb_ctrl *ctrl, u32 mask, int set)
+{
+ struct ravb_private *priv = container_of(ctrl, struct ravb_private,
+ mdiobb);
+ u32 pir = ravb_read(priv->ndev, PIR);
+
+ if (set)
+ pir |= mask;
+ else
+ pir &= ~mask;
+ ravb_write(priv->ndev, pir, PIR);
+}
+
+/* MDC pin control */
+static void ravb_set_mdc(struct mdiobb_ctrl *ctrl, int level)
+{
+ ravb_mdio_ctrl(ctrl, PIR_MDC, level);
+}
+
+/* Data I/O pin control */
+static void ravb_set_mdio_dir(struct mdiobb_ctrl *ctrl, int output)
+{
+ ravb_mdio_ctrl(ctrl, PIR_MMD, output);
+}
+
+/* Set data bit */
+static void ravb_set_mdio_data(struct mdiobb_ctrl *ctrl, int value)
+{
+ ravb_mdio_ctrl(ctrl, PIR_MDO, value);
+}
+
+/* Get data bit */
+static int ravb_get_mdio_data(struct mdiobb_ctrl *ctrl)
+{
+ struct ravb_private *priv = container_of(ctrl, struct ravb_private,
+ mdiobb);
+
+ return (ravb_read(priv->ndev, PIR) & PIR_MDI) != 0;
+}
+
+/* MDIO bus control struct */
+static struct mdiobb_ops bb_ops = {
+ .owner = THIS_MODULE,
+ .set_mdc = ravb_set_mdc,
+ .set_mdio_dir = ravb_set_mdio_dir,
+ .set_mdio_data = ravb_set_mdio_data,
+ .get_mdio_data = ravb_get_mdio_data,
+};
+
+/* Free skb's and DMA buffers for Ethernet AVB */
+static void ravb_ring_free(struct net_device *ndev, int q)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ int ring_size;
+ int i;
+
+ /* Free RX skb ringbuffer */
+ if (priv->rx_skb[q]) {
+ for (i = 0; i < priv->num_rx_ring[q]; i++)
+ dev_kfree_skb(priv->rx_skb[q][i]);
+ }
+ kfree(priv->rx_skb[q]);
+ priv->rx_skb[q] = NULL;
+
+ /* Free TX skb ringbuffer */
+ if (priv->tx_skb[q]) {
+ for (i = 0; i < priv->num_tx_ring[q]; i++)
+ dev_kfree_skb(priv->tx_skb[q][i]);
+ }
+ kfree(priv->tx_skb[q]);
+ priv->tx_skb[q] = NULL;
+
+ /* Free aligned TX buffers */
+ if (priv->tx_buffers[q]) {
+ for (i = 0; i < priv->num_tx_ring[q]; i++)
+ kfree(priv->tx_buffers[q][i]);
+ }
+ kfree(priv->tx_buffers[q]);
+ priv->tx_buffers[q] = NULL;
+
+ if (priv->rx_ring[q]) {
+ ring_size = sizeof(struct ravb_ex_rx_desc) *
+ (priv->num_rx_ring[q] + 1);
+ dma_free_coherent(NULL, ring_size, priv->rx_ring[q],
+ priv->rx_desc_dma[q]);
+ priv->rx_ring[q] = NULL;
+ }
+
+ if (priv->tx_ring[q]) {
+ ring_size = sizeof(struct ravb_tx_desc) *
+ (priv->num_tx_ring[q] + 1);
+ dma_free_coherent(NULL, ring_size, priv->tx_ring[q],
+ priv->tx_desc_dma[q]);
+ priv->tx_ring[q] = NULL;
+ }
+}
+
+/* Format skb and descriptor buffer for Ethernet AVB */
+static void ravb_ring_format(struct net_device *ndev, int q)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ struct ravb_ex_rx_desc *rx_desc = NULL;
+ struct ravb_tx_desc *tx_desc = NULL;
+ struct ravb_desc *desc = NULL;
+ int rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q];
+ int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q];
+ struct sk_buff *skb;
+ dma_addr_t dma_addr;
+ void *buffer;
+ int i;
+
+ priv->cur_rx[q] = 0;
+ priv->cur_tx[q] = 0;
+ priv->dirty_rx[q] = 0;
+ priv->dirty_tx[q] = 0;
+
+ memset(priv->rx_ring[q], 0, rx_ring_size);
+ /* Build RX ring buffer */
+ for (i = 0; i < priv->num_rx_ring[q]; i++) {
+ priv->rx_skb[q][i] = NULL;
+ skb = netdev_alloc_skb(ndev, PKT_BUF_SZ + RAVB_ALIGN - 1);
+ if (!skb)
+ break;
+ ravb_set_buffer_align(skb);
+ /* RX descriptor */
+ rx_desc = &priv->rx_ring[q][i];
+ /* The size of the buffer should be on 16-byte boundary. */
+ rx_desc->ds_cc = cpu_to_le16(ALIGN(PKT_BUF_SZ, 16));
+ dma_addr = dma_map_single(&ndev->dev, skb->data,
+ ALIGN(PKT_BUF_SZ, 16),
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&ndev->dev, dma_addr)) {
+ dev_kfree_skb(skb);
+ break;
+ }
+ priv->rx_skb[q][i] = skb;
+ rx_desc->dptr = cpu_to_le32(dma_addr);
+ rx_desc->die_dt = DT_FEMPTY;
+ }
+ rx_desc = &priv->rx_ring[q][i];
+ rx_desc->dptr = cpu_to_le32((u32)priv->rx_desc_dma[q]);
+ rx_desc->die_dt = DT_LINKFIX; /* type */
+ priv->dirty_rx[q] = (u32)(i - priv->num_rx_ring[q]);
+
+ memset(priv->tx_ring[q], 0, tx_ring_size);
+ /* Build TX ring buffer */
+ for (i = 0; i < priv->num_tx_ring[q]; i++) {
+ priv->tx_skb[q][i] = NULL;
+ priv->tx_buffers[q][i] = NULL;
+ buffer = kmalloc(PKT_BUF_SZ + RAVB_ALIGN - 1, GFP_KERNEL);
+ if (!buffer)
+ break;
+ /* Aligned TX buffer */
+ priv->tx_buffers[q][i] = buffer;
+ tx_desc = &priv->tx_ring[q][i];
+ tx_desc->die_dt = DT_EEMPTY;
+ }
+ tx_desc = &priv->tx_ring[q][i];
+ tx_desc->dptr = cpu_to_le32((u32)priv->tx_desc_dma[q]);
+ tx_desc->die_dt = DT_LINKFIX; /* type */
+
+ /* RX descriptor base address for best effort */
+ desc = &priv->desc_bat[RX_QUEUE_OFFSET + q];
+ desc->die_dt = DT_LINKFIX; /* type */
+ desc->dptr = cpu_to_le32((u32)priv->rx_desc_dma[q]);
+
+ /* TX descriptor base address for best effort */
+ desc = &priv->desc_bat[q];
+ desc->die_dt = DT_LINKFIX; /* type */
+ desc->dptr = cpu_to_le32((u32)priv->tx_desc_dma[q]);
+}
+
+/* Init skb and descriptor buffer for Ethernet AVB */
+static int ravb_ring_init(struct net_device *ndev, int q)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ int ring_size;
+
+ /* Allocate RX and TX skb rings */
+ priv->rx_skb[q] = kcalloc(priv->num_rx_ring[q],
+ sizeof(*priv->rx_skb[q]), GFP_KERNEL);
+ priv->tx_skb[q] = kcalloc(priv->num_tx_ring[q],
+ sizeof(*priv->tx_skb[q]), GFP_KERNEL);
+ if (!priv->rx_skb[q] || !priv->tx_skb[q])
+ goto error;
+
+ /* Allocate rings for the aligned buffers */
+ priv->tx_buffers[q] = kcalloc(priv->num_tx_ring[q],
+ sizeof(*priv->tx_buffers[q]), GFP_KERNEL);
+ if (!priv->tx_buffers[q])
+ goto error;
+
+ /* Allocate all RX descriptors. */
+ ring_size = sizeof(struct ravb_ex_rx_desc) * (priv->num_rx_ring[q] + 1);
+ priv->rx_ring[q] = dma_alloc_coherent(NULL, ring_size,
+ &priv->rx_desc_dma[q],
+ GFP_KERNEL);
+ if (!priv->rx_ring[q])
+ goto error;
+
+ priv->dirty_rx[q] = 0;
+
+ /* Allocate all TX descriptors. */
+ ring_size = sizeof(struct ravb_tx_desc) * (priv->num_tx_ring[q] + 1);
+ priv->tx_ring[q] = dma_alloc_coherent(NULL, ring_size,
+ &priv->tx_desc_dma[q],
+ GFP_KERNEL);
+ if (!priv->tx_ring[q])
+ goto error;
+
+ return 0;
+
+error:
+ ravb_ring_free(ndev, q);
+
+ return -ENOMEM;
+}
+
+/* E-MAC init function */
+static void ravb_emac_init(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ u32 ecmr;
+
+ /* Receive frame limit set register */
+ ravb_write(ndev, ndev->mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN, RFLR);
+
+ /* PAUSE prohibition */
+ ecmr = ravb_read(ndev, ECMR);
+ ecmr &= ECMR_DM;
+ ecmr |= ECMR_ZPF | (priv->duplex ? ECMR_DM : 0) | ECMR_TE | ECMR_RE;
+ ravb_write(ndev, ecmr, ECMR);
+
+ ravb_set_rate(ndev);
+
+ /* Set MAC address */
+ ravb_write(ndev,
+ (ndev->dev_addr[0] << 24) | (ndev->dev_addr[1] << 16) |
+ (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]), MAHR);
+ ravb_write(ndev,
+ (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]), MALR);
+
+ ravb_write(ndev, 1, MPR);
+
+ /* E-MAC status register clear */
+ ravb_write(ndev, ECSR_ICD | ECSR_MPD, ECSR);
+
+ /* E-MAC interrupt enable register */
+ ravb_write(ndev, ECSIPR_ICDIP | ECSIPR_MPDIP | ECSIPR_LCHNGIP, ECSIPR);
+}
+
+/* Device init function for Ethernet AVB */
+static int ravb_dmac_init(struct net_device *ndev)
+{
+ int error;
+
+ /* Set CONFIG mode */
+ error = ravb_config(ndev);
+ if (error)
+ return error;
+
+ error = ravb_ring_init(ndev, RAVB_BE);
+ if (error)
+ return error;
+ error = ravb_ring_init(ndev, RAVB_NC);
+ if (error) {
+ ravb_ring_free(ndev, RAVB_BE);
+ return error;
+ }
+
+ /* Descriptor format */
+ ravb_ring_format(ndev, RAVB_BE);
+ ravb_ring_format(ndev, RAVB_NC);
+
+#if defined(__LITTLE_ENDIAN)
+ ravb_write(ndev, ravb_read(ndev, CCC) & ~CCC_BOC, CCC);
+#else
+ ravb_write(ndev, ravb_read(ndev, CCC) | CCC_BOC, CCC);
+#endif
+
+ /* Set AVB RX */
+ ravb_write(ndev, RCR_EFFS | RCR_ENCF | RCR_ETS0 | 0x18000000, RCR);
+
+ /* Set FIFO size */
+ ravb_write(ndev, TGC_TQP_AVBMODE1 | 0x00222200, TGC);
+
+ /* Timestamp enable */
+ ravb_write(ndev, TCCR_TFEN, TCCR);
+
+ /* Interrupt enable: */
+ /* Frame receive */
+ ravb_write(ndev, RIC0_FRE0 | RIC0_FRE1, RIC0);
+ /* Receive FIFO full warning */
+ ravb_write(ndev, RIC1_RFWE, RIC1);
+ /* Receive FIFO full error, descriptor empty */
+ ravb_write(ndev, RIC2_QFE0 | RIC2_QFE1 | RIC2_RFFE, RIC2);
+ /* Frame transmitted, timestamp FIFO updated */
+ ravb_write(ndev, TIC_FTE0 | TIC_FTE1 | TIC_TFUE, TIC);
+
+ /* Setting the control will start the AVB-DMAC process. */
+ ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_OPC) | CCC_OPC_OPERATION,
+ CCC);
+
+ return 0;
+}
+
+/* Free TX skb function for AVB-IP */
+static int ravb_tx_free(struct net_device *ndev, int q)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &priv->stats[q];
+ struct ravb_tx_desc *desc;
+ int free_num = 0;
+ int entry = 0;
+ u32 size;
+
+ for (; priv->cur_tx[q] - priv->dirty_tx[q] > 0; priv->dirty_tx[q]++) {
+ entry = priv->dirty_tx[q] % priv->num_tx_ring[q];
+ desc = &priv->tx_ring[q][entry];
+ if (desc->die_dt != DT_FEMPTY)
+ break;
+ /* Descriptor type must be checked before all other reads */
+ dma_rmb();
+ size = le16_to_cpu(desc->ds_tagl) & TX_DS;
+ /* Free the original skb. */
+ if (priv->tx_skb[q][entry]) {
+ dma_unmap_single(&ndev->dev, le32_to_cpu(desc->dptr),
+ size, DMA_TO_DEVICE);
+ dev_kfree_skb_any(priv->tx_skb[q][entry]);
+ priv->tx_skb[q][entry] = NULL;
+ free_num++;
+ }
+ stats->tx_packets++;
+ stats->tx_bytes += size;
+ desc->die_dt = DT_EEMPTY;
+ }
+ return free_num;
+}
+
+static void ravb_get_tx_tstamp(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ struct ravb_tstamp_skb *ts_skb, *ts_skb2;
+ struct skb_shared_hwtstamps shhwtstamps;
+ struct sk_buff *skb;
+ struct timespec64 ts;
+ u16 tag, tfa_tag;
+ int count;
+ u32 tfa2;
+
+ count = (ravb_read(ndev, TSR) & TSR_TFFL) >> 8;
+ while (count--) {
+ tfa2 = ravb_read(ndev, TFA2);
+ tfa_tag = (tfa2 & TFA2_TST) >> 16;
+ ts.tv_nsec = (u64)ravb_read(ndev, TFA0);
+ ts.tv_sec = ((u64)(tfa2 & TFA2_TSV) << 32) |
+ ravb_read(ndev, TFA1);
+ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+ shhwtstamps.hwtstamp = timespec64_to_ktime(ts);
+ list_for_each_entry_safe(ts_skb, ts_skb2, &priv->ts_skb_list,
+ list) {
+ skb = ts_skb->skb;
+ tag = ts_skb->tag;
+ list_del(&ts_skb->list);
+ kfree(ts_skb);
+ if (tag == tfa_tag) {
+ skb_tstamp_tx(skb, &shhwtstamps);
+ break;
+ }
+ }
+ ravb_write(ndev, ravb_read(ndev, TCCR) | TCCR_TFR, TCCR);
+ }
+}
+
+/* Packet receive function for Ethernet AVB */
+static bool ravb_rx(struct net_device *ndev, int *quota, int q)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ int entry = priv->cur_rx[q] % priv->num_rx_ring[q];
+ int boguscnt = (priv->dirty_rx[q] + priv->num_rx_ring[q]) -
+ priv->cur_rx[q];
+ struct net_device_stats *stats = &priv->stats[q];
+ struct ravb_ex_rx_desc *desc;
+ struct sk_buff *skb;
+ dma_addr_t dma_addr;
+ struct timespec64 ts;
+ u16 pkt_len = 0;
+ u8 desc_status;
+ int limit;
+
+ boguscnt = min(boguscnt, *quota);
+ limit = boguscnt;
+ desc = &priv->rx_ring[q][entry];
+ while (desc->die_dt != DT_FEMPTY) {
+ /* Descriptor type must be checked before all other reads */
+ dma_rmb();
+ desc_status = desc->msc;
+ pkt_len = le16_to_cpu(desc->ds_cc) & RX_DS;
+
+ if (--boguscnt < 0)
+ break;
+
+ if (desc_status & MSC_MC)
+ stats->multicast++;
+
+ if (desc_status & (MSC_CRC | MSC_RFE | MSC_RTSF | MSC_RTLF |
+ MSC_CEEF)) {
+ stats->rx_errors++;
+ if (desc_status & MSC_CRC)
+ stats->rx_crc_errors++;
+ if (desc_status & MSC_RFE)
+ stats->rx_frame_errors++;
+ if (desc_status & (MSC_RTLF | MSC_RTSF))
+ stats->rx_length_errors++;
+ if (desc_status & MSC_CEEF)
+ stats->rx_missed_errors++;
+ } else {
+ u32 get_ts = priv->tstamp_rx_ctrl & RAVB_RXTSTAMP_TYPE;
+
+ skb = priv->rx_skb[q][entry];
+ priv->rx_skb[q][entry] = NULL;
+ dma_sync_single_for_cpu(&ndev->dev,
+ le32_to_cpu(desc->dptr),
+ ALIGN(PKT_BUF_SZ, 16),
+ DMA_FROM_DEVICE);
+ get_ts &= (q == RAVB_NC) ?
+ RAVB_RXTSTAMP_TYPE_V2_L2_EVENT :
+ ~RAVB_RXTSTAMP_TYPE_V2_L2_EVENT;
+ if (get_ts) {
+ struct skb_shared_hwtstamps *shhwtstamps;
+
+ shhwtstamps = skb_hwtstamps(skb);
+ memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+ ts.tv_sec = ((u64) le16_to_cpu(desc->ts_sh) <<
+ 32) | le32_to_cpu(desc->ts_sl);
+ ts.tv_nsec = le32_to_cpu(desc->ts_n);
+ shhwtstamps->hwtstamp = timespec64_to_ktime(ts);
+ }
+ skb_put(skb, pkt_len);
+ skb->protocol = eth_type_trans(skb, ndev);
+ napi_gro_receive(&priv->napi[q], skb);
+ stats->rx_packets++;
+ stats->rx_bytes += pkt_len;
+ }
+
+ entry = (++priv->cur_rx[q]) % priv->num_rx_ring[q];
+ desc = &priv->rx_ring[q][entry];
+ }
+
+ /* Refill the RX ring buffers. */
+ for (; priv->cur_rx[q] - priv->dirty_rx[q] > 0; priv->dirty_rx[q]++) {
+ entry = priv->dirty_rx[q] % priv->num_rx_ring[q];
+ desc = &priv->rx_ring[q][entry];
+ /* The size of the buffer should be on 16-byte boundary. */
+ desc->ds_cc = cpu_to_le16(ALIGN(PKT_BUF_SZ, 16));
+
+ if (!priv->rx_skb[q][entry]) {
+ skb = netdev_alloc_skb(ndev,
+ PKT_BUF_SZ + RAVB_ALIGN - 1);
+ if (!skb)
+ break; /* Better luck next round. */
+ ravb_set_buffer_align(skb);
+ dma_unmap_single(&ndev->dev, le32_to_cpu(desc->dptr),
+ ALIGN(PKT_BUF_SZ, 16),
+ DMA_FROM_DEVICE);
+ dma_addr = dma_map_single(&ndev->dev, skb->data,
+ le16_to_cpu(desc->ds_cc),
+ DMA_FROM_DEVICE);
+ skb_checksum_none_assert(skb);
+ if (dma_mapping_error(&ndev->dev, dma_addr)) {
+ dev_kfree_skb_any(skb);
+ break;
+ }
+ desc->dptr = cpu_to_le32(dma_addr);
+ priv->rx_skb[q][entry] = skb;
+ }
+ /* Descriptor type must be set after all the above writes */
+ dma_wmb();
+ desc->die_dt = DT_FEMPTY;
+ }
+
+ *quota -= limit - (++boguscnt);
+
+ return boguscnt <= 0;
+}
+
+static void ravb_rcv_snd_disable(struct net_device *ndev)
+{
+ /* Disable TX and RX */
+ ravb_write(ndev, ravb_read(ndev, ECMR) & ~(ECMR_RE | ECMR_TE), ECMR);
+}
+
+static void ravb_rcv_snd_enable(struct net_device *ndev)
+{
+ /* Enable TX and RX */
+ ravb_write(ndev, ravb_read(ndev, ECMR) | ECMR_RE | ECMR_TE, ECMR);
+}
+
+/* function for waiting dma process finished */
+static int ravb_stop_dma(struct net_device *ndev)
+{
+ int error;
+
+ /* Wait for stopping the hardware TX process */
+ error = ravb_wait(ndev, TCCR,
+ TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, 0);
+ if (error)
+ return error;
+
+ error = ravb_wait(ndev, CSR, CSR_TPO0 | CSR_TPO1 | CSR_TPO2 | CSR_TPO3,
+ 0);
+ if (error)
+ return error;
+
+ /* Stop the E-MAC's RX/TX processes. */
+ ravb_rcv_snd_disable(ndev);
+
+ /* Wait for stopping the RX DMA process */
+ error = ravb_wait(ndev, CSR, CSR_RPO, 0);
+ if (error)
+ return error;
+
+ /* Stop AVB-DMAC process */
+ return ravb_config(ndev);
+}
+
+/* E-MAC interrupt handler */
+static void ravb_emac_interrupt(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ u32 ecsr, psr;
+
+ ecsr = ravb_read(ndev, ECSR);
+ ravb_write(ndev, ecsr, ECSR); /* clear interrupt */
+ if (ecsr & ECSR_ICD)
+ ndev->stats.tx_carrier_errors++;
+ if (ecsr & ECSR_LCHNG) {
+ /* Link changed */
+ if (priv->no_avb_link)
+ return;
+ psr = ravb_read(ndev, PSR);
+ if (priv->avb_link_active_low)
+ psr ^= PSR_LMON;
+ if (!(psr & PSR_LMON)) {
+ /* DIsable RX and TX */
+ ravb_rcv_snd_disable(ndev);
+ } else {
+ /* Enable RX and TX */
+ ravb_rcv_snd_enable(ndev);
+ }
+ }
+}
+
+/* Error interrupt handler */
+static void ravb_error_interrupt(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ u32 eis, ris2;
+
+ eis = ravb_read(ndev, EIS);
+ ravb_write(ndev, ~EIS_QFS, EIS);
+ if (eis & EIS_QFS) {
+ ris2 = ravb_read(ndev, RIS2);
+ ravb_write(ndev, ~(RIS2_QFF0 | RIS2_RFFF), RIS2);
+
+ /* Receive Descriptor Empty int */
+ if (ris2 & RIS2_QFF0)
+ priv->stats[RAVB_BE].rx_over_errors++;
+
+ /* Receive Descriptor Empty int */
+ if (ris2 & RIS2_QFF1)
+ priv->stats[RAVB_NC].rx_over_errors++;
+
+ /* Receive FIFO Overflow int */
+ if (ris2 & RIS2_RFFF)
+ priv->rx_fifo_errors++;
+ }
+}
+
+static irqreturn_t ravb_interrupt(int irq, void *dev_id)
+{
+ struct net_device *ndev = dev_id;
+ struct ravb_private *priv = netdev_priv(ndev);
+ irqreturn_t result = IRQ_NONE;
+ u32 iss;
+
+ spin_lock(&priv->lock);
+ /* Get interrupt status */
+ iss = ravb_read(ndev, ISS);
+
+ /* Received and transmitted interrupts */
+ if (iss & (ISS_FRS | ISS_FTS | ISS_TFUS)) {
+ u32 ris0 = ravb_read(ndev, RIS0);
+ u32 ric0 = ravb_read(ndev, RIC0);
+ u32 tis = ravb_read(ndev, TIS);
+ u32 tic = ravb_read(ndev, TIC);
+ int q;
+
+ /* Timestamp updated */
+ if (tis & TIS_TFUF) {
+ ravb_write(ndev, ~TIS_TFUF, TIS);
+ ravb_get_tx_tstamp(ndev);
+ result = IRQ_HANDLED;
+ }
+
+ /* Network control and best effort queue RX/TX */
+ for (q = RAVB_NC; q >= RAVB_BE; q--) {
+ if (((ris0 & ric0) & BIT(q)) ||
+ ((tis & tic) & BIT(q))) {
+ if (napi_schedule_prep(&priv->napi[q])) {
+ /* Mask RX and TX interrupts */
+ ravb_write(ndev, ric0 & ~BIT(q), RIC0);
+ ravb_write(ndev, tic & ~BIT(q), TIC);
+ __napi_schedule(&priv->napi[q]);
+ } else {
+ netdev_warn(ndev,
+ "ignoring interrupt, rx status 0x%08x, rx mask 0x%08x,\n",
+ ris0, ric0);
+ netdev_warn(ndev,
+ " tx status 0x%08x, tx mask 0x%08x.\n",
+ tis, tic);
+ }
+ result = IRQ_HANDLED;
+ }
+ }
+ }
+
+ /* E-MAC status summary */
+ if (iss & ISS_MS) {
+ ravb_emac_interrupt(ndev);
+ result = IRQ_HANDLED;
+ }
+
+ /* Error status summary */
+ if (iss & ISS_ES) {
+ ravb_error_interrupt(ndev);
+ result = IRQ_HANDLED;
+ }
+
+ if (iss & ISS_CGIS)
+ result = ravb_ptp_interrupt(ndev);
+
+ mmiowb();
+ spin_unlock(&priv->lock);
+ return result;
+}
+
+static int ravb_poll(struct napi_struct *napi, int budget)
+{
+ struct net_device *ndev = napi->dev;
+ struct ravb_private *priv = netdev_priv(ndev);
+ unsigned long flags;
+ int q = napi - priv->napi;
+ int mask = BIT(q);
+ int quota = budget;
+ u32 ris0, tis;
+
+ for (;;) {
+ tis = ravb_read(ndev, TIS);
+ ris0 = ravb_read(ndev, RIS0);
+ if (!((ris0 & mask) || (tis & mask)))
+ break;
+
+ /* Processing RX Descriptor Ring */
+ if (ris0 & mask) {
+ /* Clear RX interrupt */
+ ravb_write(ndev, ~mask, RIS0);
+ if (ravb_rx(ndev, &quota, q))
+ goto out;
+ }
+ /* Processing TX Descriptor Ring */
+ if (tis & mask) {
+ spin_lock_irqsave(&priv->lock, flags);
+ /* Clear TX interrupt */
+ ravb_write(ndev, ~mask, TIS);
+ ravb_tx_free(ndev, q);
+ netif_wake_subqueue(ndev, q);
+ mmiowb();
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ }
+
+ napi_complete(napi);
+
+ /* Re-enable RX/TX interrupts */
+ spin_lock_irqsave(&priv->lock, flags);
+ ravb_write(ndev, ravb_read(ndev, RIC0) | mask, RIC0);
+ ravb_write(ndev, ravb_read(ndev, TIC) | mask, TIC);
+ mmiowb();
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Receive error message handling */
+ priv->rx_over_errors = priv->stats[RAVB_BE].rx_over_errors;
+ priv->rx_over_errors += priv->stats[RAVB_NC].rx_over_errors;
+ if (priv->rx_over_errors != ndev->stats.rx_over_errors) {
+ ndev->stats.rx_over_errors = priv->rx_over_errors;
+ netif_err(priv, rx_err, ndev, "Receive Descriptor Empty\n");
+ }
+ if (priv->rx_fifo_errors != ndev->stats.rx_fifo_errors) {
+ ndev->stats.rx_fifo_errors = priv->rx_fifo_errors;
+ netif_err(priv, rx_err, ndev, "Receive FIFO Overflow\n");
+ }
+out:
+ return budget - quota;
+}
+
+/* PHY state control function */
+static void ravb_adjust_link(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ struct phy_device *phydev = priv->phydev;
+ bool new_state = false;
+
+ if (phydev->link) {
+ if (phydev->duplex != priv->duplex) {
+ new_state = true;
+ priv->duplex = phydev->duplex;
+ ravb_set_duplex(ndev);
+ }
+
+ if (phydev->speed != priv->speed) {
+ new_state = true;
+ priv->speed = phydev->speed;
+ ravb_set_rate(ndev);
+ }
+ if (!priv->link) {
+ ravb_write(ndev, ravb_read(ndev, ECMR) & ~ECMR_TXF,
+ ECMR);
+ new_state = true;
+ priv->link = phydev->link;
+ if (priv->no_avb_link)
+ ravb_rcv_snd_enable(ndev);
+ }
+ } else if (priv->link) {
+ new_state = true;
+ priv->link = 0;
+ priv->speed = 0;
+ priv->duplex = -1;
+ if (priv->no_avb_link)
+ ravb_rcv_snd_disable(ndev);
+ }
+
+ if (new_state && netif_msg_link(priv))
+ phy_print_status(phydev);
+}
+
+/* PHY init function */
+static int ravb_phy_init(struct net_device *ndev)
+{
+ struct device_node *np = ndev->dev.parent->of_node;
+ struct ravb_private *priv = netdev_priv(ndev);
+ struct phy_device *phydev;
+ struct device_node *pn;
+
+ priv->link = 0;
+ priv->speed = 0;
+ priv->duplex = -1;
+
+ /* Try connecting to PHY */
+ pn = of_parse_phandle(np, "phy-handle", 0);
+ phydev = of_phy_connect(ndev, pn, ravb_adjust_link, 0,
+ priv->phy_interface);
+ if (!phydev) {
+ netdev_err(ndev, "failed to connect PHY\n");
+ return -ENOENT;
+ }
+
+ netdev_info(ndev, "attached PHY %d (IRQ %d) to driver %s\n",
+ phydev->addr, phydev->irq, phydev->drv->name);
+
+ priv->phydev = phydev;
+
+ return 0;
+}
+
+/* PHY control start function */
+static int ravb_phy_start(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ int error;
+
+ error = ravb_phy_init(ndev);
+ if (error)
+ return error;
+
+ phy_start(priv->phydev);
+
+ return 0;
+}
+
+static int ravb_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ int error = -ENODEV;
+ unsigned long flags;
+
+ if (priv->phydev) {
+ spin_lock_irqsave(&priv->lock, flags);
+ error = phy_ethtool_gset(priv->phydev, ecmd);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ return error;
+}
+
+static int ravb_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ unsigned long flags;
+ int error;
+
+ if (!priv->phydev)
+ return -ENODEV;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Disable TX and RX */
+ ravb_rcv_snd_disable(ndev);
+
+ error = phy_ethtool_sset(priv->phydev, ecmd);
+ if (error)
+ goto error_exit;
+
+ if (ecmd->duplex == DUPLEX_FULL)
+ priv->duplex = 1;
+ else
+ priv->duplex = 0;
+
+ ravb_set_duplex(ndev);
+
+error_exit:
+ mdelay(1);
+
+ /* Enable TX and RX */
+ ravb_rcv_snd_enable(ndev);
+
+ mmiowb();
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return error;
+}
+
+static int ravb_nway_reset(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ int error = -ENODEV;
+ unsigned long flags;
+
+ if (priv->phydev) {
+ spin_lock_irqsave(&priv->lock, flags);
+ error = phy_start_aneg(priv->phydev);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ return error;
+}
+
+static u32 ravb_get_msglevel(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+
+ return priv->msg_enable;
+}
+
+static void ravb_set_msglevel(struct net_device *ndev, u32 value)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+
+ priv->msg_enable = value;
+}
+
+static const char ravb_gstrings_stats[][ETH_GSTRING_LEN] = {
+ "rx_queue_0_current",
+ "tx_queue_0_current",
+ "rx_queue_0_dirty",
+ "tx_queue_0_dirty",
+ "rx_queue_0_packets",
+ "tx_queue_0_packets",
+ "rx_queue_0_bytes",
+ "tx_queue_0_bytes",
+ "rx_queue_0_mcast_packets",
+ "rx_queue_0_errors",
+ "rx_queue_0_crc_errors",
+ "rx_queue_0_frame_errors",
+ "rx_queue_0_length_errors",
+ "rx_queue_0_missed_errors",
+ "rx_queue_0_over_errors",
+
+ "rx_queue_1_current",
+ "tx_queue_1_current",
+ "rx_queue_1_dirty",
+ "tx_queue_1_dirty",
+ "rx_queue_1_packets",
+ "tx_queue_1_packets",
+ "rx_queue_1_bytes",
+ "tx_queue_1_bytes",
+ "rx_queue_1_mcast_packets",
+ "rx_queue_1_errors",
+ "rx_queue_1_crc_errors",
+ "rx_queue_1_frame_errors_",
+ "rx_queue_1_length_errors",
+ "rx_queue_1_missed_errors",
+ "rx_queue_1_over_errors",
+};
+
+#define RAVB_STATS_LEN ARRAY_SIZE(ravb_gstrings_stats)
+
+static int ravb_get_sset_count(struct net_device *netdev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return RAVB_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void ravb_get_ethtool_stats(struct net_device *ndev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ int i = 0;
+ int q;
+
+ /* Device-specific stats */
+ for (q = RAVB_BE; q < NUM_RX_QUEUE; q++) {
+ struct net_device_stats *stats = &priv->stats[q];
+
+ data[i++] = priv->cur_rx[q];
+ data[i++] = priv->cur_tx[q];
+ data[i++] = priv->dirty_rx[q];
+ data[i++] = priv->dirty_tx[q];
+ data[i++] = stats->rx_packets;
+ data[i++] = stats->tx_packets;
+ data[i++] = stats->rx_bytes;
+ data[i++] = stats->tx_bytes;
+ data[i++] = stats->multicast;
+ data[i++] = stats->rx_errors;
+ data[i++] = stats->rx_crc_errors;
+ data[i++] = stats->rx_frame_errors;
+ data[i++] = stats->rx_length_errors;
+ data[i++] = stats->rx_missed_errors;
+ data[i++] = stats->rx_over_errors;
+ }
+}
+
+static void ravb_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
+{
+ switch (stringset) {
+ case ETH_SS_STATS:
+ memcpy(data, *ravb_gstrings_stats, sizeof(ravb_gstrings_stats));
+ break;
+ }
+}
+
+static void ravb_get_ringparam(struct net_device *ndev,
+ struct ethtool_ringparam *ring)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+
+ ring->rx_max_pending = BE_RX_RING_MAX;
+ ring->tx_max_pending = BE_TX_RING_MAX;
+ ring->rx_pending = priv->num_rx_ring[RAVB_BE];
+ ring->tx_pending = priv->num_tx_ring[RAVB_BE];
+}
+
+static int ravb_set_ringparam(struct net_device *ndev,
+ struct ethtool_ringparam *ring)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ int error;
+
+ if (ring->tx_pending > BE_TX_RING_MAX ||
+ ring->rx_pending > BE_RX_RING_MAX ||
+ ring->tx_pending < BE_TX_RING_MIN ||
+ ring->rx_pending < BE_RX_RING_MIN)
+ return -EINVAL;
+ if (ring->rx_mini_pending || ring->rx_jumbo_pending)
+ return -EINVAL;
+
+ if (netif_running(ndev)) {
+ netif_device_detach(ndev);
+ /* Stop PTP Clock driver */
+ ravb_ptp_stop(ndev);
+ /* Wait for DMA stopping */
+ error = ravb_stop_dma(ndev);
+ if (error) {
+ netdev_err(ndev,
+ "cannot set ringparam! Any AVB processes are still running?\n");
+ return error;
+ }
+ synchronize_irq(ndev->irq);
+
+ /* Free all the skb's in the RX queue and the DMA buffers. */
+ ravb_ring_free(ndev, RAVB_BE);
+ ravb_ring_free(ndev, RAVB_NC);
+ }
+
+ /* Set new parameters */
+ priv->num_rx_ring[RAVB_BE] = ring->rx_pending;
+ priv->num_tx_ring[RAVB_BE] = ring->tx_pending;
+
+ if (netif_running(ndev)) {
+ error = ravb_dmac_init(ndev);
+ if (error) {
+ netdev_err(ndev,
+ "%s: ravb_dmac_init() failed, error %d\n",
+ __func__, error);
+ return error;
+ }
+
+ ravb_emac_init(ndev);
+
+ /* Initialise PTP Clock driver */
+ ravb_ptp_init(ndev, priv->pdev);
+
+ netif_device_attach(ndev);
+ }
+
+ return 0;
+}
+
+static int ravb_get_ts_info(struct net_device *ndev,
+ struct ethtool_ts_info *info)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+
+ info->so_timestamping =
+ SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE |
+ SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+ info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
+ info->rx_filters =
+ (1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+ (1 << HWTSTAMP_FILTER_ALL);
+ info->phc_index = ptp_clock_index(priv->ptp.clock);
+
+ return 0;
+}
+
+static const struct ethtool_ops ravb_ethtool_ops = {
+ .get_settings = ravb_get_settings,
+ .set_settings = ravb_set_settings,
+ .nway_reset = ravb_nway_reset,
+ .get_msglevel = ravb_get_msglevel,
+ .set_msglevel = ravb_set_msglevel,
+ .get_link = ethtool_op_get_link,
+ .get_strings = ravb_get_strings,
+ .get_ethtool_stats = ravb_get_ethtool_stats,
+ .get_sset_count = ravb_get_sset_count,
+ .get_ringparam = ravb_get_ringparam,
+ .set_ringparam = ravb_set_ringparam,
+ .get_ts_info = ravb_get_ts_info,
+};
+
+/* Network device open function for Ethernet AVB */
+static int ravb_open(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ int error;
+
+ napi_enable(&priv->napi[RAVB_BE]);
+ napi_enable(&priv->napi[RAVB_NC]);
+
+ error = request_irq(ndev->irq, ravb_interrupt, IRQF_SHARED, ndev->name,
+ ndev);
+ if (error) {
+ netdev_err(ndev, "cannot request IRQ\n");
+ goto out_napi_off;
+ }
+
+ /* Device init */
+ error = ravb_dmac_init(ndev);
+ if (error)
+ goto out_free_irq;
+ ravb_emac_init(ndev);
+
+ /* Initialise PTP Clock driver */
+ ravb_ptp_init(ndev, priv->pdev);
+
+ netif_tx_start_all_queues(ndev);
+
+ /* PHY control start */
+ error = ravb_phy_start(ndev);
+ if (error)
+ goto out_ptp_stop;
+
+ return 0;
+
+out_ptp_stop:
+ /* Stop PTP Clock driver */
+ ravb_ptp_stop(ndev);
+out_free_irq:
+ free_irq(ndev->irq, ndev);
+out_napi_off:
+ napi_disable(&priv->napi[RAVB_NC]);
+ napi_disable(&priv->napi[RAVB_BE]);
+ return error;
+}
+
+/* Timeout function for Ethernet AVB */
+static void ravb_tx_timeout(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+
+ netif_err(priv, tx_err, ndev,
+ "transmit timed out, status %08x, resetting...\n",
+ ravb_read(ndev, ISS));
+
+ /* tx_errors count up */
+ ndev->stats.tx_errors++;
+
+ schedule_work(&priv->work);
+}
+
+static void ravb_tx_timeout_work(struct work_struct *work)
+{
+ struct ravb_private *priv = container_of(work, struct ravb_private,
+ work);
+ struct net_device *ndev = priv->ndev;
+
+ netif_tx_stop_all_queues(ndev);
+
+ /* Stop PTP Clock driver */
+ ravb_ptp_stop(ndev);
+
+ /* Wait for DMA stopping */
+ ravb_stop_dma(ndev);
+
+ ravb_ring_free(ndev, RAVB_BE);
+ ravb_ring_free(ndev, RAVB_NC);
+
+ /* Device init */
+ ravb_dmac_init(ndev);
+ ravb_emac_init(ndev);
+
+ /* Initialise PTP Clock driver */
+ ravb_ptp_init(ndev, priv->pdev);
+
+ netif_tx_start_all_queues(ndev);
+}
+
+/* Packet transmit function for Ethernet AVB */
+static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ struct ravb_tstamp_skb *ts_skb = NULL;
+ u16 q = skb_get_queue_mapping(skb);
+ struct ravb_tx_desc *desc;
+ unsigned long flags;
+ u32 dma_addr;
+ void *buffer;
+ u32 entry;
+ u32 tccr;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->cur_tx[q] - priv->dirty_tx[q] >= priv->num_tx_ring[q]) {
+ netif_err(priv, tx_queued, ndev,
+ "still transmitting with the full ring!\n");
+ netif_stop_subqueue(ndev, q);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+ entry = priv->cur_tx[q] % priv->num_tx_ring[q];
+ priv->tx_skb[q][entry] = skb;
+
+ if (skb_put_padto(skb, ETH_ZLEN))
+ goto drop;
+
+ buffer = PTR_ALIGN(priv->tx_buffers[q][entry], RAVB_ALIGN);
+ memcpy(buffer, skb->data, skb->len);
+ desc = &priv->tx_ring[q][entry];
+ desc->ds_tagl = cpu_to_le16(skb->len);
+ dma_addr = dma_map_single(&ndev->dev, buffer, skb->len, DMA_TO_DEVICE);
+ if (dma_mapping_error(&ndev->dev, dma_addr))
+ goto drop;
+ desc->dptr = cpu_to_le32(dma_addr);
+
+ /* TX timestamp required */
+ if (q == RAVB_NC) {
+ ts_skb = kmalloc(sizeof(*ts_skb), GFP_ATOMIC);
+ if (!ts_skb) {
+ dma_unmap_single(&ndev->dev, dma_addr, skb->len,
+ DMA_TO_DEVICE);
+ goto drop;
+ }
+ ts_skb->skb = skb;
+ ts_skb->tag = priv->ts_skb_tag++;
+ priv->ts_skb_tag &= 0x3ff;
+ list_add_tail(&ts_skb->list, &priv->ts_skb_list);
+
+ /* TAG and timestamp required flag */
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ skb_tx_timestamp(skb);
+ desc->tagh_tsr = (ts_skb->tag >> 4) | TX_TSR;
+ desc->ds_tagl |= le16_to_cpu(ts_skb->tag << 12);
+ }
+
+ /* Descriptor type must be set after all the above writes */
+ dma_wmb();
+ desc->die_dt = DT_FSINGLE;
+
+ tccr = ravb_read(ndev, TCCR);
+ if (!(tccr & (TCCR_TSRQ0 << q)))
+ ravb_write(ndev, tccr | (TCCR_TSRQ0 << q), TCCR);
+
+ priv->cur_tx[q]++;
+ if (priv->cur_tx[q] - priv->dirty_tx[q] >= priv->num_tx_ring[q] &&
+ !ravb_tx_free(ndev, q))
+ netif_stop_subqueue(ndev, q);
+
+exit:
+ mmiowb();
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return NETDEV_TX_OK;
+
+drop:
+ dev_kfree_skb_any(skb);
+ priv->tx_skb[q][entry] = NULL;
+ goto exit;
+}
+
+static u16 ravb_select_queue(struct net_device *ndev, struct sk_buff *skb,
+ void *accel_priv, select_queue_fallback_t fallback)
+{
+ /* If skb needs TX timestamp, it is handled in network control queue */
+ return (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) ? RAVB_NC :
+ RAVB_BE;
+
+}
+
+static struct net_device_stats *ravb_get_stats(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ struct net_device_stats *nstats, *stats0, *stats1;
+
+ nstats = &ndev->stats;
+ stats0 = &priv->stats[RAVB_BE];
+ stats1 = &priv->stats[RAVB_NC];
+
+ nstats->tx_dropped += ravb_read(ndev, TROCR);
+ ravb_write(ndev, 0, TROCR); /* (write clear) */
+ nstats->collisions += ravb_read(ndev, CDCR);
+ ravb_write(ndev, 0, CDCR); /* (write clear) */
+ nstats->tx_carrier_errors += ravb_read(ndev, LCCR);
+ ravb_write(ndev, 0, LCCR); /* (write clear) */
+
+ nstats->tx_carrier_errors += ravb_read(ndev, CERCR);
+ ravb_write(ndev, 0, CERCR); /* (write clear) */
+ nstats->tx_carrier_errors += ravb_read(ndev, CEECR);
+ ravb_write(ndev, 0, CEECR); /* (write clear) */
+
+ nstats->rx_packets = stats0->rx_packets + stats1->rx_packets;
+ nstats->tx_packets = stats0->tx_packets + stats1->tx_packets;
+ nstats->rx_bytes = stats0->rx_bytes + stats1->rx_bytes;
+ nstats->tx_bytes = stats0->tx_bytes + stats1->tx_bytes;
+ nstats->multicast = stats0->multicast + stats1->multicast;
+ nstats->rx_errors = stats0->rx_errors + stats1->rx_errors;
+ nstats->rx_crc_errors = stats0->rx_crc_errors + stats1->rx_crc_errors;
+ nstats->rx_frame_errors =
+ stats0->rx_frame_errors + stats1->rx_frame_errors;
+ nstats->rx_length_errors =
+ stats0->rx_length_errors + stats1->rx_length_errors;
+ nstats->rx_missed_errors =
+ stats0->rx_missed_errors + stats1->rx_missed_errors;
+ nstats->rx_over_errors =
+ stats0->rx_over_errors + stats1->rx_over_errors;
+
+ return nstats;
+}
+
+/* Update promiscuous bit */
+static void ravb_set_rx_mode(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ unsigned long flags;
+ u32 ecmr;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ecmr = ravb_read(ndev, ECMR);
+ if (ndev->flags & IFF_PROMISC)
+ ecmr |= ECMR_PRM;
+ else
+ ecmr &= ~ECMR_PRM;
+ ravb_write(ndev, ecmr, ECMR);
+ mmiowb();
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+/* Device close function for Ethernet AVB */
+static int ravb_close(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ struct ravb_tstamp_skb *ts_skb, *ts_skb2;
+
+ netif_tx_stop_all_queues(ndev);
+
+ /* Disable interrupts by clearing the interrupt masks. */
+ ravb_write(ndev, 0, RIC0);
+ ravb_write(ndev, 0, RIC1);
+ ravb_write(ndev, 0, RIC2);
+ ravb_write(ndev, 0, TIC);
+
+ /* Stop PTP Clock driver */
+ ravb_ptp_stop(ndev);
+
+ /* Set the config mode to stop the AVB-DMAC's processes */
+ if (ravb_stop_dma(ndev) < 0)
+ netdev_err(ndev,
+ "device will be stopped after h/w processes are done.\n");
+
+ /* Clear the timestamp list */
+ list_for_each_entry_safe(ts_skb, ts_skb2, &priv->ts_skb_list, list) {
+ list_del(&ts_skb->list);
+ kfree(ts_skb);
+ }
+
+ /* PHY disconnect */
+ if (priv->phydev) {
+ phy_stop(priv->phydev);
+ phy_disconnect(priv->phydev);
+ priv->phydev = NULL;
+ }
+
+ free_irq(ndev->irq, ndev);
+
+ napi_disable(&priv->napi[RAVB_NC]);
+ napi_disable(&priv->napi[RAVB_BE]);
+
+ /* Free all the skb's in the RX queue and the DMA buffers. */
+ ravb_ring_free(ndev, RAVB_BE);
+ ravb_ring_free(ndev, RAVB_NC);
+
+ return 0;
+}
+
+static int ravb_hwtstamp_get(struct net_device *ndev, struct ifreq *req)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ struct hwtstamp_config config;
+
+ config.flags = 0;
+ config.tx_type = priv->tstamp_tx_ctrl ? HWTSTAMP_TX_ON :
+ HWTSTAMP_TX_OFF;
+ if (priv->tstamp_rx_ctrl & RAVB_RXTSTAMP_TYPE_V2_L2_EVENT)
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
+ else if (priv->tstamp_rx_ctrl & RAVB_RXTSTAMP_TYPE_ALL)
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
+ else
+ config.rx_filter = HWTSTAMP_FILTER_NONE;
+
+ return copy_to_user(req->ifr_data, &config, sizeof(config)) ?
+ -EFAULT : 0;
+}
+
+/* Control hardware time stamping */
+static int ravb_hwtstamp_set(struct net_device *ndev, struct ifreq *req)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ struct hwtstamp_config config;
+ u32 tstamp_rx_ctrl = RAVB_RXTSTAMP_ENABLED;
+ u32 tstamp_tx_ctrl;
+
+ if (copy_from_user(&config, req->ifr_data, sizeof(config)))
+ return -EFAULT;
+
+ /* Reserved for future extensions */
+ if (config.flags)
+ return -EINVAL;
+
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ tstamp_tx_ctrl = 0;
+ break;
+ case HWTSTAMP_TX_ON:
+ tstamp_tx_ctrl = RAVB_TXTSTAMP_ENABLED;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ tstamp_rx_ctrl = 0;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ tstamp_rx_ctrl |= RAVB_RXTSTAMP_TYPE_V2_L2_EVENT;
+ break;
+ default:
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
+ tstamp_rx_ctrl |= RAVB_RXTSTAMP_TYPE_ALL;
+ }
+
+ priv->tstamp_tx_ctrl = tstamp_tx_ctrl;
+ priv->tstamp_rx_ctrl = tstamp_rx_ctrl;
+
+ return copy_to_user(req->ifr_data, &config, sizeof(config)) ?
+ -EFAULT : 0;
+}
+
+/* ioctl to device function */
+static int ravb_do_ioctl(struct net_device *ndev, struct ifreq *req, int cmd)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ struct phy_device *phydev = priv->phydev;
+
+ if (!netif_running(ndev))
+ return -EINVAL;
+
+ if (!phydev)
+ return -ENODEV;
+
+ switch (cmd) {
+ case SIOCGHWTSTAMP:
+ return ravb_hwtstamp_get(ndev, req);
+ case SIOCSHWTSTAMP:
+ return ravb_hwtstamp_set(ndev, req);
+ }
+
+ return phy_mii_ioctl(phydev, req, cmd);
+}
+
+static const struct net_device_ops ravb_netdev_ops = {
+ .ndo_open = ravb_open,
+ .ndo_stop = ravb_close,
+ .ndo_start_xmit = ravb_start_xmit,
+ .ndo_select_queue = ravb_select_queue,
+ .ndo_get_stats = ravb_get_stats,
+ .ndo_set_rx_mode = ravb_set_rx_mode,
+ .ndo_tx_timeout = ravb_tx_timeout,
+ .ndo_do_ioctl = ravb_do_ioctl,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_change_mtu = eth_change_mtu,
+};
+
+/* MDIO bus init function */
+static int ravb_mdio_init(struct ravb_private *priv)
+{
+ struct platform_device *pdev = priv->pdev;
+ struct device *dev = &pdev->dev;
+ int error;
+
+ /* Bitbang init */
+ priv->mdiobb.ops = &bb_ops;
+
+ /* MII controller setting */
+ priv->mii_bus = alloc_mdio_bitbang(&priv->mdiobb);
+ if (!priv->mii_bus)
+ return -ENOMEM;
+
+ /* Hook up MII support for ethtool */
+ priv->mii_bus->name = "ravb_mii";
+ priv->mii_bus->parent = dev;
+ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+ pdev->name, pdev->id);
+
+ /* Register MDIO bus */
+ error = of_mdiobus_register(priv->mii_bus, dev->of_node);
+ if (error)
+ goto out_free_bus;
+
+ return 0;
+
+out_free_bus:
+ free_mdio_bitbang(priv->mii_bus);
+ return error;
+}
+
+/* MDIO bus release function */
+static int ravb_mdio_release(struct ravb_private *priv)
+{
+ /* Unregister mdio bus */
+ mdiobus_unregister(priv->mii_bus);
+
+ /* Free bitbang info */
+ free_mdio_bitbang(priv->mii_bus);
+
+ return 0;
+}
+
+static int ravb_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct ravb_private *priv;
+ struct net_device *ndev;
+ int error, irq, q;
+ struct resource *res;
+
+ if (!np) {
+ dev_err(&pdev->dev,
+ "this driver is required to be instantiated from device tree\n");
+ return -EINVAL;
+ }
+
+ /* Get base address */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "invalid resource\n");
+ return -EINVAL;
+ }
+
+ ndev = alloc_etherdev_mqs(sizeof(struct ravb_private),
+ NUM_TX_QUEUE, NUM_RX_QUEUE);
+ if (!ndev)
+ return -ENOMEM;
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
+ /* The Ether-specific entries in the device structure. */
+ ndev->base_addr = res->start;
+ ndev->dma = -1;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ error = -ENODEV;
+ goto out_release;
+ }
+ ndev->irq = irq;
+
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ priv = netdev_priv(ndev);
+ priv->ndev = ndev;
+ priv->pdev = pdev;
+ priv->num_tx_ring[RAVB_BE] = BE_TX_RING_SIZE;
+ priv->num_rx_ring[RAVB_BE] = BE_RX_RING_SIZE;
+ priv->num_tx_ring[RAVB_NC] = NC_TX_RING_SIZE;
+ priv->num_rx_ring[RAVB_NC] = NC_RX_RING_SIZE;
+ priv->addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->addr)) {
+ error = PTR_ERR(priv->addr);
+ goto out_release;
+ }
+
+ spin_lock_init(&priv->lock);
+ INIT_WORK(&priv->work, ravb_tx_timeout_work);
+
+ priv->phy_interface = of_get_phy_mode(np);
+
+ priv->no_avb_link = of_property_read_bool(np, "renesas,no-ether-link");
+ priv->avb_link_active_low =
+ of_property_read_bool(np, "renesas,ether-link-active-low");
+
+ /* Set function */
+ ndev->netdev_ops = &ravb_netdev_ops;
+ ndev->ethtool_ops = &ravb_ethtool_ops;
+
+ /* Set AVB config mode */
+ ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_OPC) | CCC_OPC_CONFIG,
+ CCC);
+
+ /* Set CSEL value */
+ ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_CSEL) | CCC_CSEL_HPB,
+ CCC);
+
+ /* Set GTI value */
+ ravb_write(ndev, ((1000 << 20) / 130) & GTI_TIV, GTI);
+
+ /* Request GTI loading */
+ ravb_write(ndev, ravb_read(ndev, GCCR) | GCCR_LTI, GCCR);
+
+ /* Allocate descriptor base address table */
+ priv->desc_bat_size = sizeof(struct ravb_desc) * DBAT_ENTRY_NUM;
+ priv->desc_bat = dma_alloc_coherent(NULL, priv->desc_bat_size,
+ &priv->desc_bat_dma, GFP_KERNEL);
+ if (!priv->desc_bat) {
+ dev_err(&ndev->dev,
+ "Cannot allocate desc base address table (size %d bytes)\n",
+ priv->desc_bat_size);
+ error = -ENOMEM;
+ goto out_release;
+ }
+ for (q = RAVB_BE; q < DBAT_ENTRY_NUM; q++)
+ priv->desc_bat[q].die_dt = DT_EOS;
+ ravb_write(ndev, priv->desc_bat_dma, DBAT);
+
+ /* Initialise HW timestamp list */
+ INIT_LIST_HEAD(&priv->ts_skb_list);
+
+ /* Debug message level */
+ priv->msg_enable = RAVB_DEF_MSG_ENABLE;
+
+ /* Read and set MAC address */
+ ravb_read_mac_address(ndev, of_get_mac_address(np));
+ if (!is_valid_ether_addr(ndev->dev_addr)) {
+ dev_warn(&pdev->dev,
+ "no valid MAC address supplied, using a random one\n");
+ eth_hw_addr_random(ndev);
+ }
+
+ /* MDIO bus init */
+ error = ravb_mdio_init(priv);
+ if (error) {
+ dev_err(&ndev->dev, "failed to initialize MDIO\n");
+ goto out_dma_free;
+ }
+
+ netif_napi_add(ndev, &priv->napi[RAVB_BE], ravb_poll, 64);
+ netif_napi_add(ndev, &priv->napi[RAVB_NC], ravb_poll, 64);
+
+ /* Network device register */
+ error = register_netdev(ndev);
+ if (error)
+ goto out_napi_del;
+
+ /* Print device information */
+ netdev_info(ndev, "Base address at %#x, %pM, IRQ %d.\n",
+ (u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
+
+ platform_set_drvdata(pdev, ndev);
+
+ return 0;
+
+out_napi_del:
+ netif_napi_del(&priv->napi[RAVB_NC]);
+ netif_napi_del(&priv->napi[RAVB_BE]);
+ ravb_mdio_release(priv);
+out_dma_free:
+ dma_free_coherent(NULL, priv->desc_bat_size, priv->desc_bat,
+ priv->desc_bat_dma);
+out_release:
+ if (ndev)
+ free_netdev(ndev);
+
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ return error;
+}
+
+static int ravb_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct ravb_private *priv = netdev_priv(ndev);
+
+ dma_free_coherent(NULL, priv->desc_bat_size, priv->desc_bat,
+ priv->desc_bat_dma);
+ /* Set reset mode */
+ ravb_write(ndev, CCC_OPC_RESET, CCC);
+ pm_runtime_put_sync(&pdev->dev);
+ unregister_netdev(ndev);
+ netif_napi_del(&priv->napi[RAVB_NC]);
+ netif_napi_del(&priv->napi[RAVB_BE]);
+ ravb_mdio_release(priv);
+ pm_runtime_disable(&pdev->dev);
+ free_netdev(ndev);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ravb_runtime_nop(struct device *dev)
+{
+ /* Runtime PM callback shared between ->runtime_suspend()
+ * and ->runtime_resume(). Simply returns success.
+ *
+ * This driver re-initializes all registers after
+ * pm_runtime_get_sync() anyway so there is no need
+ * to save and restore registers here.
+ */
+ return 0;
+}
+
+static const struct dev_pm_ops ravb_dev_pm_ops = {
+ .runtime_suspend = ravb_runtime_nop,
+ .runtime_resume = ravb_runtime_nop,
+};
+
+#define RAVB_PM_OPS (&ravb_dev_pm_ops)
+#else
+#define RAVB_PM_OPS NULL
+#endif
+
+static const struct of_device_id ravb_match_table[] = {
+ { .compatible = "renesas,etheravb-r8a7790" },
+ { .compatible = "renesas,etheravb-r8a7794" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ravb_match_table);
+
+static struct platform_driver ravb_driver = {
+ .probe = ravb_probe,
+ .remove = ravb_remove,
+ .driver = {
+ .name = "ravb",
+ .pm = RAVB_PM_OPS,
+ .of_match_table = ravb_match_table,
+ },
+};
+
+module_platform_driver(ravb_driver);
+
+MODULE_AUTHOR("Mitsuhiro Kimura, Masaru Nagai");
+MODULE_DESCRIPTION("Renesas Ethernet AVB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/renesas/ravb_ptp.c b/drivers/net/ethernet/renesas/ravb_ptp.c
new file mode 100644
index 000000000000..42656da50500
--- /dev/null
+++ b/drivers/net/ethernet/renesas/ravb_ptp.c
@@ -0,0 +1,357 @@
+/* PTP 1588 clock using the Renesas Ethernet AVB
+ *
+ * Copyright (C) 2013-2015 Renesas Electronics Corporation
+ * Copyright (C) 2015 Renesas Solutions Corp.
+ * Copyright (C) 2015 Cogent Embedded, Inc. <source@cogentembedded.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "ravb.h"
+
+static int ravb_ptp_tcr_request(struct ravb_private *priv, u32 request)
+{
+ struct net_device *ndev = priv->ndev;
+ int error;
+
+ error = ravb_wait(ndev, GCCR, GCCR_TCR, GCCR_TCR_NOREQ);
+ if (error)
+ return error;
+
+ ravb_write(ndev, ravb_read(ndev, GCCR) | request, GCCR);
+ return ravb_wait(ndev, GCCR, GCCR_TCR, GCCR_TCR_NOREQ);
+}
+
+/* Caller must hold the lock */
+static int ravb_ptp_time_read(struct ravb_private *priv, struct timespec64 *ts)
+{
+ struct net_device *ndev = priv->ndev;
+ int error;
+
+ error = ravb_ptp_tcr_request(priv, GCCR_TCR_CAPTURE);
+ if (error)
+ return error;
+
+ ts->tv_nsec = ravb_read(ndev, GCT0);
+ ts->tv_sec = ravb_read(ndev, GCT1) |
+ ((s64)ravb_read(ndev, GCT2) << 32);
+
+ return 0;
+}
+
+/* Caller must hold the lock */
+static int ravb_ptp_time_write(struct ravb_private *priv,
+ const struct timespec64 *ts)
+{
+ struct net_device *ndev = priv->ndev;
+ int error;
+ u32 gccr;
+
+ error = ravb_ptp_tcr_request(priv, GCCR_TCR_RESET);
+ if (error)
+ return error;
+
+ gccr = ravb_read(ndev, GCCR);
+ if (gccr & GCCR_LTO)
+ return -EBUSY;
+ ravb_write(ndev, ts->tv_nsec, GTO0);
+ ravb_write(ndev, ts->tv_sec, GTO1);
+ ravb_write(ndev, (ts->tv_sec >> 32) & 0xffff, GTO2);
+ ravb_write(ndev, gccr | GCCR_LTO, GCCR);
+
+ return 0;
+}
+
+/* Caller must hold the lock */
+static int ravb_ptp_update_compare(struct ravb_private *priv, u32 ns)
+{
+ struct net_device *ndev = priv->ndev;
+ /* When the comparison value (GPTC.PTCV) is in range of
+ * [x-1 to x+1] (x is the configured increment value in
+ * GTI.TIV), it may happen that a comparison match is
+ * not detected when the timer wraps around.
+ */
+ u32 gti_ns_plus_1 = (priv->ptp.current_addend >> 20) + 1;
+ u32 gccr;
+
+ if (ns < gti_ns_plus_1)
+ ns = gti_ns_plus_1;
+ else if (ns > 0 - gti_ns_plus_1)
+ ns = 0 - gti_ns_plus_1;
+
+ gccr = ravb_read(ndev, GCCR);
+ if (gccr & GCCR_LPTC)
+ return -EBUSY;
+ ravb_write(ndev, ns, GPTC);
+ ravb_write(ndev, gccr | GCCR_LPTC, GCCR);
+
+ return 0;
+}
+
+/* PTP clock operations */
+static int ravb_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+ struct ravb_private *priv = container_of(ptp, struct ravb_private,
+ ptp.info);
+ struct net_device *ndev = priv->ndev;
+ unsigned long flags;
+ u32 diff, addend;
+ bool neg_adj = false;
+ u32 gccr;
+
+ if (ppb < 0) {
+ neg_adj = true;
+ ppb = -ppb;
+ }
+ addend = priv->ptp.default_addend;
+ diff = div_u64((u64)addend * ppb, NSEC_PER_SEC);
+
+ addend = neg_adj ? addend - diff : addend + diff;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->ptp.current_addend = addend;
+
+ gccr = ravb_read(ndev, GCCR);
+ if (gccr & GCCR_LTI)
+ return -EBUSY;
+ ravb_write(ndev, addend & GTI_TIV, GTI);
+ ravb_write(ndev, gccr | GCCR_LTI, GCCR);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int ravb_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct ravb_private *priv = container_of(ptp, struct ravb_private,
+ ptp.info);
+ struct timespec64 ts;
+ unsigned long flags;
+ int error;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ error = ravb_ptp_time_read(priv, &ts);
+ if (!error) {
+ u64 now = ktime_to_ns(timespec64_to_ktime(ts));
+
+ ts = ns_to_timespec64(now + delta);
+ error = ravb_ptp_time_write(priv, &ts);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return error;
+}
+
+static int ravb_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts)
+{
+ struct ravb_private *priv = container_of(ptp, struct ravb_private,
+ ptp.info);
+ unsigned long flags;
+ int error;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ error = ravb_ptp_time_read(priv, ts);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return error;
+}
+
+static int ravb_ptp_settime64(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct ravb_private *priv = container_of(ptp, struct ravb_private,
+ ptp.info);
+ unsigned long flags;
+ int error;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ error = ravb_ptp_time_write(priv, ts);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return error;
+}
+
+static int ravb_ptp_extts(struct ptp_clock_info *ptp,
+ struct ptp_extts_request *req, int on)
+{
+ struct ravb_private *priv = container_of(ptp, struct ravb_private,
+ ptp.info);
+ struct net_device *ndev = priv->ndev;
+ unsigned long flags;
+ u32 gic;
+
+ if (req->index)
+ return -EINVAL;
+
+ if (priv->ptp.extts[req->index] == on)
+ return 0;
+ priv->ptp.extts[req->index] = on;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ gic = ravb_read(ndev, GIC);
+ if (on)
+ gic |= GIC_PTCE;
+ else
+ gic &= ~GIC_PTCE;
+ ravb_write(ndev, gic, GIC);
+ mmiowb();
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int ravb_ptp_perout(struct ptp_clock_info *ptp,
+ struct ptp_perout_request *req, int on)
+{
+ struct ravb_private *priv = container_of(ptp, struct ravb_private,
+ ptp.info);
+ struct net_device *ndev = priv->ndev;
+ struct ravb_ptp_perout *perout;
+ unsigned long flags;
+ int error = 0;
+ u32 gic;
+
+ if (req->index)
+ return -EINVAL;
+
+ if (on) {
+ u64 start_ns;
+ u64 period_ns;
+
+ start_ns = req->start.sec * NSEC_PER_SEC + req->start.nsec;
+ period_ns = req->period.sec * NSEC_PER_SEC + req->period.nsec;
+
+ if (start_ns > U32_MAX) {
+ netdev_warn(ndev,
+ "ptp: start value (nsec) is over limit. Maximum size of start is only 32 bits\n");
+ return -ERANGE;
+ }
+
+ if (period_ns > U32_MAX) {
+ netdev_warn(ndev,
+ "ptp: period value (nsec) is over limit. Maximum size of period is only 32 bits\n");
+ return -ERANGE;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ perout = &priv->ptp.perout[req->index];
+ perout->target = (u32)start_ns;
+ perout->period = (u32)period_ns;
+ error = ravb_ptp_update_compare(priv, (u32)start_ns);
+ if (!error) {
+ /* Unmask interrupt */
+ gic = ravb_read(ndev, GIC);
+ gic |= GIC_PTME;
+ ravb_write(ndev, gic, GIC);
+ }
+ } else {
+ spin_lock_irqsave(&priv->lock, flags);
+
+ perout = &priv->ptp.perout[req->index];
+ perout->period = 0;
+
+ /* Mask interrupt */
+ gic = ravb_read(ndev, GIC);
+ gic &= ~GIC_PTME;
+ ravb_write(ndev, gic, GIC);
+ }
+ mmiowb();
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return error;
+}
+
+static int ravb_ptp_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *req, int on)
+{
+ switch (req->type) {
+ case PTP_CLK_REQ_EXTTS:
+ return ravb_ptp_extts(ptp, &req->extts, on);
+ case PTP_CLK_REQ_PEROUT:
+ return ravb_ptp_perout(ptp, &req->perout, on);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static const struct ptp_clock_info ravb_ptp_info = {
+ .owner = THIS_MODULE,
+ .name = "ravb clock",
+ .max_adj = 50000000,
+ .n_ext_ts = N_EXT_TS,
+ .n_per_out = N_PER_OUT,
+ .adjfreq = ravb_ptp_adjfreq,
+ .adjtime = ravb_ptp_adjtime,
+ .gettime64 = ravb_ptp_gettime64,
+ .settime64 = ravb_ptp_settime64,
+ .enable = ravb_ptp_enable,
+};
+
+/* Caller must hold the lock */
+irqreturn_t ravb_ptp_interrupt(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ u32 gis = ravb_read(ndev, GIS);
+
+ gis &= ravb_read(ndev, GIC);
+ if (gis & GIS_PTCF) {
+ struct ptp_clock_event event;
+
+ event.type = PTP_CLOCK_EXTTS;
+ event.index = 0;
+ event.timestamp = ravb_read(ndev, GCPT);
+ ptp_clock_event(priv->ptp.clock, &event);
+ }
+ if (gis & GIS_PTMF) {
+ struct ravb_ptp_perout *perout = priv->ptp.perout;
+
+ if (perout->period) {
+ perout->target += perout->period;
+ ravb_ptp_update_compare(priv, perout->target);
+ }
+ }
+
+ if (gis) {
+ ravb_write(ndev, ~gis, GIS);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+void ravb_ptp_init(struct net_device *ndev, struct platform_device *pdev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ unsigned long flags;
+ u32 gccr;
+
+ priv->ptp.info = ravb_ptp_info;
+
+ priv->ptp.default_addend = ravb_read(ndev, GTI);
+ priv->ptp.current_addend = priv->ptp.default_addend;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ravb_wait(ndev, GCCR, GCCR_TCR, GCCR_TCR_NOREQ);
+ gccr = ravb_read(ndev, GCCR) & ~GCCR_TCSS;
+ ravb_write(ndev, gccr | GCCR_TCSS_ADJGPTP, GCCR);
+ mmiowb();
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ priv->ptp.clock = ptp_clock_register(&priv->ptp.info, &pdev->dev);
+}
+
+void ravb_ptp_stop(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+
+ ravb_write(ndev, 0, GIC);
+ ravb_write(ndev, 0, GIS);
+
+ ptp_clock_unregister(priv->ptp.clock);
+}
diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c
index cf98cc9bbc8d..2d8578cade03 100644
--- a/drivers/net/ethernet/rocker/rocker.c
+++ b/drivers/net/ethernet/rocker/rocker.c
@@ -181,7 +181,7 @@ struct rocker_desc_info {
size_t data_size;
size_t tlv_size;
struct rocker_desc *desc;
- DEFINE_DMA_UNMAP_ADDR(mapaddr);
+ dma_addr_t mapaddr;
};
struct rocker_dma_ring_info {
@@ -225,6 +225,7 @@ struct rocker_port {
struct napi_struct napi_rx;
struct rocker_dma_ring_info tx_ring;
struct rocker_dma_ring_info rx_ring;
+ struct list_head trans_mem;
};
struct rocker {
@@ -236,21 +237,21 @@ struct rocker {
struct {
u64 id;
} hw;
- spinlock_t cmd_ring_lock;
+ spinlock_t cmd_ring_lock; /* for cmd ring accesses */
struct rocker_dma_ring_info cmd_ring;
struct rocker_dma_ring_info event_ring;
DECLARE_HASHTABLE(flow_tbl, 16);
- spinlock_t flow_tbl_lock;
+ spinlock_t flow_tbl_lock; /* for flow tbl accesses */
u64 flow_tbl_next_cookie;
DECLARE_HASHTABLE(group_tbl, 16);
- spinlock_t group_tbl_lock;
+ spinlock_t group_tbl_lock; /* for group tbl accesses */
DECLARE_HASHTABLE(fdb_tbl, 16);
- spinlock_t fdb_tbl_lock;
+ spinlock_t fdb_tbl_lock; /* for fdb tbl accesses */
unsigned long internal_vlan_bitmap[ROCKER_INTERNAL_VLAN_BITMAP_LEN];
DECLARE_HASHTABLE(internal_vlan_tbl, 8);
- spinlock_t internal_vlan_tbl_lock;
+ spinlock_t internal_vlan_tbl_lock; /* for vlan tbl accesses */
DECLARE_HASHTABLE(neigh_tbl, 16);
- spinlock_t neigh_tbl_lock;
+ spinlock_t neigh_tbl_lock; /* for neigh tbl accesses */
u32 neigh_tbl_next_index;
};
@@ -294,7 +295,7 @@ static bool rocker_vlan_id_is_internal(__be16 vlan_id)
return (_vlan_id >= start && _vlan_id <= end);
}
-static __be16 rocker_port_vid_to_vlan(struct rocker_port *rocker_port,
+static __be16 rocker_port_vid_to_vlan(const struct rocker_port *rocker_port,
u16 vid, bool *pop_vlan)
{
__be16 vlan_id;
@@ -311,7 +312,7 @@ static __be16 rocker_port_vid_to_vlan(struct rocker_port *rocker_port,
return vlan_id;
}
-static u16 rocker_port_vlan_to_vid(struct rocker_port *rocker_port,
+static u16 rocker_port_vlan_to_vid(const struct rocker_port *rocker_port,
__be16 vlan_id)
{
if (rocker_vlan_id_is_internal(vlan_id))
@@ -320,11 +321,88 @@ static u16 rocker_port_vlan_to_vid(struct rocker_port *rocker_port,
return ntohs(vlan_id);
}
-static bool rocker_port_is_bridged(struct rocker_port *rocker_port)
+static bool rocker_port_is_bridged(const struct rocker_port *rocker_port)
{
return !!rocker_port->bridge_dev;
}
+#define ROCKER_OP_FLAG_REMOVE BIT(0)
+#define ROCKER_OP_FLAG_NOWAIT BIT(1)
+#define ROCKER_OP_FLAG_LEARNED BIT(2)
+#define ROCKER_OP_FLAG_REFRESH BIT(3)
+
+static void *__rocker_port_mem_alloc(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, int flags,
+ size_t size)
+{
+ struct list_head *elem = NULL;
+ gfp_t gfp_flags = (flags & ROCKER_OP_FLAG_NOWAIT) ?
+ GFP_ATOMIC : GFP_KERNEL;
+
+ /* If in transaction prepare phase, allocate the memory
+ * and enqueue it on a per-port list. If in transaction
+ * commit phase, dequeue the memory from the per-port list
+ * rather than re-allocating the memory. The idea is the
+ * driver code paths for prepare and commit are identical
+ * so the memory allocated in the prepare phase is the
+ * memory used in the commit phase.
+ */
+
+ switch (trans) {
+ case SWITCHDEV_TRANS_PREPARE:
+ elem = kzalloc(size + sizeof(*elem), gfp_flags);
+ if (!elem)
+ return NULL;
+ list_add_tail(elem, &rocker_port->trans_mem);
+ break;
+ case SWITCHDEV_TRANS_COMMIT:
+ BUG_ON(list_empty(&rocker_port->trans_mem));
+ elem = rocker_port->trans_mem.next;
+ list_del_init(elem);
+ break;
+ case SWITCHDEV_TRANS_NONE:
+ elem = kzalloc(size + sizeof(*elem), gfp_flags);
+ if (elem)
+ INIT_LIST_HEAD(elem);
+ break;
+ default:
+ break;
+ }
+
+ return elem ? elem + 1 : NULL;
+}
+
+static void *rocker_port_kzalloc(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, int flags,
+ size_t size)
+{
+ return __rocker_port_mem_alloc(rocker_port, trans, flags, size);
+}
+
+static void *rocker_port_kcalloc(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, int flags,
+ size_t n, size_t size)
+{
+ return __rocker_port_mem_alloc(rocker_port, trans, flags, n * size);
+}
+
+static void rocker_port_kfree(enum switchdev_trans trans, const void *mem)
+{
+ struct list_head *elem;
+
+ /* Frees are ignored if in transaction prepare phase. The
+ * memory remains on the per-port list until freed in the
+ * commit phase.
+ */
+
+ if (trans == SWITCHDEV_TRANS_PREPARE)
+ return;
+
+ elem = (struct list_head *)mem - 1;
+ BUG_ON(!list_empty(elem));
+ kfree(elem);
+}
+
struct rocker_wait {
wait_queue_head_t wait;
bool done;
@@ -343,20 +421,23 @@ static void rocker_wait_init(struct rocker_wait *wait)
rocker_wait_reset(wait);
}
-static struct rocker_wait *rocker_wait_create(gfp_t gfp)
+static struct rocker_wait *rocker_wait_create(struct rocker_port *rocker_port,
+ enum switchdev_trans trans,
+ int flags)
{
struct rocker_wait *wait;
- wait = kmalloc(sizeof(*wait), gfp);
+ wait = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*wait));
if (!wait)
return NULL;
rocker_wait_init(wait);
return wait;
}
-static void rocker_wait_destroy(struct rocker_wait *work)
+static void rocker_wait_destroy(enum switchdev_trans trans,
+ struct rocker_wait *wait)
{
- kfree(work);
+ rocker_port_kfree(trans, wait);
}
static bool rocker_wait_event_timeout(struct rocker_wait *wait,
@@ -374,18 +455,18 @@ static void rocker_wait_wake_up(struct rocker_wait *wait)
wake_up(&wait->wait);
}
-static u32 rocker_msix_vector(struct rocker *rocker, unsigned int vector)
+static u32 rocker_msix_vector(const struct rocker *rocker, unsigned int vector)
{
return rocker->msix_entries[vector].vector;
}
-static u32 rocker_msix_tx_vector(struct rocker_port *rocker_port)
+static u32 rocker_msix_tx_vector(const struct rocker_port *rocker_port)
{
return rocker_msix_vector(rocker_port->rocker,
ROCKER_MSIX_VEC_TX(rocker_port->port_number));
}
-static u32 rocker_msix_rx_vector(struct rocker_port *rocker_port)
+static u32 rocker_msix_rx_vector(const struct rocker_port *rocker_port)
{
return rocker_msix_vector(rocker_port->rocker,
ROCKER_MSIX_VEC_RX(rocker_port->port_number));
@@ -404,9 +485,9 @@ static u32 rocker_msix_rx_vector(struct rocker_port *rocker_port)
* HW basic testing functions
*****************************/
-static int rocker_reg_test(struct rocker *rocker)
+static int rocker_reg_test(const struct rocker *rocker)
{
- struct pci_dev *pdev = rocker->pdev;
+ const struct pci_dev *pdev = rocker->pdev;
u64 test_reg;
u64 rnd;
@@ -434,12 +515,12 @@ static int rocker_reg_test(struct rocker *rocker)
return 0;
}
-static int rocker_dma_test_one(struct rocker *rocker, struct rocker_wait *wait,
- u32 test_type, dma_addr_t dma_handle,
- unsigned char *buf, unsigned char *expect,
- size_t size)
+static int rocker_dma_test_one(const struct rocker *rocker,
+ struct rocker_wait *wait, u32 test_type,
+ dma_addr_t dma_handle, const unsigned char *buf,
+ const unsigned char *expect, size_t size)
{
- struct pci_dev *pdev = rocker->pdev;
+ const struct pci_dev *pdev = rocker->pdev;
int i;
rocker_wait_reset(wait);
@@ -463,7 +544,7 @@ static int rocker_dma_test_one(struct rocker *rocker, struct rocker_wait *wait,
#define ROCKER_TEST_DMA_BUF_SIZE (PAGE_SIZE * 4)
#define ROCKER_TEST_DMA_FILL_PATTERN 0x96
-static int rocker_dma_test_offset(struct rocker *rocker,
+static int rocker_dma_test_offset(const struct rocker *rocker,
struct rocker_wait *wait, int offset)
{
struct pci_dev *pdev = rocker->pdev;
@@ -523,7 +604,8 @@ free_alloc:
return err;
}
-static int rocker_dma_test(struct rocker *rocker, struct rocker_wait *wait)
+static int rocker_dma_test(const struct rocker *rocker,
+ struct rocker_wait *wait)
{
int i;
int err;
@@ -545,9 +627,9 @@ static irqreturn_t rocker_test_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int rocker_basic_hw_test(struct rocker *rocker)
+static int rocker_basic_hw_test(const struct rocker *rocker)
{
- struct pci_dev *pdev = rocker->pdev;
+ const struct pci_dev *pdev = rocker->pdev;
struct rocker_wait wait;
int err;
@@ -680,7 +762,7 @@ static u64 rocker_tlv_get_u64(const struct rocker_tlv *tlv)
return *(u64 *) rocker_tlv_data(tlv);
}
-static void rocker_tlv_parse(struct rocker_tlv **tb, int maxtype,
+static void rocker_tlv_parse(const struct rocker_tlv **tb, int maxtype,
const char *buf, int buf_len)
{
const struct rocker_tlv *tlv;
@@ -693,19 +775,19 @@ static void rocker_tlv_parse(struct rocker_tlv **tb, int maxtype,
u32 type = rocker_tlv_type(tlv);
if (type > 0 && type <= maxtype)
- tb[type] = (struct rocker_tlv *) tlv;
+ tb[type] = tlv;
}
}
-static void rocker_tlv_parse_nested(struct rocker_tlv **tb, int maxtype,
+static void rocker_tlv_parse_nested(const struct rocker_tlv **tb, int maxtype,
const struct rocker_tlv *tlv)
{
rocker_tlv_parse(tb, maxtype, rocker_tlv_data(tlv),
rocker_tlv_len(tlv));
}
-static void rocker_tlv_parse_desc(struct rocker_tlv **tb, int maxtype,
- struct rocker_desc_info *desc_info)
+static void rocker_tlv_parse_desc(const struct rocker_tlv **tb, int maxtype,
+ const struct rocker_desc_info *desc_info)
{
rocker_tlv_parse(tb, maxtype, desc_info->data,
desc_info->desc->tlv_size);
@@ -790,9 +872,9 @@ static void rocker_tlv_nest_end(struct rocker_desc_info *desc_info,
}
static void rocker_tlv_nest_cancel(struct rocker_desc_info *desc_info,
- struct rocker_tlv *start)
+ const struct rocker_tlv *start)
{
- desc_info->tlv_size = (char *) start - desc_info->data;
+ desc_info->tlv_size = (const char *) start - desc_info->data;
}
/******************************************
@@ -804,7 +886,7 @@ static u32 __pos_inc(u32 pos, size_t limit)
return ++pos == limit ? 0 : pos;
}
-static int rocker_desc_err(struct rocker_desc_info *desc_info)
+static int rocker_desc_err(const struct rocker_desc_info *desc_info)
{
int err = desc_info->desc->comp_err & ~ROCKER_DMA_DESC_COMP_ERR_GEN;
@@ -832,31 +914,31 @@ static int rocker_desc_err(struct rocker_desc_info *desc_info)
return -EINVAL;
}
-static void rocker_desc_gen_clear(struct rocker_desc_info *desc_info)
+static void rocker_desc_gen_clear(const struct rocker_desc_info *desc_info)
{
desc_info->desc->comp_err &= ~ROCKER_DMA_DESC_COMP_ERR_GEN;
}
-static bool rocker_desc_gen(struct rocker_desc_info *desc_info)
+static bool rocker_desc_gen(const struct rocker_desc_info *desc_info)
{
u32 comp_err = desc_info->desc->comp_err;
return comp_err & ROCKER_DMA_DESC_COMP_ERR_GEN ? true : false;
}
-static void *rocker_desc_cookie_ptr_get(struct rocker_desc_info *desc_info)
+static void *rocker_desc_cookie_ptr_get(const struct rocker_desc_info *desc_info)
{
return (void *)(uintptr_t)desc_info->desc->cookie;
}
-static void rocker_desc_cookie_ptr_set(struct rocker_desc_info *desc_info,
+static void rocker_desc_cookie_ptr_set(const struct rocker_desc_info *desc_info,
void *ptr)
{
desc_info->desc->cookie = (uintptr_t) ptr;
}
static struct rocker_desc_info *
-rocker_desc_head_get(struct rocker_dma_ring_info *info)
+rocker_desc_head_get(const struct rocker_dma_ring_info *info)
{
static struct rocker_desc_info *desc_info;
u32 head = __pos_inc(info->head, info->size);
@@ -868,15 +950,15 @@ rocker_desc_head_get(struct rocker_dma_ring_info *info)
return desc_info;
}
-static void rocker_desc_commit(struct rocker_desc_info *desc_info)
+static void rocker_desc_commit(const struct rocker_desc_info *desc_info)
{
desc_info->desc->buf_size = desc_info->data_size;
desc_info->desc->tlv_size = desc_info->tlv_size;
}
-static void rocker_desc_head_set(struct rocker *rocker,
+static void rocker_desc_head_set(const struct rocker *rocker,
struct rocker_dma_ring_info *info,
- struct rocker_desc_info *desc_info)
+ const struct rocker_desc_info *desc_info)
{
u32 head = __pos_inc(info->head, info->size);
@@ -901,8 +983,8 @@ rocker_desc_tail_get(struct rocker_dma_ring_info *info)
return desc_info;
}
-static void rocker_dma_ring_credits_set(struct rocker *rocker,
- struct rocker_dma_ring_info *info,
+static void rocker_dma_ring_credits_set(const struct rocker *rocker,
+ const struct rocker_dma_ring_info *info,
u32 credits)
{
if (credits)
@@ -915,7 +997,7 @@ static unsigned long rocker_dma_ring_size_fix(size_t size)
min(roundup_pow_of_two(size), ROCKER_DMA_SIZE_MAX));
}
-static int rocker_dma_ring_create(struct rocker *rocker,
+static int rocker_dma_ring_create(const struct rocker *rocker,
unsigned int type,
size_t size,
struct rocker_dma_ring_info *info)
@@ -951,8 +1033,8 @@ static int rocker_dma_ring_create(struct rocker *rocker,
return 0;
}
-static void rocker_dma_ring_destroy(struct rocker *rocker,
- struct rocker_dma_ring_info *info)
+static void rocker_dma_ring_destroy(const struct rocker *rocker,
+ const struct rocker_dma_ring_info *info)
{
rocker_write64(rocker, DMA_DESC_ADDR(info->type), 0);
@@ -962,7 +1044,7 @@ static void rocker_dma_ring_destroy(struct rocker *rocker,
kfree(info->desc_info);
}
-static void rocker_dma_ring_pass_to_producer(struct rocker *rocker,
+static void rocker_dma_ring_pass_to_producer(const struct rocker *rocker,
struct rocker_dma_ring_info *info)
{
int i;
@@ -977,8 +1059,8 @@ static void rocker_dma_ring_pass_to_producer(struct rocker *rocker,
rocker_desc_commit(&info->desc_info[i]);
}
-static int rocker_dma_ring_bufs_alloc(struct rocker *rocker,
- struct rocker_dma_ring_info *info,
+static int rocker_dma_ring_bufs_alloc(const struct rocker *rocker,
+ const struct rocker_dma_ring_info *info,
int direction, size_t buf_size)
{
struct pci_dev *pdev = rocker->pdev;
@@ -1015,7 +1097,7 @@ static int rocker_dma_ring_bufs_alloc(struct rocker *rocker,
rollback:
for (i--; i >= 0; i--) {
- struct rocker_desc_info *desc_info = &info->desc_info[i];
+ const struct rocker_desc_info *desc_info = &info->desc_info[i];
pci_unmap_single(pdev, dma_unmap_addr(desc_info, mapaddr),
desc_info->data_size, direction);
@@ -1024,15 +1106,15 @@ rollback:
return err;
}
-static void rocker_dma_ring_bufs_free(struct rocker *rocker,
- struct rocker_dma_ring_info *info,
+static void rocker_dma_ring_bufs_free(const struct rocker *rocker,
+ const struct rocker_dma_ring_info *info,
int direction)
{
struct pci_dev *pdev = rocker->pdev;
int i;
for (i = 0; i < info->size; i++) {
- struct rocker_desc_info *desc_info = &info->desc_info[i];
+ const struct rocker_desc_info *desc_info = &info->desc_info[i];
struct rocker_desc *desc = &info->desc[i];
desc->buf_addr = 0;
@@ -1045,7 +1127,7 @@ static void rocker_dma_ring_bufs_free(struct rocker *rocker,
static int rocker_dma_rings_init(struct rocker *rocker)
{
- struct pci_dev *pdev = rocker->pdev;
+ const struct pci_dev *pdev = rocker->pdev;
int err;
err = rocker_dma_ring_create(rocker, ROCKER_DMA_CMD,
@@ -1102,11 +1184,11 @@ static void rocker_dma_rings_fini(struct rocker *rocker)
rocker_dma_ring_destroy(rocker, &rocker->cmd_ring);
}
-static int rocker_dma_rx_ring_skb_map(struct rocker *rocker,
- struct rocker_port *rocker_port,
+static int rocker_dma_rx_ring_skb_map(const struct rocker_port *rocker_port,
struct rocker_desc_info *desc_info,
struct sk_buff *skb, size_t buf_len)
{
+ const struct rocker *rocker = rocker_port->rocker;
struct pci_dev *pdev = rocker->pdev;
dma_addr_t dma_handle;
@@ -1126,13 +1208,12 @@ tlv_put_failure:
return -EMSGSIZE;
}
-static size_t rocker_port_rx_buf_len(struct rocker_port *rocker_port)
+static size_t rocker_port_rx_buf_len(const struct rocker_port *rocker_port)
{
return rocker_port->dev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
}
-static int rocker_dma_rx_ring_skb_alloc(struct rocker *rocker,
- struct rocker_port *rocker_port,
+static int rocker_dma_rx_ring_skb_alloc(const struct rocker_port *rocker_port,
struct rocker_desc_info *desc_info)
{
struct net_device *dev = rocker_port->dev;
@@ -1149,8 +1230,7 @@ static int rocker_dma_rx_ring_skb_alloc(struct rocker *rocker,
skb = netdev_alloc_skb_ip_align(dev, buf_len);
if (!skb)
return -ENOMEM;
- err = rocker_dma_rx_ring_skb_map(rocker, rocker_port, desc_info,
- skb, buf_len);
+ err = rocker_dma_rx_ring_skb_map(rocker_port, desc_info, skb, buf_len);
if (err) {
dev_kfree_skb_any(skb);
return err;
@@ -1159,8 +1239,8 @@ static int rocker_dma_rx_ring_skb_alloc(struct rocker *rocker,
return 0;
}
-static void rocker_dma_rx_ring_skb_unmap(struct rocker *rocker,
- struct rocker_tlv **attrs)
+static void rocker_dma_rx_ring_skb_unmap(const struct rocker *rocker,
+ const struct rocker_tlv **attrs)
{
struct pci_dev *pdev = rocker->pdev;
dma_addr_t dma_handle;
@@ -1174,10 +1254,10 @@ static void rocker_dma_rx_ring_skb_unmap(struct rocker *rocker,
pci_unmap_single(pdev, dma_handle, len, PCI_DMA_FROMDEVICE);
}
-static void rocker_dma_rx_ring_skb_free(struct rocker *rocker,
- struct rocker_desc_info *desc_info)
+static void rocker_dma_rx_ring_skb_free(const struct rocker *rocker,
+ const struct rocker_desc_info *desc_info)
{
- struct rocker_tlv *attrs[ROCKER_TLV_RX_MAX + 1];
+ const struct rocker_tlv *attrs[ROCKER_TLV_RX_MAX + 1];
struct sk_buff *skb = rocker_desc_cookie_ptr_get(desc_info);
if (!skb)
@@ -1187,15 +1267,15 @@ static void rocker_dma_rx_ring_skb_free(struct rocker *rocker,
dev_kfree_skb_any(skb);
}
-static int rocker_dma_rx_ring_skbs_alloc(struct rocker *rocker,
- struct rocker_port *rocker_port)
+static int rocker_dma_rx_ring_skbs_alloc(const struct rocker_port *rocker_port)
{
- struct rocker_dma_ring_info *rx_ring = &rocker_port->rx_ring;
+ const struct rocker_dma_ring_info *rx_ring = &rocker_port->rx_ring;
+ const struct rocker *rocker = rocker_port->rocker;
int i;
int err;
for (i = 0; i < rx_ring->size; i++) {
- err = rocker_dma_rx_ring_skb_alloc(rocker, rocker_port,
+ err = rocker_dma_rx_ring_skb_alloc(rocker_port,
&rx_ring->desc_info[i]);
if (err)
goto rollback;
@@ -1208,10 +1288,10 @@ rollback:
return err;
}
-static void rocker_dma_rx_ring_skbs_free(struct rocker *rocker,
- struct rocker_port *rocker_port)
+static void rocker_dma_rx_ring_skbs_free(const struct rocker_port *rocker_port)
{
- struct rocker_dma_ring_info *rx_ring = &rocker_port->rx_ring;
+ const struct rocker_dma_ring_info *rx_ring = &rocker_port->rx_ring;
+ const struct rocker *rocker = rocker_port->rocker;
int i;
for (i = 0; i < rx_ring->size; i++)
@@ -1257,7 +1337,7 @@ static int rocker_port_dma_rings_init(struct rocker_port *rocker_port)
goto err_dma_rx_ring_bufs_alloc;
}
- err = rocker_dma_rx_ring_skbs_alloc(rocker, rocker_port);
+ err = rocker_dma_rx_ring_skbs_alloc(rocker_port);
if (err) {
netdev_err(rocker_port->dev, "failed to alloc rx dma ring skbs\n");
goto err_dma_rx_ring_skbs_alloc;
@@ -1283,7 +1363,7 @@ static void rocker_port_dma_rings_fini(struct rocker_port *rocker_port)
{
struct rocker *rocker = rocker_port->rocker;
- rocker_dma_rx_ring_skbs_free(rocker, rocker_port);
+ rocker_dma_rx_ring_skbs_free(rocker_port);
rocker_dma_ring_bufs_free(rocker, &rocker_port->rx_ring,
PCI_DMA_BIDIRECTIONAL);
rocker_dma_ring_destroy(rocker, &rocker_port->rx_ring);
@@ -1292,7 +1372,8 @@ static void rocker_port_dma_rings_fini(struct rocker_port *rocker_port)
rocker_dma_ring_destroy(rocker, &rocker_port->tx_ring);
}
-static void rocker_port_set_enable(struct rocker_port *rocker_port, bool enable)
+static void rocker_port_set_enable(const struct rocker_port *rocker_port,
+ bool enable)
{
u64 val = rocker_read64(rocker_port->rocker, PORT_PHYS_ENABLE);
@@ -1310,7 +1391,7 @@ static void rocker_port_set_enable(struct rocker_port *rocker_port, bool enable)
static irqreturn_t rocker_cmd_irq_handler(int irq, void *dev_id)
{
struct rocker *rocker = dev_id;
- struct rocker_desc_info *desc_info;
+ const struct rocker_desc_info *desc_info;
struct rocker_wait *wait;
u32 credits = 0;
@@ -1319,7 +1400,7 @@ static irqreturn_t rocker_cmd_irq_handler(int irq, void *dev_id)
wait = rocker_desc_cookie_ptr_get(desc_info);
if (wait->nowait) {
rocker_desc_gen_clear(desc_info);
- rocker_wait_destroy(wait);
+ rocker_wait_destroy(SWITCHDEV_TRANS_NONE, wait);
} else {
rocker_wait_wake_up(wait);
}
@@ -1331,22 +1412,22 @@ static irqreturn_t rocker_cmd_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static void rocker_port_link_up(struct rocker_port *rocker_port)
+static void rocker_port_link_up(const struct rocker_port *rocker_port)
{
netif_carrier_on(rocker_port->dev);
netdev_info(rocker_port->dev, "Link is up\n");
}
-static void rocker_port_link_down(struct rocker_port *rocker_port)
+static void rocker_port_link_down(const struct rocker_port *rocker_port)
{
netif_carrier_off(rocker_port->dev);
netdev_info(rocker_port->dev, "Link is down\n");
}
-static int rocker_event_link_change(struct rocker *rocker,
+static int rocker_event_link_change(const struct rocker *rocker,
const struct rocker_tlv *info)
{
- struct rocker_tlv *attrs[ROCKER_TLV_EVENT_LINK_CHANGED_MAX + 1];
+ const struct rocker_tlv *attrs[ROCKER_TLV_EVENT_LINK_CHANGED_MAX + 1];
unsigned int port_number;
bool link_up;
struct rocker_port *rocker_port;
@@ -1373,22 +1454,18 @@ static int rocker_event_link_change(struct rocker *rocker,
return 0;
}
-#define ROCKER_OP_FLAG_REMOVE BIT(0)
-#define ROCKER_OP_FLAG_NOWAIT BIT(1)
-#define ROCKER_OP_FLAG_LEARNED BIT(2)
-#define ROCKER_OP_FLAG_REFRESH BIT(3)
-
static int rocker_port_fdb(struct rocker_port *rocker_port,
+ enum switchdev_trans trans,
const unsigned char *addr,
__be16 vlan_id, int flags);
-static int rocker_event_mac_vlan_seen(struct rocker *rocker,
+static int rocker_event_mac_vlan_seen(const struct rocker *rocker,
const struct rocker_tlv *info)
{
- struct rocker_tlv *attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAX + 1];
+ const struct rocker_tlv *attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAX + 1];
unsigned int port_number;
struct rocker_port *rocker_port;
- unsigned char *addr;
+ const unsigned char *addr;
int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_LEARNED;
__be16 vlan_id;
@@ -1411,14 +1488,15 @@ static int rocker_event_mac_vlan_seen(struct rocker *rocker,
rocker_port->stp_state != BR_STATE_FORWARDING)
return 0;
- return rocker_port_fdb(rocker_port, addr, vlan_id, flags);
+ return rocker_port_fdb(rocker_port, SWITCHDEV_TRANS_NONE,
+ addr, vlan_id, flags);
}
-static int rocker_event_process(struct rocker *rocker,
- struct rocker_desc_info *desc_info)
+static int rocker_event_process(const struct rocker *rocker,
+ const struct rocker_desc_info *desc_info)
{
- struct rocker_tlv *attrs[ROCKER_TLV_EVENT_MAX + 1];
- struct rocker_tlv *info;
+ const struct rocker_tlv *attrs[ROCKER_TLV_EVENT_MAX + 1];
+ const struct rocker_tlv *info;
u16 type;
rocker_tlv_parse_desc(attrs, ROCKER_TLV_EVENT_MAX, desc_info);
@@ -1442,8 +1520,8 @@ static int rocker_event_process(struct rocker *rocker,
static irqreturn_t rocker_event_irq_handler(int irq, void *dev_id)
{
struct rocker *rocker = dev_id;
- struct pci_dev *pdev = rocker->pdev;
- struct rocker_desc_info *desc_info;
+ const struct pci_dev *pdev = rocker->pdev;
+ const struct rocker_desc_info *desc_info;
u32 credits = 0;
int err;
@@ -1487,65 +1565,75 @@ static irqreturn_t rocker_rx_irq_handler(int irq, void *dev_id)
* Command interface
********************/
-typedef int (*rocker_cmd_cb_t)(struct rocker *rocker,
- struct rocker_port *rocker_port,
- struct rocker_desc_info *desc_info,
- void *priv);
+typedef int (*rocker_cmd_prep_cb_t)(const struct rocker_port *rocker_port,
+ struct rocker_desc_info *desc_info,
+ void *priv);
+
+typedef int (*rocker_cmd_proc_cb_t)(const struct rocker_port *rocker_port,
+ const struct rocker_desc_info *desc_info,
+ void *priv);
-static int rocker_cmd_exec(struct rocker *rocker,
- struct rocker_port *rocker_port,
- rocker_cmd_cb_t prepare, void *prepare_priv,
- rocker_cmd_cb_t process, void *process_priv,
- bool nowait)
+static int rocker_cmd_exec(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, int flags,
+ rocker_cmd_prep_cb_t prepare, void *prepare_priv,
+ rocker_cmd_proc_cb_t process, void *process_priv)
{
+ struct rocker *rocker = rocker_port->rocker;
struct rocker_desc_info *desc_info;
struct rocker_wait *wait;
- unsigned long flags;
+ bool nowait = !!(flags & ROCKER_OP_FLAG_NOWAIT);
+ unsigned long lock_flags;
int err;
- wait = rocker_wait_create(nowait ? GFP_ATOMIC : GFP_KERNEL);
+ wait = rocker_wait_create(rocker_port, trans, flags);
if (!wait)
return -ENOMEM;
wait->nowait = nowait;
- spin_lock_irqsave(&rocker->cmd_ring_lock, flags);
+ spin_lock_irqsave(&rocker->cmd_ring_lock, lock_flags);
+
desc_info = rocker_desc_head_get(&rocker->cmd_ring);
if (!desc_info) {
- spin_unlock_irqrestore(&rocker->cmd_ring_lock, flags);
+ spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);
err = -EAGAIN;
goto out;
}
- err = prepare(rocker, rocker_port, desc_info, prepare_priv);
+
+ err = prepare(rocker_port, desc_info, prepare_priv);
if (err) {
- spin_unlock_irqrestore(&rocker->cmd_ring_lock, flags);
+ spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);
goto out;
}
+
rocker_desc_cookie_ptr_set(desc_info, wait);
- rocker_desc_head_set(rocker, &rocker->cmd_ring, desc_info);
- spin_unlock_irqrestore(&rocker->cmd_ring_lock, flags);
+
+ if (trans != SWITCHDEV_TRANS_PREPARE)
+ rocker_desc_head_set(rocker, &rocker->cmd_ring, desc_info);
+
+ spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);
if (nowait)
return 0;
- if (!rocker_wait_event_timeout(wait, HZ / 10))
- return -EIO;
+ if (trans != SWITCHDEV_TRANS_PREPARE)
+ if (!rocker_wait_event_timeout(wait, HZ / 10))
+ return -EIO;
err = rocker_desc_err(desc_info);
if (err)
return err;
if (process)
- err = process(rocker, rocker_port, desc_info, process_priv);
+ err = process(rocker_port, desc_info, process_priv);
rocker_desc_gen_clear(desc_info);
out:
- rocker_wait_destroy(wait);
+ rocker_wait_destroy(trans, wait);
return err;
}
static int
-rocker_cmd_get_port_settings_prep(struct rocker *rocker,
- struct rocker_port *rocker_port,
+rocker_cmd_get_port_settings_prep(const struct rocker_port *rocker_port,
struct rocker_desc_info *desc_info,
void *priv)
{
@@ -1565,14 +1653,13 @@ rocker_cmd_get_port_settings_prep(struct rocker *rocker,
}
static int
-rocker_cmd_get_port_settings_ethtool_proc(struct rocker *rocker,
- struct rocker_port *rocker_port,
- struct rocker_desc_info *desc_info,
+rocker_cmd_get_port_settings_ethtool_proc(const struct rocker_port *rocker_port,
+ const struct rocker_desc_info *desc_info,
void *priv)
{
struct ethtool_cmd *ecmd = priv;
- struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
- struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
+ const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
+ const struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
u32 speed;
u8 duplex;
u8 autoneg;
@@ -1604,15 +1691,14 @@ rocker_cmd_get_port_settings_ethtool_proc(struct rocker *rocker,
}
static int
-rocker_cmd_get_port_settings_macaddr_proc(struct rocker *rocker,
- struct rocker_port *rocker_port,
- struct rocker_desc_info *desc_info,
+rocker_cmd_get_port_settings_macaddr_proc(const struct rocker_port *rocker_port,
+ const struct rocker_desc_info *desc_info,
void *priv)
{
unsigned char *macaddr = priv;
- struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
- struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
- struct rocker_tlv *attr;
+ const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
+ const struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
+ const struct rocker_tlv *attr;
rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);
if (!attrs[ROCKER_TLV_CMD_INFO])
@@ -1637,17 +1723,16 @@ struct port_name {
};
static int
-rocker_cmd_get_port_settings_phys_name_proc(struct rocker *rocker,
- struct rocker_port *rocker_port,
- struct rocker_desc_info *desc_info,
+rocker_cmd_get_port_settings_phys_name_proc(const struct rocker_port *rocker_port,
+ const struct rocker_desc_info *desc_info,
void *priv)
{
- struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
- struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
+ const struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
+ const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
struct port_name *name = priv;
- struct rocker_tlv *attr;
+ const struct rocker_tlv *attr;
size_t i, j, len;
- char *str;
+ const char *str;
rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);
if (!attrs[ROCKER_TLV_CMD_INFO])
@@ -1679,8 +1764,7 @@ rocker_cmd_get_port_settings_phys_name_proc(struct rocker *rocker,
}
static int
-rocker_cmd_set_port_settings_ethtool_prep(struct rocker *rocker,
- struct rocker_port *rocker_port,
+rocker_cmd_set_port_settings_ethtool_prep(const struct rocker_port *rocker_port,
struct rocker_desc_info *desc_info,
void *priv)
{
@@ -1710,12 +1794,11 @@ rocker_cmd_set_port_settings_ethtool_prep(struct rocker *rocker,
}
static int
-rocker_cmd_set_port_settings_macaddr_prep(struct rocker *rocker,
- struct rocker_port *rocker_port,
+rocker_cmd_set_port_settings_macaddr_prep(const struct rocker_port *rocker_port,
struct rocker_desc_info *desc_info,
void *priv)
{
- unsigned char *macaddr = priv;
+ const unsigned char *macaddr = priv;
struct rocker_tlv *cmd_info;
if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
@@ -1735,8 +1818,7 @@ rocker_cmd_set_port_settings_macaddr_prep(struct rocker *rocker,
}
static int
-rocker_cmd_set_port_learning_prep(struct rocker *rocker,
- struct rocker_port *rocker_port,
+rocker_cmd_set_port_learning_prep(const struct rocker_port *rocker_port,
struct rocker_desc_info *desc_info,
void *priv)
{
@@ -1761,46 +1843,48 @@ rocker_cmd_set_port_learning_prep(struct rocker *rocker,
static int rocker_cmd_get_port_settings_ethtool(struct rocker_port *rocker_port,
struct ethtool_cmd *ecmd)
{
- return rocker_cmd_exec(rocker_port->rocker, rocker_port,
+ return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
rocker_cmd_get_port_settings_prep, NULL,
rocker_cmd_get_port_settings_ethtool_proc,
- ecmd, false);
+ ecmd);
}
static int rocker_cmd_get_port_settings_macaddr(struct rocker_port *rocker_port,
unsigned char *macaddr)
{
- return rocker_cmd_exec(rocker_port->rocker, rocker_port,
+ return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
rocker_cmd_get_port_settings_prep, NULL,
rocker_cmd_get_port_settings_macaddr_proc,
- macaddr, false);
+ macaddr);
}
static int rocker_cmd_set_port_settings_ethtool(struct rocker_port *rocker_port,
struct ethtool_cmd *ecmd)
{
- return rocker_cmd_exec(rocker_port->rocker, rocker_port,
+ return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
rocker_cmd_set_port_settings_ethtool_prep,
- ecmd, NULL, NULL, false);
+ ecmd, NULL, NULL);
}
static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port,
unsigned char *macaddr)
{
- return rocker_cmd_exec(rocker_port->rocker, rocker_port,
+ return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
rocker_cmd_set_port_settings_macaddr_prep,
- macaddr, NULL, NULL, false);
+ macaddr, NULL, NULL);
}
-static int rocker_port_set_learning(struct rocker_port *rocker_port)
+static int rocker_port_set_learning(struct rocker_port *rocker_port,
+ enum switchdev_trans trans)
{
- return rocker_cmd_exec(rocker_port->rocker, rocker_port,
+ return rocker_cmd_exec(rocker_port, trans, 0,
rocker_cmd_set_port_learning_prep,
- NULL, NULL, NULL, false);
+ NULL, NULL, NULL);
}
-static int rocker_cmd_flow_tbl_add_ig_port(struct rocker_desc_info *desc_info,
- struct rocker_flow_tbl_entry *entry)
+static int
+rocker_cmd_flow_tbl_add_ig_port(struct rocker_desc_info *desc_info,
+ const struct rocker_flow_tbl_entry *entry)
{
if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
entry->key.ig_port.in_pport))
@@ -1815,8 +1899,9 @@ static int rocker_cmd_flow_tbl_add_ig_port(struct rocker_desc_info *desc_info,
return 0;
}
-static int rocker_cmd_flow_tbl_add_vlan(struct rocker_desc_info *desc_info,
- struct rocker_flow_tbl_entry *entry)
+static int
+rocker_cmd_flow_tbl_add_vlan(struct rocker_desc_info *desc_info,
+ const struct rocker_flow_tbl_entry *entry)
{
if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
entry->key.vlan.in_pport))
@@ -1838,8 +1923,9 @@ static int rocker_cmd_flow_tbl_add_vlan(struct rocker_desc_info *desc_info,
return 0;
}
-static int rocker_cmd_flow_tbl_add_term_mac(struct rocker_desc_info *desc_info,
- struct rocker_flow_tbl_entry *entry)
+static int
+rocker_cmd_flow_tbl_add_term_mac(struct rocker_desc_info *desc_info,
+ const struct rocker_flow_tbl_entry *entry)
{
if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
entry->key.term_mac.in_pport))
@@ -1875,7 +1961,7 @@ static int rocker_cmd_flow_tbl_add_term_mac(struct rocker_desc_info *desc_info,
static int
rocker_cmd_flow_tbl_add_ucast_routing(struct rocker_desc_info *desc_info,
- struct rocker_flow_tbl_entry *entry)
+ const struct rocker_flow_tbl_entry *entry)
{
if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
entry->key.ucast_routing.eth_type))
@@ -1896,8 +1982,9 @@ rocker_cmd_flow_tbl_add_ucast_routing(struct rocker_desc_info *desc_info,
return 0;
}
-static int rocker_cmd_flow_tbl_add_bridge(struct rocker_desc_info *desc_info,
- struct rocker_flow_tbl_entry *entry)
+static int
+rocker_cmd_flow_tbl_add_bridge(struct rocker_desc_info *desc_info,
+ const struct rocker_flow_tbl_entry *entry)
{
if (entry->key.bridge.has_eth_dst &&
rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
@@ -1929,8 +2016,9 @@ static int rocker_cmd_flow_tbl_add_bridge(struct rocker_desc_info *desc_info,
return 0;
}
-static int rocker_cmd_flow_tbl_add_acl(struct rocker_desc_info *desc_info,
- struct rocker_flow_tbl_entry *entry)
+static int
+rocker_cmd_flow_tbl_add_acl(struct rocker_desc_info *desc_info,
+ const struct rocker_flow_tbl_entry *entry)
{
if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
entry->key.acl.in_pport))
@@ -1995,12 +2083,11 @@ static int rocker_cmd_flow_tbl_add_acl(struct rocker_desc_info *desc_info,
return 0;
}
-static int rocker_cmd_flow_tbl_add(struct rocker *rocker,
- struct rocker_port *rocker_port,
+static int rocker_cmd_flow_tbl_add(const struct rocker_port *rocker_port,
struct rocker_desc_info *desc_info,
void *priv)
{
- struct rocker_flow_tbl_entry *entry = priv;
+ const struct rocker_flow_tbl_entry *entry = priv;
struct rocker_tlv *cmd_info;
int err = 0;
@@ -2053,8 +2140,7 @@ static int rocker_cmd_flow_tbl_add(struct rocker *rocker,
return 0;
}
-static int rocker_cmd_flow_tbl_del(struct rocker *rocker,
- struct rocker_port *rocker_port,
+static int rocker_cmd_flow_tbl_del(const struct rocker_port *rocker_port,
struct rocker_desc_info *desc_info,
void *priv)
{
@@ -2090,7 +2176,7 @@ rocker_cmd_group_tbl_add_l2_interface(struct rocker_desc_info *desc_info,
static int
rocker_cmd_group_tbl_add_l2_rewrite(struct rocker_desc_info *desc_info,
- struct rocker_group_tbl_entry *entry)
+ const struct rocker_group_tbl_entry *entry)
{
if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID_LOWER,
entry->l2_rewrite.group_id))
@@ -2113,7 +2199,7 @@ rocker_cmd_group_tbl_add_l2_rewrite(struct rocker_desc_info *desc_info,
static int
rocker_cmd_group_tbl_add_group_ids(struct rocker_desc_info *desc_info,
- struct rocker_group_tbl_entry *entry)
+ const struct rocker_group_tbl_entry *entry)
{
int i;
struct rocker_tlv *group_ids;
@@ -2139,7 +2225,7 @@ rocker_cmd_group_tbl_add_group_ids(struct rocker_desc_info *desc_info,
static int
rocker_cmd_group_tbl_add_l3_unicast(struct rocker_desc_info *desc_info,
- struct rocker_group_tbl_entry *entry)
+ const struct rocker_group_tbl_entry *entry)
{
if (!is_zero_ether_addr(entry->l3_unicast.eth_src) &&
rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
@@ -2163,8 +2249,7 @@ rocker_cmd_group_tbl_add_l3_unicast(struct rocker_desc_info *desc_info,
return 0;
}
-static int rocker_cmd_group_tbl_add(struct rocker *rocker,
- struct rocker_port *rocker_port,
+static int rocker_cmd_group_tbl_add(const struct rocker_port *rocker_port,
struct rocker_desc_info *desc_info,
void *priv)
{
@@ -2209,8 +2294,7 @@ static int rocker_cmd_group_tbl_add(struct rocker *rocker,
return 0;
}
-static int rocker_cmd_group_tbl_del(struct rocker *rocker,
- struct rocker_port *rocker_port,
+static int rocker_cmd_group_tbl_del(const struct rocker_port *rocker_port,
struct rocker_desc_info *desc_info,
void *priv)
{
@@ -2293,7 +2377,8 @@ static void rocker_free_tbls(struct rocker *rocker)
}
static struct rocker_flow_tbl_entry *
-rocker_flow_tbl_find(struct rocker *rocker, struct rocker_flow_tbl_entry *match)
+rocker_flow_tbl_find(const struct rocker *rocker,
+ const struct rocker_flow_tbl_entry *match)
{
struct rocker_flow_tbl_entry *found;
size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
@@ -2308,24 +2393,25 @@ rocker_flow_tbl_find(struct rocker *rocker, struct rocker_flow_tbl_entry *match)
}
static int rocker_flow_tbl_add(struct rocker_port *rocker_port,
- struct rocker_flow_tbl_entry *match,
- bool nowait)
+ enum switchdev_trans trans, int flags,
+ struct rocker_flow_tbl_entry *match)
{
struct rocker *rocker = rocker_port->rocker;
struct rocker_flow_tbl_entry *found;
size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
- unsigned long flags;
+ unsigned long lock_flags;
match->key_crc32 = crc32(~0, &match->key, key_len);
- spin_lock_irqsave(&rocker->flow_tbl_lock, flags);
+ spin_lock_irqsave(&rocker->flow_tbl_lock, lock_flags);
found = rocker_flow_tbl_find(rocker, match);
if (found) {
match->cookie = found->cookie;
- hash_del(&found->entry);
- kfree(found);
+ if (trans != SWITCHDEV_TRANS_PREPARE)
+ hash_del(&found->entry);
+ rocker_port_kfree(trans, found);
found = match;
found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD;
} else {
@@ -2334,73 +2420,69 @@ static int rocker_flow_tbl_add(struct rocker_port *rocker_port,
found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD;
}
- hash_add(rocker->flow_tbl, &found->entry, found->key_crc32);
+ if (trans != SWITCHDEV_TRANS_PREPARE)
+ hash_add(rocker->flow_tbl, &found->entry, found->key_crc32);
- spin_unlock_irqrestore(&rocker->flow_tbl_lock, flags);
+ spin_unlock_irqrestore(&rocker->flow_tbl_lock, lock_flags);
- return rocker_cmd_exec(rocker, rocker_port,
- rocker_cmd_flow_tbl_add,
- found, NULL, NULL, nowait);
+ return rocker_cmd_exec(rocker_port, trans, flags,
+ rocker_cmd_flow_tbl_add, found, NULL, NULL);
}
static int rocker_flow_tbl_del(struct rocker_port *rocker_port,
- struct rocker_flow_tbl_entry *match,
- bool nowait)
+ enum switchdev_trans trans, int flags,
+ struct rocker_flow_tbl_entry *match)
{
struct rocker *rocker = rocker_port->rocker;
struct rocker_flow_tbl_entry *found;
size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
- unsigned long flags;
+ unsigned long lock_flags;
int err = 0;
match->key_crc32 = crc32(~0, &match->key, key_len);
- spin_lock_irqsave(&rocker->flow_tbl_lock, flags);
+ spin_lock_irqsave(&rocker->flow_tbl_lock, lock_flags);
found = rocker_flow_tbl_find(rocker, match);
if (found) {
- hash_del(&found->entry);
+ if (trans != SWITCHDEV_TRANS_PREPARE)
+ hash_del(&found->entry);
found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL;
}
- spin_unlock_irqrestore(&rocker->flow_tbl_lock, flags);
+ spin_unlock_irqrestore(&rocker->flow_tbl_lock, lock_flags);
- kfree(match);
+ rocker_port_kfree(trans, match);
if (found) {
- err = rocker_cmd_exec(rocker, rocker_port,
+ err = rocker_cmd_exec(rocker_port, trans, flags,
rocker_cmd_flow_tbl_del,
- found, NULL, NULL, nowait);
- kfree(found);
+ found, NULL, NULL);
+ rocker_port_kfree(trans, found);
}
return err;
}
-static gfp_t rocker_op_flags_gfp(int flags)
-{
- return flags & ROCKER_OP_FLAG_NOWAIT ? GFP_ATOMIC : GFP_KERNEL;
-}
-
static int rocker_flow_tbl_do(struct rocker_port *rocker_port,
- int flags, struct rocker_flow_tbl_entry *entry)
+ enum switchdev_trans trans, int flags,
+ struct rocker_flow_tbl_entry *entry)
{
- bool nowait = flags & ROCKER_OP_FLAG_NOWAIT;
-
if (flags & ROCKER_OP_FLAG_REMOVE)
- return rocker_flow_tbl_del(rocker_port, entry, nowait);
+ return rocker_flow_tbl_del(rocker_port, trans, flags, entry);
else
- return rocker_flow_tbl_add(rocker_port, entry, nowait);
+ return rocker_flow_tbl_add(rocker_port, trans, flags, entry);
}
static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port,
- int flags, u32 in_pport, u32 in_pport_mask,
+ enum switchdev_trans trans, int flags,
+ u32 in_pport, u32 in_pport_mask,
enum rocker_of_dpa_table_id goto_tbl)
{
struct rocker_flow_tbl_entry *entry;
- entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+ entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
@@ -2410,18 +2492,19 @@ static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port,
entry->key.ig_port.in_pport_mask = in_pport_mask;
entry->key.ig_port.goto_tbl = goto_tbl;
- return rocker_flow_tbl_do(rocker_port, flags, entry);
+ return rocker_flow_tbl_do(rocker_port, trans, flags, entry);
}
static int rocker_flow_tbl_vlan(struct rocker_port *rocker_port,
- int flags, u32 in_pport,
- __be16 vlan_id, __be16 vlan_id_mask,
+ enum switchdev_trans trans, int flags,
+ u32 in_pport, __be16 vlan_id,
+ __be16 vlan_id_mask,
enum rocker_of_dpa_table_id goto_tbl,
bool untagged, __be16 new_vlan_id)
{
struct rocker_flow_tbl_entry *entry;
- entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+ entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
@@ -2435,10 +2518,11 @@ static int rocker_flow_tbl_vlan(struct rocker_port *rocker_port,
entry->key.vlan.untagged = untagged;
entry->key.vlan.new_vlan_id = new_vlan_id;
- return rocker_flow_tbl_do(rocker_port, flags, entry);
+ return rocker_flow_tbl_do(rocker_port, trans, flags, entry);
}
static int rocker_flow_tbl_term_mac(struct rocker_port *rocker_port,
+ enum switchdev_trans trans,
u32 in_pport, u32 in_pport_mask,
__be16 eth_type, const u8 *eth_dst,
const u8 *eth_dst_mask, __be16 vlan_id,
@@ -2447,7 +2531,7 @@ static int rocker_flow_tbl_term_mac(struct rocker_port *rocker_port,
{
struct rocker_flow_tbl_entry *entry;
- entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+ entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
@@ -2471,11 +2555,11 @@ static int rocker_flow_tbl_term_mac(struct rocker_port *rocker_port,
entry->key.term_mac.vlan_id_mask = vlan_id_mask;
entry->key.term_mac.copy_to_cpu = copy_to_cpu;
- return rocker_flow_tbl_do(rocker_port, flags, entry);
+ return rocker_flow_tbl_do(rocker_port, trans, flags, entry);
}
static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port,
- int flags,
+ enum switchdev_trans trans, int flags,
const u8 *eth_dst, const u8 *eth_dst_mask,
__be16 vlan_id, u32 tunnel_id,
enum rocker_of_dpa_table_id goto_tbl,
@@ -2487,7 +2571,7 @@ static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port,
bool dflt = !eth_dst || (eth_dst && eth_dst_mask);
bool wild = false;
- entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+ entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
@@ -2500,7 +2584,7 @@ static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port,
if (eth_dst_mask) {
entry->key.bridge.has_eth_dst_mask = 1;
ether_addr_copy(entry->key.bridge.eth_dst_mask, eth_dst_mask);
- if (memcmp(eth_dst_mask, ff_mac, ETH_ALEN))
+ if (!ether_addr_equal(eth_dst_mask, ff_mac))
wild = true;
}
@@ -2525,10 +2609,11 @@ static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port,
entry->key.bridge.group_id = group_id;
entry->key.bridge.copy_to_cpu = copy_to_cpu;
- return rocker_flow_tbl_do(rocker_port, flags, entry);
+ return rocker_flow_tbl_do(rocker_port, trans, flags, entry);
}
static int rocker_flow_tbl_ucast4_routing(struct rocker_port *rocker_port,
+ enum switchdev_trans trans,
__be16 eth_type, __be32 dst,
__be32 dst_mask, u32 priority,
enum rocker_of_dpa_table_id goto_tbl,
@@ -2536,7 +2621,7 @@ static int rocker_flow_tbl_ucast4_routing(struct rocker_port *rocker_port,
{
struct rocker_flow_tbl_entry *entry;
- entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+ entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
@@ -2550,30 +2635,29 @@ static int rocker_flow_tbl_ucast4_routing(struct rocker_port *rocker_port,
entry->key_len = offsetof(struct rocker_flow_tbl_key,
ucast_routing.group_id);
- return rocker_flow_tbl_do(rocker_port, flags, entry);
+ return rocker_flow_tbl_do(rocker_port, trans, flags, entry);
}
static int rocker_flow_tbl_acl(struct rocker_port *rocker_port,
- int flags, u32 in_pport,
- u32 in_pport_mask,
+ enum switchdev_trans trans, int flags,
+ u32 in_pport, u32 in_pport_mask,
const u8 *eth_src, const u8 *eth_src_mask,
const u8 *eth_dst, const u8 *eth_dst_mask,
- __be16 eth_type,
- __be16 vlan_id, __be16 vlan_id_mask,
- u8 ip_proto, u8 ip_proto_mask,
- u8 ip_tos, u8 ip_tos_mask,
+ __be16 eth_type, __be16 vlan_id,
+ __be16 vlan_id_mask, u8 ip_proto,
+ u8 ip_proto_mask, u8 ip_tos, u8 ip_tos_mask,
u32 group_id)
{
u32 priority;
struct rocker_flow_tbl_entry *entry;
- entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+ entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
priority = ROCKER_PRIORITY_ACL_NORMAL;
if (eth_dst && eth_dst_mask) {
- if (memcmp(eth_dst_mask, mcast_mac, ETH_ALEN) == 0)
+ if (ether_addr_equal(eth_dst_mask, mcast_mac))
priority = ROCKER_PRIORITY_ACL_DFLT;
else if (is_link_local_ether_addr(eth_dst))
priority = ROCKER_PRIORITY_ACL_CTRL;
@@ -2602,12 +2686,12 @@ static int rocker_flow_tbl_acl(struct rocker_port *rocker_port,
entry->key.acl.ip_tos_mask = ip_tos_mask;
entry->key.acl.group_id = group_id;
- return rocker_flow_tbl_do(rocker_port, flags, entry);
+ return rocker_flow_tbl_do(rocker_port, trans, flags, entry);
}
static struct rocker_group_tbl_entry *
-rocker_group_tbl_find(struct rocker *rocker,
- struct rocker_group_tbl_entry *match)
+rocker_group_tbl_find(const struct rocker *rocker,
+ const struct rocker_group_tbl_entry *match)
{
struct rocker_group_tbl_entry *found;
@@ -2620,34 +2704,36 @@ rocker_group_tbl_find(struct rocker *rocker,
return NULL;
}
-static void rocker_group_tbl_entry_free(struct rocker_group_tbl_entry *entry)
+static void rocker_group_tbl_entry_free(enum switchdev_trans trans,
+ struct rocker_group_tbl_entry *entry)
{
switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) {
case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
- kfree(entry->group_ids);
+ rocker_port_kfree(trans, entry->group_ids);
break;
default:
break;
}
- kfree(entry);
+ rocker_port_kfree(trans, entry);
}
static int rocker_group_tbl_add(struct rocker_port *rocker_port,
- struct rocker_group_tbl_entry *match,
- bool nowait)
+ enum switchdev_trans trans, int flags,
+ struct rocker_group_tbl_entry *match)
{
struct rocker *rocker = rocker_port->rocker;
struct rocker_group_tbl_entry *found;
- unsigned long flags;
+ unsigned long lock_flags;
- spin_lock_irqsave(&rocker->group_tbl_lock, flags);
+ spin_lock_irqsave(&rocker->group_tbl_lock, lock_flags);
found = rocker_group_tbl_find(rocker, match);
if (found) {
- hash_del(&found->entry);
- rocker_group_tbl_entry_free(found);
+ if (trans != SWITCHDEV_TRANS_PREPARE)
+ hash_del(&found->entry);
+ rocker_group_tbl_entry_free(trans, found);
found = match;
found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD;
} else {
@@ -2655,116 +2741,118 @@ static int rocker_group_tbl_add(struct rocker_port *rocker_port,
found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD;
}
- hash_add(rocker->group_tbl, &found->entry, found->group_id);
+ if (trans != SWITCHDEV_TRANS_PREPARE)
+ hash_add(rocker->group_tbl, &found->entry, found->group_id);
- spin_unlock_irqrestore(&rocker->group_tbl_lock, flags);
+ spin_unlock_irqrestore(&rocker->group_tbl_lock, lock_flags);
- return rocker_cmd_exec(rocker, rocker_port,
- rocker_cmd_group_tbl_add,
- found, NULL, NULL, nowait);
+ return rocker_cmd_exec(rocker_port, trans, flags,
+ rocker_cmd_group_tbl_add, found, NULL, NULL);
}
static int rocker_group_tbl_del(struct rocker_port *rocker_port,
- struct rocker_group_tbl_entry *match,
- bool nowait)
+ enum switchdev_trans trans, int flags,
+ struct rocker_group_tbl_entry *match)
{
struct rocker *rocker = rocker_port->rocker;
struct rocker_group_tbl_entry *found;
- unsigned long flags;
+ unsigned long lock_flags;
int err = 0;
- spin_lock_irqsave(&rocker->group_tbl_lock, flags);
+ spin_lock_irqsave(&rocker->group_tbl_lock, lock_flags);
found = rocker_group_tbl_find(rocker, match);
if (found) {
- hash_del(&found->entry);
+ if (trans != SWITCHDEV_TRANS_PREPARE)
+ hash_del(&found->entry);
found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL;
}
- spin_unlock_irqrestore(&rocker->group_tbl_lock, flags);
+ spin_unlock_irqrestore(&rocker->group_tbl_lock, lock_flags);
- rocker_group_tbl_entry_free(match);
+ rocker_group_tbl_entry_free(trans, match);
if (found) {
- err = rocker_cmd_exec(rocker, rocker_port,
+ err = rocker_cmd_exec(rocker_port, trans, flags,
rocker_cmd_group_tbl_del,
- found, NULL, NULL, nowait);
- rocker_group_tbl_entry_free(found);
+ found, NULL, NULL);
+ rocker_group_tbl_entry_free(trans, found);
}
return err;
}
static int rocker_group_tbl_do(struct rocker_port *rocker_port,
- int flags, struct rocker_group_tbl_entry *entry)
+ enum switchdev_trans trans, int flags,
+ struct rocker_group_tbl_entry *entry)
{
- bool nowait = flags & ROCKER_OP_FLAG_NOWAIT;
-
if (flags & ROCKER_OP_FLAG_REMOVE)
- return rocker_group_tbl_del(rocker_port, entry, nowait);
+ return rocker_group_tbl_del(rocker_port, trans, flags, entry);
else
- return rocker_group_tbl_add(rocker_port, entry, nowait);
+ return rocker_group_tbl_add(rocker_port, trans, flags, entry);
}
static int rocker_group_l2_interface(struct rocker_port *rocker_port,
- int flags, __be16 vlan_id,
- u32 out_pport, int pop_vlan)
+ enum switchdev_trans trans, int flags,
+ __be16 vlan_id, u32 out_pport,
+ int pop_vlan)
{
struct rocker_group_tbl_entry *entry;
- entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+ entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
entry->group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
entry->l2_interface.pop_vlan = pop_vlan;
- return rocker_group_tbl_do(rocker_port, flags, entry);
+ return rocker_group_tbl_do(rocker_port, trans, flags, entry);
}
static int rocker_group_l2_fan_out(struct rocker_port *rocker_port,
+ enum switchdev_trans trans,
int flags, u8 group_count,
- u32 *group_ids, u32 group_id)
+ const u32 *group_ids, u32 group_id)
{
struct rocker_group_tbl_entry *entry;
- entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+ entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
entry->group_id = group_id;
entry->group_count = group_count;
- entry->group_ids = kcalloc(group_count, sizeof(u32),
- rocker_op_flags_gfp(flags));
+ entry->group_ids = rocker_port_kcalloc(rocker_port, trans, flags,
+ group_count, sizeof(u32));
if (!entry->group_ids) {
- kfree(entry);
+ rocker_port_kfree(trans, entry);
return -ENOMEM;
}
memcpy(entry->group_ids, group_ids, group_count * sizeof(u32));
- return rocker_group_tbl_do(rocker_port, flags, entry);
+ return rocker_group_tbl_do(rocker_port, trans, flags, entry);
}
static int rocker_group_l2_flood(struct rocker_port *rocker_port,
- int flags, __be16 vlan_id,
- u8 group_count, u32 *group_ids,
- u32 group_id)
+ enum switchdev_trans trans, int flags,
+ __be16 vlan_id, u8 group_count,
+ const u32 *group_ids, u32 group_id)
{
- return rocker_group_l2_fan_out(rocker_port, flags,
+ return rocker_group_l2_fan_out(rocker_port, trans, flags,
group_count, group_ids,
group_id);
}
static int rocker_group_l3_unicast(struct rocker_port *rocker_port,
- int flags, u32 index, u8 *src_mac,
- u8 *dst_mac, __be16 vlan_id,
- bool ttl_check, u32 pport)
+ enum switchdev_trans trans, int flags,
+ u32 index, const u8 *src_mac, const u8 *dst_mac,
+ __be16 vlan_id, bool ttl_check, u32 pport)
{
struct rocker_group_tbl_entry *entry;
- entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+ entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
@@ -2777,11 +2865,11 @@ static int rocker_group_l3_unicast(struct rocker_port *rocker_port,
entry->l3_unicast.ttl_check = ttl_check;
entry->l3_unicast.group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, pport);
- return rocker_group_tbl_do(rocker_port, flags, entry);
+ return rocker_group_tbl_do(rocker_port, trans, flags, entry);
}
static struct rocker_neigh_tbl_entry *
- rocker_neigh_tbl_find(struct rocker *rocker, __be32 ip_addr)
+rocker_neigh_tbl_find(const struct rocker *rocker, __be32 ip_addr)
{
struct rocker_neigh_tbl_entry *found;
@@ -2794,37 +2882,44 @@ static struct rocker_neigh_tbl_entry *
}
static void _rocker_neigh_add(struct rocker *rocker,
+ enum switchdev_trans trans,
struct rocker_neigh_tbl_entry *entry)
{
- entry->index = rocker->neigh_tbl_next_index++;
+ if (trans != SWITCHDEV_TRANS_COMMIT)
+ entry->index = rocker->neigh_tbl_next_index++;
+ if (trans == SWITCHDEV_TRANS_PREPARE)
+ return;
entry->ref_count++;
hash_add(rocker->neigh_tbl, &entry->entry,
be32_to_cpu(entry->ip_addr));
}
-static void _rocker_neigh_del(struct rocker *rocker,
+static void _rocker_neigh_del(enum switchdev_trans trans,
struct rocker_neigh_tbl_entry *entry)
{
+ if (trans == SWITCHDEV_TRANS_PREPARE)
+ return;
if (--entry->ref_count == 0) {
hash_del(&entry->entry);
- kfree(entry);
+ rocker_port_kfree(trans, entry);
}
}
-static void _rocker_neigh_update(struct rocker *rocker,
- struct rocker_neigh_tbl_entry *entry,
- u8 *eth_dst, bool ttl_check)
+static void _rocker_neigh_update(struct rocker_neigh_tbl_entry *entry,
+ enum switchdev_trans trans,
+ const u8 *eth_dst, bool ttl_check)
{
if (eth_dst) {
ether_addr_copy(entry->eth_dst, eth_dst);
entry->ttl_check = ttl_check;
- } else {
+ } else if (trans != SWITCHDEV_TRANS_PREPARE) {
entry->ref_count++;
}
}
static int rocker_port_ipv4_neigh(struct rocker_port *rocker_port,
- int flags, __be32 ip_addr, u8 *eth_dst)
+ enum switchdev_trans trans,
+ int flags, __be32 ip_addr, const u8 *eth_dst)
{
struct rocker *rocker = rocker_port->rocker;
struct rocker_neigh_tbl_entry *entry;
@@ -2840,7 +2935,7 @@ static int rocker_port_ipv4_neigh(struct rocker_port *rocker_port,
bool removing;
int err = 0;
- entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+ entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
@@ -2857,12 +2952,12 @@ static int rocker_port_ipv4_neigh(struct rocker_port *rocker_port,
entry->dev = rocker_port->dev;
ether_addr_copy(entry->eth_dst, eth_dst);
entry->ttl_check = true;
- _rocker_neigh_add(rocker, entry);
+ _rocker_neigh_add(rocker, trans, entry);
} else if (removing) {
memcpy(entry, found, sizeof(*entry));
- _rocker_neigh_del(rocker, found);
+ _rocker_neigh_del(trans, found);
} else if (updating) {
- _rocker_neigh_update(rocker, found, eth_dst, true);
+ _rocker_neigh_update(found, trans, eth_dst, true);
memcpy(entry, found, sizeof(*entry));
} else {
err = -ENOENT;
@@ -2879,7 +2974,7 @@ static int rocker_port_ipv4_neigh(struct rocker_port *rocker_port,
* other routes' nexthops.
*/
- err = rocker_group_l3_unicast(rocker_port, flags,
+ err = rocker_group_l3_unicast(rocker_port, trans, flags,
entry->index,
rocker_port->dev->dev_addr,
entry->eth_dst,
@@ -2895,7 +2990,7 @@ static int rocker_port_ipv4_neigh(struct rocker_port *rocker_port,
if (adding || removing) {
group_id = ROCKER_GROUP_L3_UNICAST(entry->index);
- err = rocker_flow_tbl_ucast4_routing(rocker_port,
+ err = rocker_flow_tbl_ucast4_routing(rocker_port, trans,
eth_type, ip_addr,
inet_make_mask(32),
priority, goto_tbl,
@@ -2909,13 +3004,13 @@ static int rocker_port_ipv4_neigh(struct rocker_port *rocker_port,
err_out:
if (!adding)
- kfree(entry);
+ rocker_port_kfree(trans, entry);
return err;
}
static int rocker_port_ipv4_resolve(struct rocker_port *rocker_port,
- __be32 ip_addr)
+ enum switchdev_trans trans, __be32 ip_addr)
{
struct net_device *dev = rocker_port->dev;
struct neighbour *n = __ipv4_neigh_lookup(dev, (__force u32)ip_addr);
@@ -2933,7 +3028,8 @@ static int rocker_port_ipv4_resolve(struct rocker_port *rocker_port,
*/
if (n->nud_state & NUD_VALID)
- err = rocker_port_ipv4_neigh(rocker_port, 0, ip_addr, n->ha);
+ err = rocker_port_ipv4_neigh(rocker_port, trans, 0,
+ ip_addr, n->ha);
else
neigh_event_send(n, NULL);
@@ -2941,7 +3037,8 @@ static int rocker_port_ipv4_resolve(struct rocker_port *rocker_port,
return err;
}
-static int rocker_port_ipv4_nh(struct rocker_port *rocker_port, int flags,
+static int rocker_port_ipv4_nh(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, int flags,
__be32 ip_addr, u32 *index)
{
struct rocker *rocker = rocker_port->rocker;
@@ -2954,7 +3051,7 @@ static int rocker_port_ipv4_nh(struct rocker_port *rocker_port, int flags,
bool resolved = true;
int err = 0;
- entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+ entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
if (!entry)
return -ENOMEM;
@@ -2971,13 +3068,13 @@ static int rocker_port_ipv4_nh(struct rocker_port *rocker_port, int flags,
if (adding) {
entry->ip_addr = ip_addr;
entry->dev = rocker_port->dev;
- _rocker_neigh_add(rocker, entry);
+ _rocker_neigh_add(rocker, trans, entry);
*index = entry->index;
resolved = false;
} else if (removing) {
- _rocker_neigh_del(rocker, found);
+ _rocker_neigh_del(trans, found);
} else if (updating) {
- _rocker_neigh_update(rocker, found, NULL, false);
+ _rocker_neigh_update(found, trans, NULL, false);
resolved = !is_zero_ether_addr(found->eth_dst);
} else {
err = -ENOENT;
@@ -2986,7 +3083,7 @@ static int rocker_port_ipv4_nh(struct rocker_port *rocker_port, int flags,
spin_unlock_irqrestore(&rocker->neigh_tbl_lock, lock_flags);
if (!adding)
- kfree(entry);
+ rocker_port_kfree(trans, entry);
if (err)
return err;
@@ -2994,24 +3091,25 @@ static int rocker_port_ipv4_nh(struct rocker_port *rocker_port, int flags,
/* Resolved means neigh ip_addr is resolved to neigh mac. */
if (!resolved)
- err = rocker_port_ipv4_resolve(rocker_port, ip_addr);
+ err = rocker_port_ipv4_resolve(rocker_port, trans, ip_addr);
return err;
}
static int rocker_port_vlan_flood_group(struct rocker_port *rocker_port,
+ enum switchdev_trans trans,
int flags, __be16 vlan_id)
{
struct rocker_port *p;
- struct rocker *rocker = rocker_port->rocker;
+ const struct rocker *rocker = rocker_port->rocker;
u32 group_id = ROCKER_GROUP_L2_FLOOD(vlan_id, 0);
u32 *group_ids;
u8 group_count = 0;
int err = 0;
int i;
- group_ids = kcalloc(rocker->port_count, sizeof(u32),
- rocker_op_flags_gfp(flags));
+ group_ids = rocker_port_kcalloc(rocker_port, trans, flags,
+ rocker->port_count, sizeof(u32));
if (!group_ids)
return -ENOMEM;
@@ -3022,6 +3120,8 @@ static int rocker_port_vlan_flood_group(struct rocker_port *rocker_port,
for (i = 0; i < rocker->port_count; i++) {
p = rocker->ports[i];
+ if (!p)
+ continue;
if (!rocker_port_is_bridged(p))
continue;
if (test_bit(ntohs(vlan_id), p->vlan_bitmap)) {
@@ -3034,23 +3134,22 @@ static int rocker_port_vlan_flood_group(struct rocker_port *rocker_port,
if (group_count == 0)
goto no_ports_in_vlan;
- err = rocker_group_l2_flood(rocker_port, flags, vlan_id,
- group_count, group_ids,
- group_id);
+ err = rocker_group_l2_flood(rocker_port, trans, flags, vlan_id,
+ group_count, group_ids, group_id);
if (err)
netdev_err(rocker_port->dev,
"Error (%d) port VLAN l2 flood group\n", err);
no_ports_in_vlan:
- kfree(group_ids);
+ rocker_port_kfree(trans, group_ids);
return err;
}
static int rocker_port_vlan_l2_groups(struct rocker_port *rocker_port,
- int flags, __be16 vlan_id,
- bool pop_vlan)
+ enum switchdev_trans trans, int flags,
+ __be16 vlan_id, bool pop_vlan)
{
- struct rocker *rocker = rocker_port->rocker;
+ const struct rocker *rocker = rocker_port->rocker;
struct rocker_port *p;
bool adding = !(flags & ROCKER_OP_FLAG_REMOVE);
u32 out_pport;
@@ -3065,9 +3164,8 @@ static int rocker_port_vlan_l2_groups(struct rocker_port *rocker_port,
if (rocker_port->stp_state == BR_STATE_LEARNING ||
rocker_port->stp_state == BR_STATE_FORWARDING) {
out_pport = rocker_port->pport;
- err = rocker_group_l2_interface(rocker_port, flags,
- vlan_id, out_pport,
- pop_vlan);
+ err = rocker_group_l2_interface(rocker_port, trans, flags,
+ vlan_id, out_pport, pop_vlan);
if (err) {
netdev_err(rocker_port->dev,
"Error (%d) port VLAN l2 group for pport %d\n",
@@ -3083,7 +3181,7 @@ static int rocker_port_vlan_l2_groups(struct rocker_port *rocker_port,
for (i = 0; i < rocker->port_count; i++) {
p = rocker->ports[i];
- if (test_bit(ntohs(vlan_id), p->vlan_bitmap))
+ if (p && test_bit(ntohs(vlan_id), p->vlan_bitmap))
ref++;
}
@@ -3091,9 +3189,8 @@ static int rocker_port_vlan_l2_groups(struct rocker_port *rocker_port,
return 0;
out_pport = 0;
- err = rocker_group_l2_interface(rocker_port, flags,
- vlan_id, out_pport,
- pop_vlan);
+ err = rocker_group_l2_interface(rocker_port, trans, flags,
+ vlan_id, out_pport, pop_vlan);
if (err) {
netdev_err(rocker_port->dev,
"Error (%d) port VLAN l2 group for CPU port\n", err);
@@ -3149,14 +3246,14 @@ static struct rocker_ctrl {
};
static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port,
- int flags, struct rocker_ctrl *ctrl,
- __be16 vlan_id)
+ enum switchdev_trans trans, int flags,
+ const struct rocker_ctrl *ctrl, __be16 vlan_id)
{
u32 in_pport = rocker_port->pport;
u32 in_pport_mask = 0xffffffff;
u32 out_pport = 0;
- u8 *eth_src = NULL;
- u8 *eth_src_mask = NULL;
+ const u8 *eth_src = NULL;
+ const u8 *eth_src_mask = NULL;
__be16 vlan_id_mask = htons(0xffff);
u8 ip_proto = 0;
u8 ip_proto_mask = 0;
@@ -3165,7 +3262,7 @@ static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port,
u32 group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
int err;
- err = rocker_flow_tbl_acl(rocker_port, flags,
+ err = rocker_flow_tbl_acl(rocker_port, trans, flags,
in_pport, in_pport_mask,
eth_src, eth_src_mask,
ctrl->eth_dst, ctrl->eth_dst_mask,
@@ -3182,7 +3279,8 @@ static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port,
}
static int rocker_port_ctrl_vlan_bridge(struct rocker_port *rocker_port,
- int flags, struct rocker_ctrl *ctrl,
+ enum switchdev_trans trans, int flags,
+ const struct rocker_ctrl *ctrl,
__be16 vlan_id)
{
enum rocker_of_dpa_table_id goto_tbl =
@@ -3194,7 +3292,7 @@ static int rocker_port_ctrl_vlan_bridge(struct rocker_port *rocker_port,
if (!rocker_port_is_bridged(rocker_port))
return 0;
- err = rocker_flow_tbl_bridge(rocker_port, flags,
+ err = rocker_flow_tbl_bridge(rocker_port, trans, flags,
ctrl->eth_dst, ctrl->eth_dst_mask,
vlan_id, tunnel_id,
goto_tbl, group_id, ctrl->copy_to_cpu);
@@ -3206,8 +3304,8 @@ static int rocker_port_ctrl_vlan_bridge(struct rocker_port *rocker_port,
}
static int rocker_port_ctrl_vlan_term(struct rocker_port *rocker_port,
- int flags, struct rocker_ctrl *ctrl,
- __be16 vlan_id)
+ enum switchdev_trans trans, int flags,
+ const struct rocker_ctrl *ctrl, __be16 vlan_id)
{
u32 in_pport_mask = 0xffffffff;
__be16 vlan_id_mask = htons(0xffff);
@@ -3216,7 +3314,7 @@ static int rocker_port_ctrl_vlan_term(struct rocker_port *rocker_port,
if (ntohs(vlan_id) == 0)
vlan_id = rocker_port->internal_vlan_id;
- err = rocker_flow_tbl_term_mac(rocker_port,
+ err = rocker_flow_tbl_term_mac(rocker_port, trans,
rocker_port->pport, in_pport_mask,
ctrl->eth_type, ctrl->eth_dst,
ctrl->eth_dst_mask, vlan_id,
@@ -3229,32 +3327,34 @@ static int rocker_port_ctrl_vlan_term(struct rocker_port *rocker_port,
return err;
}
-static int rocker_port_ctrl_vlan(struct rocker_port *rocker_port, int flags,
- struct rocker_ctrl *ctrl, __be16 vlan_id)
+static int rocker_port_ctrl_vlan(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, int flags,
+ const struct rocker_ctrl *ctrl, __be16 vlan_id)
{
if (ctrl->acl)
- return rocker_port_ctrl_vlan_acl(rocker_port, flags,
+ return rocker_port_ctrl_vlan_acl(rocker_port, trans, flags,
ctrl, vlan_id);
if (ctrl->bridge)
- return rocker_port_ctrl_vlan_bridge(rocker_port, flags,
+ return rocker_port_ctrl_vlan_bridge(rocker_port, trans, flags,
ctrl, vlan_id);
if (ctrl->term)
- return rocker_port_ctrl_vlan_term(rocker_port, flags,
+ return rocker_port_ctrl_vlan_term(rocker_port, trans, flags,
ctrl, vlan_id);
return -EOPNOTSUPP;
}
static int rocker_port_ctrl_vlan_add(struct rocker_port *rocker_port,
- int flags, __be16 vlan_id)
+ enum switchdev_trans trans, int flags,
+ __be16 vlan_id)
{
int err = 0;
int i;
for (i = 0; i < ROCKER_CTRL_MAX; i++) {
if (rocker_port->ctrls[i]) {
- err = rocker_port_ctrl_vlan(rocker_port, flags,
+ err = rocker_port_ctrl_vlan(rocker_port, trans, flags,
&rocker_ctrls[i], vlan_id);
if (err)
return err;
@@ -3264,8 +3364,9 @@ static int rocker_port_ctrl_vlan_add(struct rocker_port *rocker_port,
return err;
}
-static int rocker_port_ctrl(struct rocker_port *rocker_port, int flags,
- struct rocker_ctrl *ctrl)
+static int rocker_port_ctrl(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, int flags,
+ const struct rocker_ctrl *ctrl)
{
u16 vid;
int err = 0;
@@ -3273,7 +3374,7 @@ static int rocker_port_ctrl(struct rocker_port *rocker_port, int flags,
for (vid = 1; vid < VLAN_N_VID; vid++) {
if (!test_bit(vid, rocker_port->vlan_bitmap))
continue;
- err = rocker_port_ctrl_vlan(rocker_port, flags,
+ err = rocker_port_ctrl_vlan(rocker_port, trans, flags,
ctrl, htons(vid));
if (err)
break;
@@ -3282,8 +3383,8 @@ static int rocker_port_ctrl(struct rocker_port *rocker_port, int flags,
return err;
}
-static int rocker_port_vlan(struct rocker_port *rocker_port, int flags,
- u16 vid)
+static int rocker_port_vlan(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, int flags, u16 vid)
{
enum rocker_of_dpa_table_id goto_tbl =
ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
@@ -3297,50 +3398,57 @@ static int rocker_port_vlan(struct rocker_port *rocker_port, int flags,
internal_vlan_id = rocker_port_vid_to_vlan(rocker_port, vid, &untagged);
- if (adding && test_and_set_bit(ntohs(internal_vlan_id),
- rocker_port->vlan_bitmap))
+ if (adding && test_bit(ntohs(internal_vlan_id),
+ rocker_port->vlan_bitmap))
return 0; /* already added */
- else if (!adding && !test_and_clear_bit(ntohs(internal_vlan_id),
- rocker_port->vlan_bitmap))
+ else if (!adding && !test_bit(ntohs(internal_vlan_id),
+ rocker_port->vlan_bitmap))
return 0; /* already removed */
+ change_bit(ntohs(internal_vlan_id), rocker_port->vlan_bitmap);
+
if (adding) {
- err = rocker_port_ctrl_vlan_add(rocker_port, flags,
+ err = rocker_port_ctrl_vlan_add(rocker_port, trans, flags,
internal_vlan_id);
if (err) {
netdev_err(rocker_port->dev,
"Error (%d) port ctrl vlan add\n", err);
- return err;
+ goto err_out;
}
}
- err = rocker_port_vlan_l2_groups(rocker_port, flags,
+ err = rocker_port_vlan_l2_groups(rocker_port, trans, flags,
internal_vlan_id, untagged);
if (err) {
netdev_err(rocker_port->dev,
"Error (%d) port VLAN l2 groups\n", err);
- return err;
+ goto err_out;
}
- err = rocker_port_vlan_flood_group(rocker_port, flags,
+ err = rocker_port_vlan_flood_group(rocker_port, trans, flags,
internal_vlan_id);
if (err) {
netdev_err(rocker_port->dev,
"Error (%d) port VLAN l2 flood group\n", err);
- return err;
+ goto err_out;
}
- err = rocker_flow_tbl_vlan(rocker_port, flags,
+ err = rocker_flow_tbl_vlan(rocker_port, trans, flags,
in_pport, vlan_id, vlan_id_mask,
goto_tbl, untagged, internal_vlan_id);
if (err)
netdev_err(rocker_port->dev,
"Error (%d) port VLAN table\n", err);
+err_out:
+ if (trans == SWITCHDEV_TRANS_PREPARE)
+ change_bit(ntohs(internal_vlan_id), rocker_port->vlan_bitmap);
+
return err;
}
-static int rocker_port_ig_tbl(struct rocker_port *rocker_port, int flags)
+static int rocker_port_ig_tbl(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, int flags)
{
enum rocker_of_dpa_table_id goto_tbl;
u32 in_pport;
@@ -3355,7 +3463,7 @@ static int rocker_port_ig_tbl(struct rocker_port *rocker_port, int flags)
in_pport_mask = 0xffff0000;
goto_tbl = ROCKER_OF_DPA_TABLE_ID_VLAN;
- err = rocker_flow_tbl_ig_port(rocker_port, flags,
+ err = rocker_flow_tbl_ig_port(rocker_port, trans, flags,
in_pport, in_pport_mask,
goto_tbl);
if (err)
@@ -3367,7 +3475,8 @@ static int rocker_port_ig_tbl(struct rocker_port *rocker_port, int flags)
struct rocker_fdb_learn_work {
struct work_struct work;
- struct net_device *dev;
+ struct rocker_port *rocker_port;
+ enum switchdev_trans trans;
int flags;
u8 addr[ETH_ALEN];
u16 vid;
@@ -3375,27 +3484,28 @@ struct rocker_fdb_learn_work {
static void rocker_port_fdb_learn_work(struct work_struct *work)
{
- struct rocker_fdb_learn_work *lw =
+ const struct rocker_fdb_learn_work *lw =
container_of(work, struct rocker_fdb_learn_work, work);
bool removing = (lw->flags & ROCKER_OP_FLAG_REMOVE);
bool learned = (lw->flags & ROCKER_OP_FLAG_LEARNED);
- struct netdev_switch_notifier_fdb_info info;
+ struct switchdev_notifier_fdb_info info;
info.addr = lw->addr;
info.vid = lw->vid;
if (learned && removing)
- call_netdev_switch_notifiers(NETDEV_SWITCH_FDB_DEL,
- lw->dev, &info.info);
+ call_switchdev_notifiers(SWITCHDEV_FDB_DEL,
+ lw->rocker_port->dev, &info.info);
else if (learned && !removing)
- call_netdev_switch_notifiers(NETDEV_SWITCH_FDB_ADD,
- lw->dev, &info.info);
+ call_switchdev_notifiers(SWITCHDEV_FDB_ADD,
+ lw->rocker_port->dev, &info.info);
- kfree(work);
+ rocker_port_kfree(lw->trans, work);
}
static int rocker_port_fdb_learn(struct rocker_port *rocker_port,
- int flags, const u8 *addr, __be16 vlan_id)
+ enum switchdev_trans trans, int flags,
+ const u8 *addr, __be16 vlan_id)
{
struct rocker_fdb_learn_work *lw;
enum rocker_of_dpa_table_id goto_tbl =
@@ -3411,8 +3521,8 @@ static int rocker_port_fdb_learn(struct rocker_port *rocker_port,
group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
if (!(flags & ROCKER_OP_FLAG_REFRESH)) {
- err = rocker_flow_tbl_bridge(rocker_port, flags, addr, NULL,
- vlan_id, tunnel_id, goto_tbl,
+ err = rocker_flow_tbl_bridge(rocker_port, trans, flags, addr,
+ NULL, vlan_id, tunnel_id, goto_tbl,
group_id, copy_to_cpu);
if (err)
return err;
@@ -3424,24 +3534,29 @@ static int rocker_port_fdb_learn(struct rocker_port *rocker_port,
if (!rocker_port_is_bridged(rocker_port))
return 0;
- lw = kmalloc(sizeof(*lw), rocker_op_flags_gfp(flags));
+ lw = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*lw));
if (!lw)
return -ENOMEM;
INIT_WORK(&lw->work, rocker_port_fdb_learn_work);
- lw->dev = rocker_port->dev;
+ lw->rocker_port = rocker_port;
+ lw->trans = trans;
lw->flags = flags;
ether_addr_copy(lw->addr, addr);
lw->vid = rocker_port_vlan_to_vid(rocker_port, vlan_id);
- schedule_work(&lw->work);
+ if (trans == SWITCHDEV_TRANS_PREPARE)
+ rocker_port_kfree(trans, lw);
+ else
+ schedule_work(&lw->work);
return 0;
}
static struct rocker_fdb_tbl_entry *
-rocker_fdb_tbl_find(struct rocker *rocker, struct rocker_fdb_tbl_entry *match)
+rocker_fdb_tbl_find(const struct rocker *rocker,
+ const struct rocker_fdb_tbl_entry *match)
{
struct rocker_fdb_tbl_entry *found;
@@ -3453,6 +3568,7 @@ rocker_fdb_tbl_find(struct rocker *rocker, struct rocker_fdb_tbl_entry *match)
}
static int rocker_port_fdb(struct rocker_port *rocker_port,
+ enum switchdev_trans trans,
const unsigned char *addr,
__be16 vlan_id, int flags)
{
@@ -3462,7 +3578,7 @@ static int rocker_port_fdb(struct rocker_port *rocker_port,
bool removing = (flags & ROCKER_OP_FLAG_REMOVE);
unsigned long lock_flags;
- fdb = kzalloc(sizeof(*fdb), rocker_op_flags_gfp(flags));
+ fdb = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*fdb));
if (!fdb)
return -ENOMEM;
@@ -3477,32 +3593,34 @@ static int rocker_port_fdb(struct rocker_port *rocker_port,
found = rocker_fdb_tbl_find(rocker, fdb);
if (removing && found) {
- kfree(fdb);
- hash_del(&found->entry);
+ rocker_port_kfree(trans, fdb);
+ if (trans != SWITCHDEV_TRANS_PREPARE)
+ hash_del(&found->entry);
} else if (!removing && !found) {
- hash_add(rocker->fdb_tbl, &fdb->entry, fdb->key_crc32);
+ if (trans != SWITCHDEV_TRANS_PREPARE)
+ hash_add(rocker->fdb_tbl, &fdb->entry, fdb->key_crc32);
}
spin_unlock_irqrestore(&rocker->fdb_tbl_lock, lock_flags);
/* Check if adding and already exists, or removing and can't find */
if (!found != !removing) {
- kfree(fdb);
+ rocker_port_kfree(trans, fdb);
if (!found && removing)
return 0;
/* Refreshing existing to update aging timers */
flags |= ROCKER_OP_FLAG_REFRESH;
}
- return rocker_port_fdb_learn(rocker_port, flags, addr, vlan_id);
+ return rocker_port_fdb_learn(rocker_port, trans, flags, addr, vlan_id);
}
-static int rocker_port_fdb_flush(struct rocker_port *rocker_port)
+static int rocker_port_fdb_flush(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, int flags)
{
struct rocker *rocker = rocker_port->rocker;
struct rocker_fdb_tbl_entry *found;
unsigned long lock_flags;
- int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_REMOVE;
struct hlist_node *tmp;
int bkt;
int err = 0;
@@ -3511,6 +3629,8 @@ static int rocker_port_fdb_flush(struct rocker_port *rocker_port)
rocker_port->stp_state == BR_STATE_FORWARDING)
return 0;
+ flags |= ROCKER_OP_FLAG_REMOVE;
+
spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags);
hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) {
@@ -3518,12 +3638,13 @@ static int rocker_port_fdb_flush(struct rocker_port *rocker_port)
continue;
if (!found->learned)
continue;
- err = rocker_port_fdb_learn(rocker_port, flags,
+ err = rocker_port_fdb_learn(rocker_port, trans, flags,
found->key.addr,
found->key.vlan_id);
if (err)
goto err_out;
- hash_del(&found->entry);
+ if (trans != SWITCHDEV_TRANS_PREPARE)
+ hash_del(&found->entry);
}
err_out:
@@ -3533,7 +3654,8 @@ err_out:
}
static int rocker_port_router_mac(struct rocker_port *rocker_port,
- int flags, __be16 vlan_id)
+ enum switchdev_trans trans, int flags,
+ __be16 vlan_id)
{
u32 in_pport_mask = 0xffffffff;
__be16 eth_type;
@@ -3546,7 +3668,7 @@ static int rocker_port_router_mac(struct rocker_port *rocker_port,
vlan_id = rocker_port->internal_vlan_id;
eth_type = htons(ETH_P_IP);
- err = rocker_flow_tbl_term_mac(rocker_port,
+ err = rocker_flow_tbl_term_mac(rocker_port, trans,
rocker_port->pport, in_pport_mask,
eth_type, rocker_port->dev->dev_addr,
dst_mac_mask, vlan_id, vlan_id_mask,
@@ -3555,7 +3677,7 @@ static int rocker_port_router_mac(struct rocker_port *rocker_port,
return err;
eth_type = htons(ETH_P_IPV6);
- err = rocker_flow_tbl_term_mac(rocker_port,
+ err = rocker_flow_tbl_term_mac(rocker_port, trans,
rocker_port->pport, in_pport_mask,
eth_type, rocker_port->dev->dev_addr,
dst_mac_mask, vlan_id, vlan_id_mask,
@@ -3564,13 +3686,13 @@ static int rocker_port_router_mac(struct rocker_port *rocker_port,
return err;
}
-static int rocker_port_fwding(struct rocker_port *rocker_port)
+static int rocker_port_fwding(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, int flags)
{
bool pop_vlan;
u32 out_pport;
__be16 vlan_id;
u16 vid;
- int flags = ROCKER_OP_FLAG_NOWAIT;
int err;
/* Port will be forwarding-enabled if its STP state is LEARNING
@@ -3590,9 +3712,8 @@ static int rocker_port_fwding(struct rocker_port *rocker_port)
continue;
vlan_id = htons(vid);
pop_vlan = rocker_vlan_id_is_internal(vlan_id);
- err = rocker_group_l2_interface(rocker_port, flags,
- vlan_id, out_pport,
- pop_vlan);
+ err = rocker_group_l2_interface(rocker_port, trans, flags,
+ vlan_id, out_pport, pop_vlan);
if (err) {
netdev_err(rocker_port->dev,
"Error (%d) port VLAN l2 group for pport %d\n",
@@ -3604,13 +3725,21 @@ static int rocker_port_fwding(struct rocker_port *rocker_port)
return 0;
}
-static int rocker_port_stp_update(struct rocker_port *rocker_port, u8 state)
+static int rocker_port_stp_update(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, int flags,
+ u8 state)
{
bool want[ROCKER_CTRL_MAX] = { 0, };
- int flags;
+ bool prev_ctrls[ROCKER_CTRL_MAX];
+ u8 prev_state;
int err;
int i;
+ if (trans == SWITCHDEV_TRANS_PREPARE) {
+ memcpy(prev_ctrls, rocker_port->ctrls, sizeof(prev_ctrls));
+ prev_state = rocker_port->stp_state;
+ }
+
if (rocker_port->stp_state == state)
return 0;
@@ -3638,45 +3767,57 @@ static int rocker_port_stp_update(struct rocker_port *rocker_port, u8 state)
for (i = 0; i < ROCKER_CTRL_MAX; i++) {
if (want[i] != rocker_port->ctrls[i]) {
- flags = ROCKER_OP_FLAG_NOWAIT |
- (want[i] ? 0 : ROCKER_OP_FLAG_REMOVE);
- err = rocker_port_ctrl(rocker_port, flags,
+ int ctrl_flags = flags |
+ (want[i] ? 0 : ROCKER_OP_FLAG_REMOVE);
+ err = rocker_port_ctrl(rocker_port, trans, ctrl_flags,
&rocker_ctrls[i]);
if (err)
- return err;
+ goto err_out;
rocker_port->ctrls[i] = want[i];
}
}
- err = rocker_port_fdb_flush(rocker_port);
+ err = rocker_port_fdb_flush(rocker_port, trans, flags);
if (err)
- return err;
+ goto err_out;
+
+ err = rocker_port_fwding(rocker_port, trans, flags);
+
+err_out:
+ if (trans == SWITCHDEV_TRANS_PREPARE) {
+ memcpy(rocker_port->ctrls, prev_ctrls, sizeof(prev_ctrls));
+ rocker_port->stp_state = prev_state;
+ }
- return rocker_port_fwding(rocker_port);
+ return err;
}
-static int rocker_port_fwd_enable(struct rocker_port *rocker_port)
+static int rocker_port_fwd_enable(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, int flags)
{
if (rocker_port_is_bridged(rocker_port))
/* bridge STP will enable port */
return 0;
/* port is not bridged, so simulate going to FORWARDING state */
- return rocker_port_stp_update(rocker_port, BR_STATE_FORWARDING);
+ return rocker_port_stp_update(rocker_port, trans, flags,
+ BR_STATE_FORWARDING);
}
-static int rocker_port_fwd_disable(struct rocker_port *rocker_port)
+static int rocker_port_fwd_disable(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, int flags)
{
if (rocker_port_is_bridged(rocker_port))
/* bridge STP will disable port */
return 0;
/* port is not bridged, so simulate going to DISABLED state */
- return rocker_port_stp_update(rocker_port, BR_STATE_DISABLED);
+ return rocker_port_stp_update(rocker_port, trans, flags,
+ BR_STATE_DISABLED);
}
static struct rocker_internal_vlan_tbl_entry *
-rocker_internal_vlan_tbl_find(struct rocker *rocker, int ifindex)
+rocker_internal_vlan_tbl_find(const struct rocker *rocker, int ifindex)
{
struct rocker_internal_vlan_tbl_entry *found;
@@ -3731,8 +3872,9 @@ found:
return found->vlan_id;
}
-static void rocker_port_internal_vlan_id_put(struct rocker_port *rocker_port,
- int ifindex)
+static void
+rocker_port_internal_vlan_id_put(const struct rocker_port *rocker_port,
+ int ifindex)
{
struct rocker *rocker = rocker_port->rocker;
struct rocker_internal_vlan_tbl_entry *found;
@@ -3760,11 +3902,12 @@ not_found:
spin_unlock_irqrestore(&rocker->internal_vlan_tbl_lock, lock_flags);
}
-static int rocker_port_fib_ipv4(struct rocker_port *rocker_port, __be32 dst,
- int dst_len, struct fib_info *fi, u32 tb_id,
- int flags)
+static int rocker_port_fib_ipv4(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, __be32 dst,
+ int dst_len, const struct fib_info *fi,
+ u32 tb_id, int flags)
{
- struct fib_nh *nh;
+ const struct fib_nh *nh;
__be16 eth_type = htons(ETH_P_IP);
__be32 dst_mask = inet_make_mask(dst_len);
__be16 internal_vlan_id = rocker_port->internal_vlan_id;
@@ -3784,7 +3927,7 @@ static int rocker_port_fib_ipv4(struct rocker_port *rocker_port, __be32 dst,
has_gw = !!nh->nh_gw;
if (has_gw && nh_on_port) {
- err = rocker_port_ipv4_nh(rocker_port, flags,
+ err = rocker_port_ipv4_nh(rocker_port, trans, flags,
nh->nh_gw, &index);
if (err)
return err;
@@ -3795,7 +3938,7 @@ static int rocker_port_fib_ipv4(struct rocker_port *rocker_port, __be32 dst,
group_id = ROCKER_GROUP_L2_INTERFACE(internal_vlan_id, 0);
}
- err = rocker_flow_tbl_ucast4_routing(rocker_port, eth_type, dst,
+ err = rocker_flow_tbl_ucast4_routing(rocker_port, trans, eth_type, dst,
dst_mask, priority, goto_tbl,
group_id, flags);
if (err)
@@ -3834,7 +3977,7 @@ static int rocker_port_open(struct net_device *dev)
goto err_request_rx_irq;
}
- err = rocker_port_fwd_enable(rocker_port);
+ err = rocker_port_fwd_enable(rocker_port, SWITCHDEV_TRANS_NONE, 0);
if (err)
goto err_fwd_enable;
@@ -3861,7 +4004,8 @@ static int rocker_port_stop(struct net_device *dev)
rocker_port_set_enable(rocker_port, false);
napi_disable(&rocker_port->napi_rx);
napi_disable(&rocker_port->napi_tx);
- rocker_port_fwd_disable(rocker_port);
+ rocker_port_fwd_disable(rocker_port, SWITCHDEV_TRANS_NONE,
+ ROCKER_OP_FLAG_NOWAIT);
free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
free_irq(rocker_msix_tx_vector(rocker_port), rocker_port);
rocker_port_dma_rings_fini(rocker_port);
@@ -3869,12 +4013,12 @@ static int rocker_port_stop(struct net_device *dev)
return 0;
}
-static void rocker_tx_desc_frags_unmap(struct rocker_port *rocker_port,
- struct rocker_desc_info *desc_info)
+static void rocker_tx_desc_frags_unmap(const struct rocker_port *rocker_port,
+ const struct rocker_desc_info *desc_info)
{
- struct rocker *rocker = rocker_port->rocker;
+ const struct rocker *rocker = rocker_port->rocker;
struct pci_dev *pdev = rocker->pdev;
- struct rocker_tlv *attrs[ROCKER_TLV_TX_MAX + 1];
+ const struct rocker_tlv *attrs[ROCKER_TLV_TX_MAX + 1];
struct rocker_tlv *attr;
int rem;
@@ -3882,7 +4026,7 @@ static void rocker_tx_desc_frags_unmap(struct rocker_port *rocker_port,
if (!attrs[ROCKER_TLV_TX_FRAGS])
return;
rocker_tlv_for_each_nested(attr, attrs[ROCKER_TLV_TX_FRAGS], rem) {
- struct rocker_tlv *frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_MAX + 1];
+ const struct rocker_tlv *frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_MAX + 1];
dma_addr_t dma_handle;
size_t len;
@@ -3899,11 +4043,11 @@ static void rocker_tx_desc_frags_unmap(struct rocker_port *rocker_port,
}
}
-static int rocker_tx_desc_frag_map_put(struct rocker_port *rocker_port,
+static int rocker_tx_desc_frag_map_put(const struct rocker_port *rocker_port,
struct rocker_desc_info *desc_info,
char *buf, size_t buf_len)
{
- struct rocker *rocker = rocker_port->rocker;
+ const struct rocker *rocker = rocker_port->rocker;
struct pci_dev *pdev = rocker->pdev;
dma_addr_t dma_handle;
struct rocker_tlv *frag;
@@ -4008,269 +4152,359 @@ static int rocker_port_set_mac_address(struct net_device *dev, void *p)
return 0;
}
-static int rocker_port_vlan_rx_add_vid(struct net_device *dev,
- __be16 proto, u16 vid)
+static int rocker_port_get_phys_port_name(struct net_device *dev,
+ char *buf, size_t len)
{
struct rocker_port *rocker_port = netdev_priv(dev);
+ struct port_name name = { .buf = buf, .len = len };
int err;
- err = rocker_port_vlan(rocker_port, 0, vid);
- if (err)
- return err;
+ err = rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
+ rocker_cmd_get_port_settings_prep, NULL,
+ rocker_cmd_get_port_settings_phys_name_proc,
+ &name);
- return rocker_port_router_mac(rocker_port, 0, htons(vid));
+ return err ? -EOPNOTSUPP : 0;
}
-static int rocker_port_vlan_rx_kill_vid(struct net_device *dev,
- __be16 proto, u16 vid)
+static const struct net_device_ops rocker_port_netdev_ops = {
+ .ndo_open = rocker_port_open,
+ .ndo_stop = rocker_port_stop,
+ .ndo_start_xmit = rocker_port_xmit,
+ .ndo_set_mac_address = rocker_port_set_mac_address,
+ .ndo_bridge_getlink = switchdev_port_bridge_getlink,
+ .ndo_bridge_setlink = switchdev_port_bridge_setlink,
+ .ndo_bridge_dellink = switchdev_port_bridge_dellink,
+ .ndo_fdb_add = switchdev_port_fdb_add,
+ .ndo_fdb_del = switchdev_port_fdb_del,
+ .ndo_fdb_dump = switchdev_port_fdb_dump,
+ .ndo_get_phys_port_name = rocker_port_get_phys_port_name,
+};
+
+/********************
+ * swdev interface
+ ********************/
+
+static int rocker_port_attr_get(struct net_device *dev,
+ struct switchdev_attr *attr)
{
- struct rocker_port *rocker_port = netdev_priv(dev);
- int err;
+ const struct rocker_port *rocker_port = netdev_priv(dev);
+ const struct rocker *rocker = rocker_port->rocker;
- err = rocker_port_router_mac(rocker_port, ROCKER_OP_FLAG_REMOVE,
- htons(vid));
- if (err)
- return err;
+ switch (attr->id) {
+ case SWITCHDEV_ATTR_PORT_PARENT_ID:
+ attr->u.ppid.id_len = sizeof(rocker->hw.id);
+ memcpy(&attr->u.ppid.id, &rocker->hw.id, attr->u.ppid.id_len);
+ break;
+ case SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS:
+ attr->u.brport_flags = rocker_port->brport_flags;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
- return rocker_port_vlan(rocker_port, ROCKER_OP_FLAG_REMOVE, vid);
+ return 0;
}
-static int rocker_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
- struct net_device *dev,
- const unsigned char *addr, u16 vid,
- u16 nlm_flags)
+static void rocker_port_trans_abort(const struct rocker_port *rocker_port)
{
- struct rocker_port *rocker_port = netdev_priv(dev);
- __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, vid, NULL);
- int flags = 0;
-
- if (!rocker_port_is_bridged(rocker_port))
- return -EINVAL;
+ struct list_head *mem, *tmp;
- return rocker_port_fdb(rocker_port, addr, vlan_id, flags);
+ list_for_each_safe(mem, tmp, &rocker_port->trans_mem) {
+ list_del(mem);
+ kfree(mem);
+ }
}
-static int rocker_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
- struct net_device *dev,
- const unsigned char *addr, u16 vid)
+static int rocker_port_brport_flags_set(struct rocker_port *rocker_port,
+ enum switchdev_trans trans,
+ unsigned long brport_flags)
{
- struct rocker_port *rocker_port = netdev_priv(dev);
- __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, vid, NULL);
- int flags = ROCKER_OP_FLAG_REMOVE;
+ unsigned long orig_flags;
+ int err = 0;
- if (!rocker_port_is_bridged(rocker_port))
- return -EINVAL;
+ orig_flags = rocker_port->brport_flags;
+ rocker_port->brport_flags = brport_flags;
+ if ((orig_flags ^ rocker_port->brport_flags) & BR_LEARNING)
+ err = rocker_port_set_learning(rocker_port, trans);
- return rocker_port_fdb(rocker_port, addr, vlan_id, flags);
+ if (trans == SWITCHDEV_TRANS_PREPARE)
+ rocker_port->brport_flags = orig_flags;
+
+ return err;
}
-static int rocker_fdb_fill_info(struct sk_buff *skb,
- struct rocker_port *rocker_port,
- const unsigned char *addr, u16 vid,
- u32 portid, u32 seq, int type,
- unsigned int flags)
+static int rocker_port_attr_set(struct net_device *dev,
+ struct switchdev_attr *attr)
{
- struct nlmsghdr *nlh;
- struct ndmsg *ndm;
+ struct rocker_port *rocker_port = netdev_priv(dev);
+ int err = 0;
- nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags);
- if (!nlh)
- return -EMSGSIZE;
+ switch (attr->trans) {
+ case SWITCHDEV_TRANS_PREPARE:
+ BUG_ON(!list_empty(&rocker_port->trans_mem));
+ break;
+ case SWITCHDEV_TRANS_ABORT:
+ rocker_port_trans_abort(rocker_port);
+ return 0;
+ default:
+ break;
+ }
- ndm = nlmsg_data(nlh);
- ndm->ndm_family = AF_BRIDGE;
- ndm->ndm_pad1 = 0;
- ndm->ndm_pad2 = 0;
- ndm->ndm_flags = NTF_SELF;
- ndm->ndm_type = 0;
- ndm->ndm_ifindex = rocker_port->dev->ifindex;
- ndm->ndm_state = NUD_REACHABLE;
+ switch (attr->id) {
+ case SWITCHDEV_ATTR_PORT_STP_STATE:
+ err = rocker_port_stp_update(rocker_port, attr->trans,
+ ROCKER_OP_FLAG_NOWAIT,
+ attr->u.stp_state);
+ break;
+ case SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS:
+ err = rocker_port_brport_flags_set(rocker_port, attr->trans,
+ attr->u.brport_flags);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
- if (nla_put(skb, NDA_LLADDR, ETH_ALEN, addr))
- goto nla_put_failure;
+ return err;
+}
- if (vid && nla_put_u16(skb, NDA_VLAN, vid))
- goto nla_put_failure;
+static int rocker_port_vlan_add(struct rocker_port *rocker_port,
+ enum switchdev_trans trans, u16 vid, u16 flags)
+{
+ int err;
- nlmsg_end(skb, nlh);
- return 0;
+ /* XXX deal with flags for PVID and untagged */
-nla_put_failure:
- nlmsg_cancel(skb, nlh);
- return -EMSGSIZE;
+ err = rocker_port_vlan(rocker_port, trans, 0, vid);
+ if (err)
+ return err;
+
+ err = rocker_port_router_mac(rocker_port, trans, 0, htons(vid));
+ if (err)
+ rocker_port_vlan(rocker_port, trans,
+ ROCKER_OP_FLAG_REMOVE, vid);
+
+ return err;
}
-static int rocker_port_fdb_dump(struct sk_buff *skb,
- struct netlink_callback *cb,
- struct net_device *dev,
- struct net_device *filter_dev,
- int idx)
+static int rocker_port_vlans_add(struct rocker_port *rocker_port,
+ enum switchdev_trans trans,
+ const struct switchdev_obj_vlan *vlan)
{
- struct rocker_port *rocker_port = netdev_priv(dev);
- struct rocker *rocker = rocker_port->rocker;
- struct rocker_fdb_tbl_entry *found;
- struct hlist_node *tmp;
- int bkt;
- unsigned long lock_flags;
- const unsigned char *addr;
u16 vid;
int err;
- spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags);
- hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) {
- if (found->key.pport != rocker_port->pport)
- continue;
- if (idx < cb->args[0])
- goto skip;
- addr = found->key.addr;
- vid = rocker_port_vlan_to_vid(rocker_port, found->key.vlan_id);
- err = rocker_fdb_fill_info(skb, rocker_port, addr, vid,
- NETLINK_CB(cb->skb).portid,
- cb->nlh->nlmsg_seq,
- RTM_NEWNEIGH, NLM_F_MULTI);
- if (err < 0)
- break;
-skip:
- ++idx;
+ for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
+ err = rocker_port_vlan_add(rocker_port, trans,
+ vid, vlan->flags);
+ if (err)
+ return err;
}
- spin_unlock_irqrestore(&rocker->fdb_tbl_lock, lock_flags);
- return idx;
+
+ return 0;
}
-static int rocker_port_bridge_setlink(struct net_device *dev,
- struct nlmsghdr *nlh, u16 flags)
+static int rocker_port_fdb_add(struct rocker_port *rocker_port,
+ enum switchdev_trans trans,
+ const struct switchdev_obj_fdb *fdb)
+{
+ __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL);
+ int flags = 0;
+
+ if (!rocker_port_is_bridged(rocker_port))
+ return -EINVAL;
+
+ return rocker_port_fdb(rocker_port, trans, fdb->addr, vlan_id, flags);
+}
+
+static int rocker_port_obj_add(struct net_device *dev,
+ struct switchdev_obj *obj)
{
struct rocker_port *rocker_port = netdev_priv(dev);
- struct nlattr *protinfo;
- struct nlattr *attr;
- int err;
+ const struct switchdev_obj_ipv4_fib *fib4;
+ int err = 0;
- protinfo = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg),
- IFLA_PROTINFO);
- if (protinfo) {
- attr = nla_find_nested(protinfo, IFLA_BRPORT_LEARNING);
- if (attr) {
- if (nla_len(attr) < sizeof(u8))
- return -EINVAL;
-
- if (nla_get_u8(attr))
- rocker_port->brport_flags |= BR_LEARNING;
- else
- rocker_port->brport_flags &= ~BR_LEARNING;
- err = rocker_port_set_learning(rocker_port);
- if (err)
- return err;
- }
- attr = nla_find_nested(protinfo, IFLA_BRPORT_LEARNING_SYNC);
- if (attr) {
- if (nla_len(attr) < sizeof(u8))
- return -EINVAL;
-
- if (nla_get_u8(attr))
- rocker_port->brport_flags |= BR_LEARNING_SYNC;
- else
- rocker_port->brport_flags &= ~BR_LEARNING_SYNC;
- }
+ switch (obj->trans) {
+ case SWITCHDEV_TRANS_PREPARE:
+ BUG_ON(!list_empty(&rocker_port->trans_mem));
+ break;
+ case SWITCHDEV_TRANS_ABORT:
+ rocker_port_trans_abort(rocker_port);
+ return 0;
+ default:
+ break;
}
- return 0;
+ switch (obj->id) {
+ case SWITCHDEV_OBJ_PORT_VLAN:
+ err = rocker_port_vlans_add(rocker_port, obj->trans,
+ &obj->u.vlan);
+ break;
+ case SWITCHDEV_OBJ_IPV4_FIB:
+ fib4 = &obj->u.ipv4_fib;
+ err = rocker_port_fib_ipv4(rocker_port, obj->trans,
+ htonl(fib4->dst), fib4->dst_len,
+ fib4->fi, fib4->tb_id, 0);
+ break;
+ case SWITCHDEV_OBJ_PORT_FDB:
+ err = rocker_port_fdb_add(rocker_port, obj->trans, &obj->u.fdb);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
}
-static int rocker_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
- struct net_device *dev,
- u32 filter_mask, int nlflags)
+static int rocker_port_vlan_del(struct rocker_port *rocker_port,
+ u16 vid, u16 flags)
{
- struct rocker_port *rocker_port = netdev_priv(dev);
- u16 mode = BRIDGE_MODE_UNDEF;
- u32 mask = BR_LEARNING | BR_LEARNING_SYNC;
+ int err;
- return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode,
- rocker_port->brport_flags, mask,
- nlflags);
+ err = rocker_port_router_mac(rocker_port, SWITCHDEV_TRANS_NONE,
+ ROCKER_OP_FLAG_REMOVE, htons(vid));
+ if (err)
+ return err;
+
+ return rocker_port_vlan(rocker_port, SWITCHDEV_TRANS_NONE,
+ ROCKER_OP_FLAG_REMOVE, vid);
}
-static int rocker_port_get_phys_port_name(struct net_device *dev,
- char *buf, size_t len)
+static int rocker_port_vlans_del(struct rocker_port *rocker_port,
+ const struct switchdev_obj_vlan *vlan)
{
- struct rocker_port *rocker_port = netdev_priv(dev);
- struct port_name name = { .buf = buf, .len = len };
+ u16 vid;
int err;
- err = rocker_cmd_exec(rocker_port->rocker, rocker_port,
- rocker_cmd_get_port_settings_prep, NULL,
- rocker_cmd_get_port_settings_phys_name_proc,
- &name, false);
+ for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
+ err = rocker_port_vlan_del(rocker_port, vid, vlan->flags);
+ if (err)
+ return err;
+ }
- return err ? -EOPNOTSUPP : 0;
+ return 0;
}
-static const struct net_device_ops rocker_port_netdev_ops = {
- .ndo_open = rocker_port_open,
- .ndo_stop = rocker_port_stop,
- .ndo_start_xmit = rocker_port_xmit,
- .ndo_set_mac_address = rocker_port_set_mac_address,
- .ndo_vlan_rx_add_vid = rocker_port_vlan_rx_add_vid,
- .ndo_vlan_rx_kill_vid = rocker_port_vlan_rx_kill_vid,
- .ndo_fdb_add = rocker_port_fdb_add,
- .ndo_fdb_del = rocker_port_fdb_del,
- .ndo_fdb_dump = rocker_port_fdb_dump,
- .ndo_bridge_setlink = rocker_port_bridge_setlink,
- .ndo_bridge_getlink = rocker_port_bridge_getlink,
- .ndo_get_phys_port_name = rocker_port_get_phys_port_name,
-};
+static int rocker_port_fdb_del(struct rocker_port *rocker_port,
+ enum switchdev_trans trans,
+ const struct switchdev_obj_fdb *fdb)
+{
+ __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL);
+ int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_REMOVE;
-/********************
- * swdev interface
- ********************/
+ if (!rocker_port_is_bridged(rocker_port))
+ return -EINVAL;
+
+ return rocker_port_fdb(rocker_port, trans, fdb->addr, vlan_id, flags);
+}
-static int rocker_port_swdev_parent_id_get(struct net_device *dev,
- struct netdev_phys_item_id *psid)
+static int rocker_port_obj_del(struct net_device *dev,
+ struct switchdev_obj *obj)
{
struct rocker_port *rocker_port = netdev_priv(dev);
- struct rocker *rocker = rocker_port->rocker;
+ const struct switchdev_obj_ipv4_fib *fib4;
+ int err = 0;
- psid->id_len = sizeof(rocker->hw.id);
- memcpy(&psid->id, &rocker->hw.id, psid->id_len);
- return 0;
+ switch (obj->id) {
+ case SWITCHDEV_OBJ_PORT_VLAN:
+ err = rocker_port_vlans_del(rocker_port, &obj->u.vlan);
+ break;
+ case SWITCHDEV_OBJ_IPV4_FIB:
+ fib4 = &obj->u.ipv4_fib;
+ err = rocker_port_fib_ipv4(rocker_port, SWITCHDEV_TRANS_NONE,
+ htonl(fib4->dst), fib4->dst_len,
+ fib4->fi, fib4->tb_id,
+ ROCKER_OP_FLAG_REMOVE);
+ break;
+ case SWITCHDEV_OBJ_PORT_FDB:
+ err = rocker_port_fdb_del(rocker_port, obj->trans, &obj->u.fdb);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
}
-static int rocker_port_swdev_port_stp_update(struct net_device *dev, u8 state)
+static int rocker_port_fdb_dump(const struct rocker_port *rocker_port,
+ struct switchdev_obj *obj)
{
- struct rocker_port *rocker_port = netdev_priv(dev);
+ struct rocker *rocker = rocker_port->rocker;
+ struct switchdev_obj_fdb *fdb = &obj->u.fdb;
+ struct rocker_fdb_tbl_entry *found;
+ struct hlist_node *tmp;
+ unsigned long lock_flags;
+ int bkt;
+ int err = 0;
- return rocker_port_stp_update(rocker_port, state);
+ spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags);
+ hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) {
+ if (found->key.pport != rocker_port->pport)
+ continue;
+ fdb->addr = found->key.addr;
+ fdb->vid = rocker_port_vlan_to_vid(rocker_port,
+ found->key.vlan_id);
+ err = obj->cb(rocker_port->dev, obj);
+ if (err)
+ break;
+ }
+ spin_unlock_irqrestore(&rocker->fdb_tbl_lock, lock_flags);
+
+ return err;
}
-static int rocker_port_swdev_fib_ipv4_add(struct net_device *dev,
- __be32 dst, int dst_len,
- struct fib_info *fi,
- u8 tos, u8 type,
- u32 nlflags, u32 tb_id)
+static int rocker_port_vlan_dump(const struct rocker_port *rocker_port,
+ struct switchdev_obj *obj)
{
- struct rocker_port *rocker_port = netdev_priv(dev);
- int flags = 0;
+ struct switchdev_obj_vlan *vlan = &obj->u.vlan;
+ u16 vid;
+ int err = 0;
- return rocker_port_fib_ipv4(rocker_port, dst, dst_len,
- fi, tb_id, flags);
+ for (vid = 1; vid < VLAN_N_VID; vid++) {
+ if (!test_bit(vid, rocker_port->vlan_bitmap))
+ continue;
+ vlan->flags = 0;
+ if (rocker_vlan_id_is_internal(htons(vid)))
+ vlan->flags |= BRIDGE_VLAN_INFO_PVID;
+ vlan->vid_begin = vlan->vid_end = vid;
+ err = obj->cb(rocker_port->dev, obj);
+ if (err)
+ break;
+ }
+
+ return err;
}
-static int rocker_port_swdev_fib_ipv4_del(struct net_device *dev,
- __be32 dst, int dst_len,
- struct fib_info *fi,
- u8 tos, u8 type, u32 tb_id)
+static int rocker_port_obj_dump(struct net_device *dev,
+ struct switchdev_obj *obj)
{
- struct rocker_port *rocker_port = netdev_priv(dev);
- int flags = ROCKER_OP_FLAG_REMOVE;
+ const struct rocker_port *rocker_port = netdev_priv(dev);
+ int err = 0;
- return rocker_port_fib_ipv4(rocker_port, dst, dst_len,
- fi, tb_id, flags);
+ switch (obj->id) {
+ case SWITCHDEV_OBJ_PORT_FDB:
+ err = rocker_port_fdb_dump(rocker_port, obj);
+ break;
+ case SWITCHDEV_OBJ_PORT_VLAN:
+ err = rocker_port_vlan_dump(rocker_port, obj);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
}
-static const struct swdev_ops rocker_port_swdev_ops = {
- .swdev_parent_id_get = rocker_port_swdev_parent_id_get,
- .swdev_port_stp_update = rocker_port_swdev_port_stp_update,
- .swdev_fib_ipv4_add = rocker_port_swdev_fib_ipv4_add,
- .swdev_fib_ipv4_del = rocker_port_swdev_fib_ipv4_del,
+static const struct switchdev_ops rocker_port_switchdev_ops = {
+ .switchdev_port_attr_get = rocker_port_attr_get,
+ .switchdev_port_attr_set = rocker_port_attr_set,
+ .switchdev_port_obj_add = rocker_port_obj_add,
+ .switchdev_port_obj_del = rocker_port_obj_del,
+ .switchdev_port_obj_dump = rocker_port_obj_dump,
};
/********************
@@ -4334,8 +4568,7 @@ static void rocker_port_get_strings(struct net_device *netdev, u32 stringset,
}
static int
-rocker_cmd_get_port_stats_prep(struct rocker *rocker,
- struct rocker_port *rocker_port,
+rocker_cmd_get_port_stats_prep(const struct rocker_port *rocker_port,
struct rocker_desc_info *desc_info,
void *priv)
{
@@ -4359,14 +4592,13 @@ rocker_cmd_get_port_stats_prep(struct rocker *rocker,
}
static int
-rocker_cmd_get_port_stats_ethtool_proc(struct rocker *rocker,
- struct rocker_port *rocker_port,
- struct rocker_desc_info *desc_info,
+rocker_cmd_get_port_stats_ethtool_proc(const struct rocker_port *rocker_port,
+ const struct rocker_desc_info *desc_info,
void *priv)
{
- struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
- struct rocker_tlv *stats_attrs[ROCKER_TLV_CMD_PORT_STATS_MAX + 1];
- struct rocker_tlv *pattr;
+ const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
+ const struct rocker_tlv *stats_attrs[ROCKER_TLV_CMD_PORT_STATS_MAX + 1];
+ const struct rocker_tlv *pattr;
u32 pport;
u64 *data = priv;
int i;
@@ -4400,10 +4632,10 @@ rocker_cmd_get_port_stats_ethtool_proc(struct rocker *rocker,
static int rocker_cmd_get_port_stats_ethtool(struct rocker_port *rocker_port,
void *priv)
{
- return rocker_cmd_exec(rocker_port->rocker, rocker_port,
+ return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
rocker_cmd_get_port_stats_prep, NULL,
rocker_cmd_get_port_stats_ethtool_proc,
- priv, false);
+ priv);
}
static void rocker_port_get_stats(struct net_device *dev,
@@ -4417,8 +4649,6 @@ static void rocker_port_get_stats(struct net_device *dev,
for (i = 0; i < ARRAY_SIZE(rocker_port_stats); ++i)
data[i] = 0;
}
-
- return;
}
static int rocker_port_get_sset_count(struct net_device *netdev, int sset)
@@ -4453,8 +4683,8 @@ static struct rocker_port *rocker_port_napi_tx_get(struct napi_struct *napi)
static int rocker_port_poll_tx(struct napi_struct *napi, int budget)
{
struct rocker_port *rocker_port = rocker_port_napi_tx_get(napi);
- struct rocker *rocker = rocker_port->rocker;
- struct rocker_desc_info *desc_info;
+ const struct rocker *rocker = rocker_port->rocker;
+ const struct rocker_desc_info *desc_info;
u32 credits = 0;
int err;
@@ -4472,8 +4702,9 @@ static int rocker_port_poll_tx(struct napi_struct *napi, int budget)
if (err == 0) {
rocker_port->dev->stats.tx_packets++;
rocker_port->dev->stats.tx_bytes += skb->len;
- } else
+ } else {
rocker_port->dev->stats.tx_errors++;
+ }
dev_kfree_skb_any(skb);
credits++;
@@ -4488,11 +4719,11 @@ static int rocker_port_poll_tx(struct napi_struct *napi, int budget)
return 0;
}
-static int rocker_port_rx_proc(struct rocker *rocker,
- struct rocker_port *rocker_port,
+static int rocker_port_rx_proc(const struct rocker *rocker,
+ const struct rocker_port *rocker_port,
struct rocker_desc_info *desc_info)
{
- struct rocker_tlv *attrs[ROCKER_TLV_RX_MAX + 1];
+ const struct rocker_tlv *attrs[ROCKER_TLV_RX_MAX + 1];
struct sk_buff *skb = rocker_desc_cookie_ptr_get(desc_info);
size_t rx_len;
@@ -4514,7 +4745,7 @@ static int rocker_port_rx_proc(struct rocker *rocker,
netif_receive_skb(skb);
- return rocker_dma_rx_ring_skb_alloc(rocker, rocker_port, desc_info);
+ return rocker_dma_rx_ring_skb_alloc(rocker_port, desc_info);
}
static struct rocker_port *rocker_port_napi_rx_get(struct napi_struct *napi)
@@ -4525,7 +4756,7 @@ static struct rocker_port *rocker_port_napi_rx_get(struct napi_struct *napi)
static int rocker_port_poll_rx(struct napi_struct *napi, int budget)
{
struct rocker_port *rocker_port = rocker_port_napi_rx_get(napi);
- struct rocker *rocker = rocker_port->rocker;
+ const struct rocker *rocker = rocker_port->rocker;
struct rocker_desc_info *desc_info;
u32 credits = 0;
int err;
@@ -4565,9 +4796,9 @@ static int rocker_port_poll_rx(struct napi_struct *napi, int budget)
* PCI driver ops
*****************/
-static void rocker_carrier_init(struct rocker_port *rocker_port)
+static void rocker_carrier_init(const struct rocker_port *rocker_port)
{
- struct rocker *rocker = rocker_port->rocker;
+ const struct rocker *rocker = rocker_port->rocker;
u64 link_status = rocker_read64(rocker, PORT_PHYS_LINK_STATUS);
bool link_up;
@@ -4578,23 +4809,26 @@ static void rocker_carrier_init(struct rocker_port *rocker_port)
netif_carrier_off(rocker_port->dev);
}
-static void rocker_remove_ports(struct rocker *rocker)
+static void rocker_remove_ports(const struct rocker *rocker)
{
struct rocker_port *rocker_port;
int i;
for (i = 0; i < rocker->port_count; i++) {
rocker_port = rocker->ports[i];
- rocker_port_ig_tbl(rocker_port, ROCKER_OP_FLAG_REMOVE);
+ if (!rocker_port)
+ continue;
+ rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE,
+ ROCKER_OP_FLAG_REMOVE);
unregister_netdev(rocker_port->dev);
}
kfree(rocker->ports);
}
-static void rocker_port_dev_addr_init(struct rocker *rocker,
- struct rocker_port *rocker_port)
+static void rocker_port_dev_addr_init(struct rocker_port *rocker_port)
{
- struct pci_dev *pdev = rocker->pdev;
+ const struct rocker *rocker = rocker_port->rocker;
+ const struct pci_dev *pdev = rocker->pdev;
int err;
err = rocker_cmd_get_port_settings_macaddr(rocker_port,
@@ -4607,9 +4841,10 @@ static void rocker_port_dev_addr_init(struct rocker *rocker,
static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
{
- struct pci_dev *pdev = rocker->pdev;
+ const struct pci_dev *pdev = rocker->pdev;
struct rocker_port *rocker_port;
struct net_device *dev;
+ u16 untagged_vid = 0;
int err;
dev = alloc_etherdev(sizeof(struct rocker_port));
@@ -4621,20 +4856,19 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
rocker_port->port_number = port_number;
rocker_port->pport = port_number + 1;
rocker_port->brport_flags = BR_LEARNING | BR_LEARNING_SYNC;
+ INIT_LIST_HEAD(&rocker_port->trans_mem);
- rocker_port_dev_addr_init(rocker, rocker_port);
+ rocker_port_dev_addr_init(rocker_port);
dev->netdev_ops = &rocker_port_netdev_ops;
dev->ethtool_ops = &rocker_port_ethtool_ops;
- dev->swdev_ops = &rocker_port_swdev_ops;
+ dev->switchdev_ops = &rocker_port_switchdev_ops;
netif_napi_add(dev, &rocker_port->napi_tx, rocker_port_poll_tx,
NAPI_POLL_WEIGHT);
netif_napi_add(dev, &rocker_port->napi_rx, rocker_port_poll_rx,
NAPI_POLL_WEIGHT);
rocker_carrier_init(rocker_port);
- dev->features |= NETIF_F_NETNS_LOCAL |
- NETIF_F_HW_VLAN_CTAG_FILTER |
- NETIF_F_HW_SWITCH_OFFLOAD;
+ dev->features |= NETIF_F_NETNS_LOCAL;
err = register_netdev(dev);
if (err) {
@@ -4643,18 +4877,29 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
}
rocker->ports[port_number] = rocker_port;
- rocker_port_set_learning(rocker_port);
+ rocker_port_set_learning(rocker_port, SWITCHDEV_TRANS_NONE);
- rocker_port->internal_vlan_id =
- rocker_port_internal_vlan_id_get(rocker_port, dev->ifindex);
- err = rocker_port_ig_tbl(rocker_port, 0);
+ err = rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE, 0);
if (err) {
dev_err(&pdev->dev, "install ig port table failed\n");
goto err_port_ig_tbl;
}
+ rocker_port->internal_vlan_id =
+ rocker_port_internal_vlan_id_get(rocker_port, dev->ifindex);
+
+ err = rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE,
+ untagged_vid, 0);
+ if (err) {
+ netdev_err(rocker_port->dev, "install untagged VLAN failed\n");
+ goto err_untagged_vlan;
+ }
+
return 0;
+err_untagged_vlan:
+ rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE,
+ ROCKER_OP_FLAG_REMOVE);
err_port_ig_tbl:
unregister_netdev(dev);
err_register_netdev:
@@ -4669,7 +4914,7 @@ static int rocker_probe_ports(struct rocker *rocker)
int err;
alloc_size = sizeof(struct rocker_port *) * rocker->port_count;
- rocker->ports = kmalloc(alloc_size, GFP_KERNEL);
+ rocker->ports = kzalloc(alloc_size, GFP_KERNEL);
if (!rocker->ports)
return -ENOMEM;
for (i = 0; i < rocker->port_count; i++) {
@@ -4718,7 +4963,7 @@ err_enable_msix:
return err;
}
-static void rocker_msix_fini(struct rocker *rocker)
+static void rocker_msix_fini(const struct rocker *rocker)
{
pci_disable_msix(rocker->pdev);
kfree(rocker->msix_entries);
@@ -4884,7 +5129,7 @@ static struct pci_driver rocker_pci_driver = {
* Net device notifier event handler
************************************/
-static bool rocker_port_dev_check(struct net_device *dev)
+static bool rocker_port_dev_check(const struct net_device *dev)
{
return dev->netdev_ops == &rocker_port_netdev_ops;
}
@@ -4892,45 +5137,55 @@ static bool rocker_port_dev_check(struct net_device *dev)
static int rocker_port_bridge_join(struct rocker_port *rocker_port,
struct net_device *bridge)
{
+ u16 untagged_vid = 0;
int err;
+ /* Port is joining bridge, so the internal VLAN for the
+ * port is going to change to the bridge internal VLAN.
+ * Let's remove untagged VLAN (vid=0) from port and
+ * re-add once internal VLAN has changed.
+ */
+
+ err = rocker_port_vlan_del(rocker_port, untagged_vid, 0);
+ if (err)
+ return err;
+
rocker_port_internal_vlan_id_put(rocker_port,
rocker_port->dev->ifindex);
+ rocker_port->internal_vlan_id =
+ rocker_port_internal_vlan_id_get(rocker_port, bridge->ifindex);
rocker_port->bridge_dev = bridge;
- /* Use bridge internal VLAN ID for untagged pkts */
- err = rocker_port_vlan(rocker_port, ROCKER_OP_FLAG_REMOVE, 0);
- if (err)
- return err;
- rocker_port->internal_vlan_id =
- rocker_port_internal_vlan_id_get(rocker_port,
- bridge->ifindex);
- return rocker_port_vlan(rocker_port, 0, 0);
+ return rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE,
+ untagged_vid, 0);
}
static int rocker_port_bridge_leave(struct rocker_port *rocker_port)
{
+ u16 untagged_vid = 0;
int err;
- rocker_port_internal_vlan_id_put(rocker_port,
- rocker_port->bridge_dev->ifindex);
-
- rocker_port->bridge_dev = NULL;
-
- /* Use port internal VLAN ID for untagged pkts */
- err = rocker_port_vlan(rocker_port, ROCKER_OP_FLAG_REMOVE, 0);
+ err = rocker_port_vlan_del(rocker_port, untagged_vid, 0);
if (err)
return err;
+
+ rocker_port_internal_vlan_id_put(rocker_port,
+ rocker_port->bridge_dev->ifindex);
rocker_port->internal_vlan_id =
rocker_port_internal_vlan_id_get(rocker_port,
rocker_port->dev->ifindex);
- err = rocker_port_vlan(rocker_port, 0, 0);
+
+ rocker_port->bridge_dev = NULL;
+
+ err = rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE,
+ untagged_vid, 0);
if (err)
return err;
if (rocker_port->dev->flags & IFF_UP)
- err = rocker_port_fwd_enable(rocker_port);
+ err = rocker_port_fwd_enable(rocker_port,
+ SWITCHDEV_TRANS_NONE, 0);
return err;
}
@@ -4989,10 +5244,12 @@ static struct notifier_block rocker_netdevice_nb __read_mostly = {
static int rocker_neigh_update(struct net_device *dev, struct neighbour *n)
{
struct rocker_port *rocker_port = netdev_priv(dev);
- int flags = (n->nud_state & NUD_VALID) ? 0 : ROCKER_OP_FLAG_REMOVE;
+ int flags = (n->nud_state & NUD_VALID ? 0 : ROCKER_OP_FLAG_REMOVE) |
+ ROCKER_OP_FLAG_NOWAIT;
__be32 ip_addr = *(__be32 *)n->primary_key;
- return rocker_port_ipv4_neigh(rocker_port, flags, ip_addr, n->ha);
+ return rocker_port_ipv4_neigh(rocker_port, SWITCHDEV_TRANS_NONE,
+ flags, ip_addr, n->ha);
}
static int rocker_netevent_event(struct notifier_block *unused,
@@ -5040,7 +5297,7 @@ static int __init rocker_module_init(void)
return 0;
err_pci_register_driver:
- unregister_netdevice_notifier(&rocker_netevent_nb);
+ unregister_netevent_notifier(&rocker_netevent_nb);
unregister_netdevice_notifier(&rocker_netdevice_nb);
return err;
}
diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h
index a4e9591d7457..c61fbf968036 100644
--- a/drivers/net/ethernet/rocker/rocker.h
+++ b/drivers/net/ethernet/rocker/rocker.h
@@ -65,9 +65,9 @@ enum {
#define ROCKER_TEST_DMA_CTRL 0x0034
/* Rocker test register ctrl */
-#define ROCKER_TEST_DMA_CTRL_CLEAR (1 << 0)
-#define ROCKER_TEST_DMA_CTRL_FILL (1 << 1)
-#define ROCKER_TEST_DMA_CTRL_INVERT (1 << 2)
+#define ROCKER_TEST_DMA_CTRL_CLEAR BIT(0)
+#define ROCKER_TEST_DMA_CTRL_FILL BIT(1)
+#define ROCKER_TEST_DMA_CTRL_INVERT BIT(2)
/* Rocker DMA ring register offsets */
#define ROCKER_DMA_DESC_ADDR(x) (0x1000 + (x) * 32) /* 8-byte */
@@ -79,7 +79,7 @@ enum {
#define ROCKER_DMA_DESC_RES1(x) (0x101c + (x) * 32)
/* Rocker dma ctrl register bits */
-#define ROCKER_DMA_DESC_CTRL_RESET (1 << 0)
+#define ROCKER_DMA_DESC_CTRL_RESET BIT(0)
/* Rocker DMA ring types */
enum rocker_dma_type {
@@ -111,7 +111,7 @@ struct rocker_desc {
u16 comp_err;
};
-#define ROCKER_DMA_DESC_COMP_ERR_GEN (1 << 15)
+#define ROCKER_DMA_DESC_COMP_ERR_GEN BIT(15)
/* Rocker DMA TLV struct */
struct rocker_tlv {
@@ -237,14 +237,14 @@ enum {
ROCKER_TLV_RX_MAX = __ROCKER_TLV_RX_MAX - 1,
};
-#define ROCKER_RX_FLAGS_IPV4 (1 << 0)
-#define ROCKER_RX_FLAGS_IPV6 (1 << 1)
-#define ROCKER_RX_FLAGS_CSUM_CALC (1 << 2)
-#define ROCKER_RX_FLAGS_IPV4_CSUM_GOOD (1 << 3)
-#define ROCKER_RX_FLAGS_IP_FRAG (1 << 4)
-#define ROCKER_RX_FLAGS_TCP (1 << 5)
-#define ROCKER_RX_FLAGS_UDP (1 << 6)
-#define ROCKER_RX_FLAGS_TCP_UDP_CSUM_GOOD (1 << 7)
+#define ROCKER_RX_FLAGS_IPV4 BIT(0)
+#define ROCKER_RX_FLAGS_IPV6 BIT(1)
+#define ROCKER_RX_FLAGS_CSUM_CALC BIT(2)
+#define ROCKER_RX_FLAGS_IPV4_CSUM_GOOD BIT(3)
+#define ROCKER_RX_FLAGS_IP_FRAG BIT(4)
+#define ROCKER_RX_FLAGS_TCP BIT(5)
+#define ROCKER_RX_FLAGS_UDP BIT(6)
+#define ROCKER_RX_FLAGS_TCP_UDP_CSUM_GOOD BIT(7)
enum {
ROCKER_TLV_TX_UNSPEC,
@@ -460,6 +460,6 @@ enum rocker_of_dpa_overlay_type {
#define ROCKER_SWITCH_ID 0x0320 /* 8-byte */
/* Rocker control bits */
-#define ROCKER_CONTROL_RESET (1 << 0)
+#define ROCKER_CONTROL_RESET BIT(0)
#endif
diff --git a/drivers/net/ethernet/seeq/Kconfig b/drivers/net/ethernet/seeq/Kconfig
index 11f168e46ebe..69c62d89295e 100644
--- a/drivers/net/ethernet/seeq/Kconfig
+++ b/drivers/net/ethernet/seeq/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_SEEQ
default y
depends on HAS_IOMEM
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
index 088921294448..4dd92b7b80f4 100644
--- a/drivers/net/ethernet/sfc/Kconfig
+++ b/drivers/net/ethernet/sfc/Kconfig
@@ -36,3 +36,12 @@ config SFC_SRIOV
This enables support for the SFC9000 I/O Virtualization
features, allowing accelerated network performance in
virtualized environments.
+config SFC_MCDI_LOGGING
+ bool "Solarflare SFC9000/SFC9100-family MCDI logging support"
+ depends on SFC
+ default y
+ ---help---
+ This enables support for tracing of MCDI (Management-Controller-to-
+ Driver-Interface) commands and responses, allowing debugging of
+ driver/firmware interaction. The tracing is actually enabled by
+ a sysfs file 'mcdi_logging' under the PCI device.
diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
index 3a83c0dca8e6..ce8470fe79d5 100644
--- a/drivers/net/ethernet/sfc/Makefile
+++ b/drivers/net/ethernet/sfc/Makefile
@@ -3,6 +3,6 @@ sfc-y += efx.o nic.o farch.o falcon.o siena.o ef10.o tx.o \
tenxpress.o txc43128_phy.o falcon_boards.o \
mcdi.o mcdi_port.o mcdi_mon.o ptp.o
sfc-$(CONFIG_SFC_MTD) += mtd.o
-sfc-$(CONFIG_SFC_SRIOV) += siena_sriov.o
+sfc-$(CONFIG_SFC_SRIOV) += sriov.o siena_sriov.o ef10_sriov.o
obj-$(CONFIG_SFC) += sfc.o
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index fbb6cfa0f5f1..847643455468 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -15,6 +15,7 @@
#include "nic.h"
#include "workarounds.h"
#include "selftest.h"
+#include "ef10_sriov.h"
#include <linux/in.h>
#include <linux/jhash.h>
#include <linux/wait.h>
@@ -30,6 +31,9 @@ enum {
/* The reserved RSS context value */
#define EFX_EF10_RSS_CONTEXT_INVALID 0xffffffff
+/* The maximum size of a shared RSS context */
+/* TODO: this should really be from the mcdi protocol export */
+#define EFX_EF10_MAX_SHARED_RSS_CONTEXT_SIZE 64UL
/* The filter table(s) are managed by firmware and we have write-only
* access. When removing filters we must identify them to the
@@ -77,7 +81,6 @@ struct efx_ef10_filter_table {
/* An arbitrary search limit for the software hash table */
#define EFX_EF10_FILTER_SEARCH_LIMIT 200
-static void efx_ef10_rx_push_rss_config(struct efx_nic *efx);
static void efx_ef10_rx_free_indir_table(struct efx_nic *efx);
static void efx_ef10_filter_table_remove(struct efx_nic *efx);
@@ -92,8 +95,49 @@ static int efx_ef10_get_warm_boot_count(struct efx_nic *efx)
static unsigned int efx_ef10_mem_map_size(struct efx_nic *efx)
{
- return resource_size(&efx->pci_dev->resource[EFX_MEM_BAR]);
+ int bar;
+
+ bar = efx->type->mem_bar;
+ return resource_size(&efx->pci_dev->resource[bar]);
+}
+
+static int efx_ef10_get_pf_index(struct efx_nic *efx)
+{
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN);
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ size_t outlen;
+ int rc;
+
+ rc = efx_mcdi_rpc(efx, MC_CMD_GET_FUNCTION_INFO, NULL, 0, outbuf,
+ sizeof(outbuf), &outlen);
+ if (rc)
+ return rc;
+ if (outlen < sizeof(outbuf))
+ return -EIO;
+
+ nic_data->pf_index = MCDI_DWORD(outbuf, GET_FUNCTION_INFO_OUT_PF);
+ return 0;
+}
+
+#ifdef CONFIG_SFC_SRIOV
+static int efx_ef10_get_vf_index(struct efx_nic *efx)
+{
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN);
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ size_t outlen;
+ int rc;
+
+ rc = efx_mcdi_rpc(efx, MC_CMD_GET_FUNCTION_INFO, NULL, 0, outbuf,
+ sizeof(outbuf), &outlen);
+ if (rc)
+ return rc;
+ if (outlen < sizeof(outbuf))
+ return -EIO;
+
+ nic_data->vf_index = MCDI_DWORD(outbuf, GET_FUNCTION_INFO_OUT_VF);
+ return 0;
}
+#endif
static int efx_ef10_init_datapath_caps(struct efx_nic *efx)
{
@@ -117,6 +161,13 @@ static int efx_ef10_init_datapath_caps(struct efx_nic *efx)
nic_data->datapath_caps =
MCDI_DWORD(outbuf, GET_CAPABILITIES_OUT_FLAGS1);
+ /* record the DPCPU firmware IDs to determine VEB vswitching support.
+ */
+ nic_data->rx_dpcpu_fw_id =
+ MCDI_WORD(outbuf, GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID);
+ nic_data->tx_dpcpu_fw_id =
+ MCDI_WORD(outbuf, GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID);
+
if (!(nic_data->datapath_caps &
(1 << MC_CMD_GET_CAPABILITIES_OUT_TX_TSO_LBN))) {
netif_err(efx, drv, efx->net_dev,
@@ -147,7 +198,7 @@ static int efx_ef10_get_sysclk_freq(struct efx_nic *efx)
return rc > 0 ? rc : -ERANGE;
}
-static int efx_ef10_get_mac_address(struct efx_nic *efx, u8 *mac_address)
+static int efx_ef10_get_mac_address_pf(struct efx_nic *efx, u8 *mac_address)
{
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_MAC_ADDRESSES_OUT_LEN);
size_t outlen;
@@ -167,9 +218,66 @@ static int efx_ef10_get_mac_address(struct efx_nic *efx, u8 *mac_address)
return 0;
}
+static int efx_ef10_get_mac_address_vf(struct efx_nic *efx, u8 *mac_address)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN);
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX);
+ size_t outlen;
+ int num_addrs, rc;
+
+ MCDI_SET_DWORD(inbuf, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID,
+ EVB_PORT_ID_ASSIGNED);
+ rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_GET_MAC_ADDRESSES, inbuf,
+ sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
+
+ if (rc)
+ return rc;
+ if (outlen < MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN)
+ return -EIO;
+
+ num_addrs = MCDI_DWORD(outbuf,
+ VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT);
+
+ WARN_ON(num_addrs != 1);
+
+ ether_addr_copy(mac_address,
+ MCDI_PTR(outbuf, VPORT_GET_MAC_ADDRESSES_OUT_MACADDR));
+
+ return 0;
+}
+
+static ssize_t efx_ef10_show_link_control_flag(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+
+ return sprintf(buf, "%d\n",
+ ((efx->mcdi->fn_flags) &
+ (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL))
+ ? 1 : 0);
+}
+
+static ssize_t efx_ef10_show_primary_flag(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+
+ return sprintf(buf, "%d\n",
+ ((efx->mcdi->fn_flags) &
+ (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY))
+ ? 1 : 0);
+}
+
+static DEVICE_ATTR(link_control_flag, 0444, efx_ef10_show_link_control_flag,
+ NULL);
+static DEVICE_ATTR(primary_flag, 0444, efx_ef10_show_primary_flag, NULL);
+
static int efx_ef10_probe(struct efx_nic *efx)
{
struct efx_ef10_nic_data *nic_data;
+ struct net_device *net_dev = efx->net_dev;
int i, rc;
/* We can have one VI for each 8K region. However, until we
@@ -178,7 +286,7 @@ static int efx_ef10_probe(struct efx_nic *efx)
efx->max_channels =
min_t(unsigned int,
EFX_MAX_CHANNELS,
- resource_size(&efx->pci_dev->resource[EFX_MEM_BAR]) /
+ efx_ef10_mem_map_size(efx) /
(EFX_VI_PAGE_SIZE * EFX_TXQ_TYPES));
if (WARN_ON(efx->max_channels == 0))
return -EIO;
@@ -188,6 +296,9 @@ static int efx_ef10_probe(struct efx_nic *efx)
return -ENOMEM;
efx->nic_data = nic_data;
+ /* we assume later that we can copy from this buffer in dwords */
+ BUILD_BUG_ON(MCDI_CTL_SDU_LEN_MAX_V2 % 4);
+
rc = efx_nic_alloc_buffer(efx, &nic_data->mcdi_buf,
8 + MCDI_CTL_SDU_LEN_MAX_V2, GFP_KERNEL);
if (rc)
@@ -209,6 +320,8 @@ static int efx_ef10_probe(struct efx_nic *efx)
nic_data->rx_rss_context = EFX_EF10_RSS_CONTEXT_INVALID;
+ nic_data->vport_id = EVB_PORT_ID_ASSIGNED;
+
/* In case we're recovering from a crash (kexec), we want to
* cancel any outstanding request by the previous user of this
* function. We send a special message using the least
@@ -230,45 +343,85 @@ static int efx_ef10_probe(struct efx_nic *efx)
if (rc)
goto fail3;
+ rc = device_create_file(&efx->pci_dev->dev,
+ &dev_attr_link_control_flag);
+ if (rc)
+ goto fail3;
+
+ rc = device_create_file(&efx->pci_dev->dev, &dev_attr_primary_flag);
+ if (rc)
+ goto fail4;
+
+ rc = efx_ef10_get_pf_index(efx);
+ if (rc)
+ goto fail5;
+
rc = efx_ef10_init_datapath_caps(efx);
if (rc < 0)
- goto fail3;
+ goto fail5;
efx->rx_packet_len_offset =
ES_DZ_RX_PREFIX_PKTLEN_OFST - ES_DZ_RX_PREFIX_SIZE;
rc = efx_mcdi_port_get_number(efx);
if (rc < 0)
- goto fail3;
+ goto fail5;
efx->port_num = rc;
+ net_dev->dev_port = rc;
- rc = efx_ef10_get_mac_address(efx, efx->net_dev->perm_addr);
+ rc = efx->type->get_mac_address(efx, efx->net_dev->perm_addr);
if (rc)
- goto fail3;
+ goto fail5;
rc = efx_ef10_get_sysclk_freq(efx);
if (rc < 0)
- goto fail3;
+ goto fail5;
efx->timer_quantum_ns = 1536000 / rc; /* 1536 cycles */
- /* Check whether firmware supports bug 35388 workaround */
+ /* Check whether firmware supports bug 35388 workaround.
+ * First try to enable it, then if we get EPERM, just
+ * ask if it's already enabled
+ */
rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG35388, true);
- if (rc == 0)
+ if (rc == 0) {
nic_data->workaround_35388 = true;
- else if (rc != -ENOSYS && rc != -ENOENT)
- goto fail3;
+ } else if (rc == -EPERM) {
+ unsigned int enabled;
+
+ rc = efx_mcdi_get_workarounds(efx, NULL, &enabled);
+ if (rc)
+ goto fail3;
+ nic_data->workaround_35388 = enabled &
+ MC_CMD_GET_WORKAROUNDS_OUT_BUG35388;
+ } else if (rc != -ENOSYS && rc != -ENOENT) {
+ goto fail5;
+ }
netif_dbg(efx, probe, efx->net_dev,
"workaround for bug 35388 is %sabled\n",
nic_data->workaround_35388 ? "en" : "dis");
rc = efx_mcdi_mon_probe(efx);
- if (rc)
- goto fail3;
+ if (rc && rc != -EPERM)
+ goto fail5;
efx_ptp_probe(efx, NULL);
+#ifdef CONFIG_SFC_SRIOV
+ if ((efx->pci_dev->physfn) && (!efx->pci_dev->is_physfn)) {
+ struct pci_dev *pci_dev_pf = efx->pci_dev->physfn;
+ struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf);
+
+ efx_pf->type->get_mac_address(efx_pf, nic_data->port_id);
+ } else
+#endif
+ ether_addr_copy(nic_data->port_id, efx->net_dev->perm_addr);
+
return 0;
+fail5:
+ device_remove_file(&efx->pci_dev->dev, &dev_attr_primary_flag);
+fail4:
+ device_remove_file(&efx->pci_dev->dev, &dev_attr_link_control_flag);
fail3:
efx_mcdi_fini(efx);
fail2:
@@ -281,7 +434,7 @@ fail1:
static int efx_ef10_free_vis(struct efx_nic *efx)
{
- MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, 0);
+ MCDI_DECLARE_BUF_ERR(outbuf);
size_t outlen;
int rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FREE_VIS, NULL, 0,
outbuf, sizeof(outbuf), &outlen);
@@ -352,9 +505,9 @@ static int efx_ef10_alloc_piobufs(struct efx_nic *efx, unsigned int n)
static int efx_ef10_link_piobufs(struct efx_nic *efx)
{
struct efx_ef10_nic_data *nic_data = efx->nic_data;
- MCDI_DECLARE_BUF(inbuf,
- max(MC_CMD_LINK_PIOBUF_IN_LEN,
- MC_CMD_UNLINK_PIOBUF_IN_LEN));
+ _MCDI_DECLARE_BUF(inbuf,
+ max(MC_CMD_LINK_PIOBUF_IN_LEN,
+ MC_CMD_UNLINK_PIOBUF_IN_LEN));
struct efx_channel *channel;
struct efx_tx_queue *tx_queue;
unsigned int offset, index;
@@ -363,6 +516,8 @@ static int efx_ef10_link_piobufs(struct efx_nic *efx)
BUILD_BUG_ON(MC_CMD_LINK_PIOBUF_OUT_LEN != 0);
BUILD_BUG_ON(MC_CMD_UNLINK_PIOBUF_OUT_LEN != 0);
+ memset(inbuf, 0, sizeof(inbuf));
+
/* Link a buffer to each VI in the write-combining mapping */
for (index = 0; index < nic_data->n_piobufs; ++index) {
MCDI_SET_DWORD(inbuf, LINK_PIOBUF_IN_PIOBUF_HANDLE,
@@ -475,6 +630,25 @@ static void efx_ef10_remove(struct efx_nic *efx)
struct efx_ef10_nic_data *nic_data = efx->nic_data;
int rc;
+#ifdef CONFIG_SFC_SRIOV
+ struct efx_ef10_nic_data *nic_data_pf;
+ struct pci_dev *pci_dev_pf;
+ struct efx_nic *efx_pf;
+ struct ef10_vf *vf;
+
+ if (efx->pci_dev->is_virtfn) {
+ pci_dev_pf = efx->pci_dev->physfn;
+ if (pci_dev_pf) {
+ efx_pf = pci_get_drvdata(pci_dev_pf);
+ nic_data_pf = efx_pf->nic_data;
+ vf = nic_data_pf->vf + nic_data->vf_index;
+ vf->efx = NULL;
+ } else
+ netif_info(efx, drv, efx->net_dev,
+ "Could not get the PF id from VF\n");
+ }
+#endif
+
efx_ptp_remove(efx);
efx_mcdi_mon_remove(efx);
@@ -490,11 +664,78 @@ static void efx_ef10_remove(struct efx_nic *efx)
if (!nic_data->must_restore_piobufs)
efx_ef10_free_piobufs(efx);
+ device_remove_file(&efx->pci_dev->dev, &dev_attr_primary_flag);
+ device_remove_file(&efx->pci_dev->dev, &dev_attr_link_control_flag);
+
efx_mcdi_fini(efx);
efx_nic_free_buffer(efx, &nic_data->mcdi_buf);
kfree(nic_data);
}
+static int efx_ef10_probe_pf(struct efx_nic *efx)
+{
+ return efx_ef10_probe(efx);
+}
+
+#ifdef CONFIG_SFC_SRIOV
+static int efx_ef10_probe_vf(struct efx_nic *efx)
+{
+ int rc;
+ struct pci_dev *pci_dev_pf;
+
+ /* If the parent PF has no VF data structure, it doesn't know about this
+ * VF so fail probe. The VF needs to be re-created. This can happen
+ * if the PF driver is unloaded while the VF is assigned to a guest.
+ */
+ pci_dev_pf = efx->pci_dev->physfn;
+ if (pci_dev_pf) {
+ struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf);
+ struct efx_ef10_nic_data *nic_data_pf = efx_pf->nic_data;
+
+ if (!nic_data_pf->vf) {
+ netif_info(efx, drv, efx->net_dev,
+ "The VF cannot link to its parent PF; "
+ "please destroy and re-create the VF\n");
+ return -EBUSY;
+ }
+ }
+
+ rc = efx_ef10_probe(efx);
+ if (rc)
+ return rc;
+
+ rc = efx_ef10_get_vf_index(efx);
+ if (rc)
+ goto fail;
+
+ if (efx->pci_dev->is_virtfn) {
+ if (efx->pci_dev->physfn) {
+ struct efx_nic *efx_pf =
+ pci_get_drvdata(efx->pci_dev->physfn);
+ struct efx_ef10_nic_data *nic_data_p = efx_pf->nic_data;
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+
+ nic_data_p->vf[nic_data->vf_index].efx = efx;
+ nic_data_p->vf[nic_data->vf_index].pci_dev =
+ efx->pci_dev;
+ } else
+ netif_info(efx, drv, efx->net_dev,
+ "Could not get the PF id from VF\n");
+ }
+
+ return 0;
+
+fail:
+ efx_ef10_remove(efx);
+ return rc;
+}
+#else
+static int efx_ef10_probe_vf(struct efx_nic *efx __attribute__ ((unused)))
+{
+ return 0;
+}
+#endif
+
static int efx_ef10_alloc_vis(struct efx_nic *efx,
unsigned int min_vis, unsigned int max_vis)
{
@@ -687,7 +928,9 @@ static int efx_ef10_init_nic(struct efx_nic *efx)
nic_data->must_restore_piobufs = false;
}
- efx_ef10_rx_push_rss_config(efx);
+ /* don't fail init if RSS setup doesn't work */
+ efx->type->rx_push_rss_config(efx, false, efx->rx_indir_table);
+
return 0;
}
@@ -702,6 +945,14 @@ static void efx_ef10_reset_mc_allocations(struct efx_nic *efx)
nic_data->rx_rss_context = EFX_EF10_RSS_CONTEXT_INVALID;
}
+static enum reset_type efx_ef10_map_reset_reason(enum reset_type reason)
+{
+ if (reason == RESET_TYPE_MC_FAILURE)
+ return RESET_TYPE_DATAPATH;
+
+ return efx_mcdi_map_reset_reason(reason);
+}
+
static int efx_ef10_map_reset_flags(u32 *flags)
{
enum {
@@ -760,93 +1011,112 @@ static int efx_ef10_reset(struct efx_nic *efx, enum reset_type reset_type)
[GENERIC_STAT_ ## ext_name] = { #ext_name, 0, 0 }
static const struct efx_hw_stat_desc efx_ef10_stat_desc[EF10_STAT_COUNT] = {
- EF10_DMA_STAT(tx_bytes, TX_BYTES),
- EF10_DMA_STAT(tx_packets, TX_PKTS),
- EF10_DMA_STAT(tx_pause, TX_PAUSE_PKTS),
- EF10_DMA_STAT(tx_control, TX_CONTROL_PKTS),
- EF10_DMA_STAT(tx_unicast, TX_UNICAST_PKTS),
- EF10_DMA_STAT(tx_multicast, TX_MULTICAST_PKTS),
- EF10_DMA_STAT(tx_broadcast, TX_BROADCAST_PKTS),
- EF10_DMA_STAT(tx_lt64, TX_LT64_PKTS),
- EF10_DMA_STAT(tx_64, TX_64_PKTS),
- EF10_DMA_STAT(tx_65_to_127, TX_65_TO_127_PKTS),
- EF10_DMA_STAT(tx_128_to_255, TX_128_TO_255_PKTS),
- EF10_DMA_STAT(tx_256_to_511, TX_256_TO_511_PKTS),
- EF10_DMA_STAT(tx_512_to_1023, TX_512_TO_1023_PKTS),
- EF10_DMA_STAT(tx_1024_to_15xx, TX_1024_TO_15XX_PKTS),
- EF10_DMA_STAT(tx_15xx_to_jumbo, TX_15XX_TO_JUMBO_PKTS),
- EF10_DMA_STAT(rx_bytes, RX_BYTES),
- EF10_DMA_INVIS_STAT(rx_bytes_minus_good_bytes, RX_BAD_BYTES),
- EF10_OTHER_STAT(rx_good_bytes),
- EF10_OTHER_STAT(rx_bad_bytes),
- EF10_DMA_STAT(rx_packets, RX_PKTS),
- EF10_DMA_STAT(rx_good, RX_GOOD_PKTS),
- EF10_DMA_STAT(rx_bad, RX_BAD_FCS_PKTS),
- EF10_DMA_STAT(rx_pause, RX_PAUSE_PKTS),
- EF10_DMA_STAT(rx_control, RX_CONTROL_PKTS),
- EF10_DMA_STAT(rx_unicast, RX_UNICAST_PKTS),
- EF10_DMA_STAT(rx_multicast, RX_MULTICAST_PKTS),
- EF10_DMA_STAT(rx_broadcast, RX_BROADCAST_PKTS),
- EF10_DMA_STAT(rx_lt64, RX_UNDERSIZE_PKTS),
- EF10_DMA_STAT(rx_64, RX_64_PKTS),
- EF10_DMA_STAT(rx_65_to_127, RX_65_TO_127_PKTS),
- EF10_DMA_STAT(rx_128_to_255, RX_128_TO_255_PKTS),
- EF10_DMA_STAT(rx_256_to_511, RX_256_TO_511_PKTS),
- EF10_DMA_STAT(rx_512_to_1023, RX_512_TO_1023_PKTS),
- EF10_DMA_STAT(rx_1024_to_15xx, RX_1024_TO_15XX_PKTS),
- EF10_DMA_STAT(rx_15xx_to_jumbo, RX_15XX_TO_JUMBO_PKTS),
- EF10_DMA_STAT(rx_gtjumbo, RX_GTJUMBO_PKTS),
- EF10_DMA_STAT(rx_bad_gtjumbo, RX_JABBER_PKTS),
- EF10_DMA_STAT(rx_overflow, RX_OVERFLOW_PKTS),
- EF10_DMA_STAT(rx_align_error, RX_ALIGN_ERROR_PKTS),
- EF10_DMA_STAT(rx_length_error, RX_LENGTH_ERROR_PKTS),
- EF10_DMA_STAT(rx_nodesc_drops, RX_NODESC_DROPS),
+ EF10_DMA_STAT(port_tx_bytes, TX_BYTES),
+ EF10_DMA_STAT(port_tx_packets, TX_PKTS),
+ EF10_DMA_STAT(port_tx_pause, TX_PAUSE_PKTS),
+ EF10_DMA_STAT(port_tx_control, TX_CONTROL_PKTS),
+ EF10_DMA_STAT(port_tx_unicast, TX_UNICAST_PKTS),
+ EF10_DMA_STAT(port_tx_multicast, TX_MULTICAST_PKTS),
+ EF10_DMA_STAT(port_tx_broadcast, TX_BROADCAST_PKTS),
+ EF10_DMA_STAT(port_tx_lt64, TX_LT64_PKTS),
+ EF10_DMA_STAT(port_tx_64, TX_64_PKTS),
+ EF10_DMA_STAT(port_tx_65_to_127, TX_65_TO_127_PKTS),
+ EF10_DMA_STAT(port_tx_128_to_255, TX_128_TO_255_PKTS),
+ EF10_DMA_STAT(port_tx_256_to_511, TX_256_TO_511_PKTS),
+ EF10_DMA_STAT(port_tx_512_to_1023, TX_512_TO_1023_PKTS),
+ EF10_DMA_STAT(port_tx_1024_to_15xx, TX_1024_TO_15XX_PKTS),
+ EF10_DMA_STAT(port_tx_15xx_to_jumbo, TX_15XX_TO_JUMBO_PKTS),
+ EF10_DMA_STAT(port_rx_bytes, RX_BYTES),
+ EF10_DMA_INVIS_STAT(port_rx_bytes_minus_good_bytes, RX_BAD_BYTES),
+ EF10_OTHER_STAT(port_rx_good_bytes),
+ EF10_OTHER_STAT(port_rx_bad_bytes),
+ EF10_DMA_STAT(port_rx_packets, RX_PKTS),
+ EF10_DMA_STAT(port_rx_good, RX_GOOD_PKTS),
+ EF10_DMA_STAT(port_rx_bad, RX_BAD_FCS_PKTS),
+ EF10_DMA_STAT(port_rx_pause, RX_PAUSE_PKTS),
+ EF10_DMA_STAT(port_rx_control, RX_CONTROL_PKTS),
+ EF10_DMA_STAT(port_rx_unicast, RX_UNICAST_PKTS),
+ EF10_DMA_STAT(port_rx_multicast, RX_MULTICAST_PKTS),
+ EF10_DMA_STAT(port_rx_broadcast, RX_BROADCAST_PKTS),
+ EF10_DMA_STAT(port_rx_lt64, RX_UNDERSIZE_PKTS),
+ EF10_DMA_STAT(port_rx_64, RX_64_PKTS),
+ EF10_DMA_STAT(port_rx_65_to_127, RX_65_TO_127_PKTS),
+ EF10_DMA_STAT(port_rx_128_to_255, RX_128_TO_255_PKTS),
+ EF10_DMA_STAT(port_rx_256_to_511, RX_256_TO_511_PKTS),
+ EF10_DMA_STAT(port_rx_512_to_1023, RX_512_TO_1023_PKTS),
+ EF10_DMA_STAT(port_rx_1024_to_15xx, RX_1024_TO_15XX_PKTS),
+ EF10_DMA_STAT(port_rx_15xx_to_jumbo, RX_15XX_TO_JUMBO_PKTS),
+ EF10_DMA_STAT(port_rx_gtjumbo, RX_GTJUMBO_PKTS),
+ EF10_DMA_STAT(port_rx_bad_gtjumbo, RX_JABBER_PKTS),
+ EF10_DMA_STAT(port_rx_overflow, RX_OVERFLOW_PKTS),
+ EF10_DMA_STAT(port_rx_align_error, RX_ALIGN_ERROR_PKTS),
+ EF10_DMA_STAT(port_rx_length_error, RX_LENGTH_ERROR_PKTS),
+ EF10_DMA_STAT(port_rx_nodesc_drops, RX_NODESC_DROPS),
GENERIC_SW_STAT(rx_nodesc_trunc),
GENERIC_SW_STAT(rx_noskb_drops),
- EF10_DMA_STAT(rx_pm_trunc_bb_overflow, PM_TRUNC_BB_OVERFLOW),
- EF10_DMA_STAT(rx_pm_discard_bb_overflow, PM_DISCARD_BB_OVERFLOW),
- EF10_DMA_STAT(rx_pm_trunc_vfifo_full, PM_TRUNC_VFIFO_FULL),
- EF10_DMA_STAT(rx_pm_discard_vfifo_full, PM_DISCARD_VFIFO_FULL),
- EF10_DMA_STAT(rx_pm_trunc_qbb, PM_TRUNC_QBB),
- EF10_DMA_STAT(rx_pm_discard_qbb, PM_DISCARD_QBB),
- EF10_DMA_STAT(rx_pm_discard_mapping, PM_DISCARD_MAPPING),
- EF10_DMA_STAT(rx_dp_q_disabled_packets, RXDP_Q_DISABLED_PKTS),
- EF10_DMA_STAT(rx_dp_di_dropped_packets, RXDP_DI_DROPPED_PKTS),
- EF10_DMA_STAT(rx_dp_streaming_packets, RXDP_STREAMING_PKTS),
- EF10_DMA_STAT(rx_dp_hlb_fetch, RXDP_EMERGENCY_FETCH_CONDITIONS),
- EF10_DMA_STAT(rx_dp_hlb_wait, RXDP_EMERGENCY_WAIT_CONDITIONS),
+ EF10_DMA_STAT(port_rx_pm_trunc_bb_overflow, PM_TRUNC_BB_OVERFLOW),
+ EF10_DMA_STAT(port_rx_pm_discard_bb_overflow, PM_DISCARD_BB_OVERFLOW),
+ EF10_DMA_STAT(port_rx_pm_trunc_vfifo_full, PM_TRUNC_VFIFO_FULL),
+ EF10_DMA_STAT(port_rx_pm_discard_vfifo_full, PM_DISCARD_VFIFO_FULL),
+ EF10_DMA_STAT(port_rx_pm_trunc_qbb, PM_TRUNC_QBB),
+ EF10_DMA_STAT(port_rx_pm_discard_qbb, PM_DISCARD_QBB),
+ EF10_DMA_STAT(port_rx_pm_discard_mapping, PM_DISCARD_MAPPING),
+ EF10_DMA_STAT(port_rx_dp_q_disabled_packets, RXDP_Q_DISABLED_PKTS),
+ EF10_DMA_STAT(port_rx_dp_di_dropped_packets, RXDP_DI_DROPPED_PKTS),
+ EF10_DMA_STAT(port_rx_dp_streaming_packets, RXDP_STREAMING_PKTS),
+ EF10_DMA_STAT(port_rx_dp_hlb_fetch, RXDP_HLB_FETCH_CONDITIONS),
+ EF10_DMA_STAT(port_rx_dp_hlb_wait, RXDP_HLB_WAIT_CONDITIONS),
+ EF10_DMA_STAT(rx_unicast, VADAPTER_RX_UNICAST_PACKETS),
+ EF10_DMA_STAT(rx_unicast_bytes, VADAPTER_RX_UNICAST_BYTES),
+ EF10_DMA_STAT(rx_multicast, VADAPTER_RX_MULTICAST_PACKETS),
+ EF10_DMA_STAT(rx_multicast_bytes, VADAPTER_RX_MULTICAST_BYTES),
+ EF10_DMA_STAT(rx_broadcast, VADAPTER_RX_BROADCAST_PACKETS),
+ EF10_DMA_STAT(rx_broadcast_bytes, VADAPTER_RX_BROADCAST_BYTES),
+ EF10_DMA_STAT(rx_bad, VADAPTER_RX_BAD_PACKETS),
+ EF10_DMA_STAT(rx_bad_bytes, VADAPTER_RX_BAD_BYTES),
+ EF10_DMA_STAT(rx_overflow, VADAPTER_RX_OVERFLOW),
+ EF10_DMA_STAT(tx_unicast, VADAPTER_TX_UNICAST_PACKETS),
+ EF10_DMA_STAT(tx_unicast_bytes, VADAPTER_TX_UNICAST_BYTES),
+ EF10_DMA_STAT(tx_multicast, VADAPTER_TX_MULTICAST_PACKETS),
+ EF10_DMA_STAT(tx_multicast_bytes, VADAPTER_TX_MULTICAST_BYTES),
+ EF10_DMA_STAT(tx_broadcast, VADAPTER_TX_BROADCAST_PACKETS),
+ EF10_DMA_STAT(tx_broadcast_bytes, VADAPTER_TX_BROADCAST_BYTES),
+ EF10_DMA_STAT(tx_bad, VADAPTER_TX_BAD_PACKETS),
+ EF10_DMA_STAT(tx_bad_bytes, VADAPTER_TX_BAD_BYTES),
+ EF10_DMA_STAT(tx_overflow, VADAPTER_TX_OVERFLOW),
};
-#define HUNT_COMMON_STAT_MASK ((1ULL << EF10_STAT_tx_bytes) | \
- (1ULL << EF10_STAT_tx_packets) | \
- (1ULL << EF10_STAT_tx_pause) | \
- (1ULL << EF10_STAT_tx_unicast) | \
- (1ULL << EF10_STAT_tx_multicast) | \
- (1ULL << EF10_STAT_tx_broadcast) | \
- (1ULL << EF10_STAT_rx_bytes) | \
- (1ULL << EF10_STAT_rx_bytes_minus_good_bytes) | \
- (1ULL << EF10_STAT_rx_good_bytes) | \
- (1ULL << EF10_STAT_rx_bad_bytes) | \
- (1ULL << EF10_STAT_rx_packets) | \
- (1ULL << EF10_STAT_rx_good) | \
- (1ULL << EF10_STAT_rx_bad) | \
- (1ULL << EF10_STAT_rx_pause) | \
- (1ULL << EF10_STAT_rx_control) | \
- (1ULL << EF10_STAT_rx_unicast) | \
- (1ULL << EF10_STAT_rx_multicast) | \
- (1ULL << EF10_STAT_rx_broadcast) | \
- (1ULL << EF10_STAT_rx_lt64) | \
- (1ULL << EF10_STAT_rx_64) | \
- (1ULL << EF10_STAT_rx_65_to_127) | \
- (1ULL << EF10_STAT_rx_128_to_255) | \
- (1ULL << EF10_STAT_rx_256_to_511) | \
- (1ULL << EF10_STAT_rx_512_to_1023) | \
- (1ULL << EF10_STAT_rx_1024_to_15xx) | \
- (1ULL << EF10_STAT_rx_15xx_to_jumbo) | \
- (1ULL << EF10_STAT_rx_gtjumbo) | \
- (1ULL << EF10_STAT_rx_bad_gtjumbo) | \
- (1ULL << EF10_STAT_rx_overflow) | \
- (1ULL << EF10_STAT_rx_nodesc_drops) | \
+#define HUNT_COMMON_STAT_MASK ((1ULL << EF10_STAT_port_tx_bytes) | \
+ (1ULL << EF10_STAT_port_tx_packets) | \
+ (1ULL << EF10_STAT_port_tx_pause) | \
+ (1ULL << EF10_STAT_port_tx_unicast) | \
+ (1ULL << EF10_STAT_port_tx_multicast) | \
+ (1ULL << EF10_STAT_port_tx_broadcast) | \
+ (1ULL << EF10_STAT_port_rx_bytes) | \
+ (1ULL << \
+ EF10_STAT_port_rx_bytes_minus_good_bytes) | \
+ (1ULL << EF10_STAT_port_rx_good_bytes) | \
+ (1ULL << EF10_STAT_port_rx_bad_bytes) | \
+ (1ULL << EF10_STAT_port_rx_packets) | \
+ (1ULL << EF10_STAT_port_rx_good) | \
+ (1ULL << EF10_STAT_port_rx_bad) | \
+ (1ULL << EF10_STAT_port_rx_pause) | \
+ (1ULL << EF10_STAT_port_rx_control) | \
+ (1ULL << EF10_STAT_port_rx_unicast) | \
+ (1ULL << EF10_STAT_port_rx_multicast) | \
+ (1ULL << EF10_STAT_port_rx_broadcast) | \
+ (1ULL << EF10_STAT_port_rx_lt64) | \
+ (1ULL << EF10_STAT_port_rx_64) | \
+ (1ULL << EF10_STAT_port_rx_65_to_127) | \
+ (1ULL << EF10_STAT_port_rx_128_to_255) | \
+ (1ULL << EF10_STAT_port_rx_256_to_511) | \
+ (1ULL << EF10_STAT_port_rx_512_to_1023) |\
+ (1ULL << EF10_STAT_port_rx_1024_to_15xx) |\
+ (1ULL << EF10_STAT_port_rx_15xx_to_jumbo) |\
+ (1ULL << EF10_STAT_port_rx_gtjumbo) | \
+ (1ULL << EF10_STAT_port_rx_bad_gtjumbo) |\
+ (1ULL << EF10_STAT_port_rx_overflow) | \
+ (1ULL << EF10_STAT_port_rx_nodesc_drops) |\
(1ULL << GENERIC_STAT_rx_nodesc_trunc) | \
(1ULL << GENERIC_STAT_rx_noskb_drops))
@@ -854,39 +1124,39 @@ static const struct efx_hw_stat_desc efx_ef10_stat_desc[EF10_STAT_COUNT] = {
* switchable port we do not expose these because they might not
* include all the packets they should.
*/
-#define HUNT_10G_ONLY_STAT_MASK ((1ULL << EF10_STAT_tx_control) | \
- (1ULL << EF10_STAT_tx_lt64) | \
- (1ULL << EF10_STAT_tx_64) | \
- (1ULL << EF10_STAT_tx_65_to_127) | \
- (1ULL << EF10_STAT_tx_128_to_255) | \
- (1ULL << EF10_STAT_tx_256_to_511) | \
- (1ULL << EF10_STAT_tx_512_to_1023) | \
- (1ULL << EF10_STAT_tx_1024_to_15xx) | \
- (1ULL << EF10_STAT_tx_15xx_to_jumbo))
+#define HUNT_10G_ONLY_STAT_MASK ((1ULL << EF10_STAT_port_tx_control) | \
+ (1ULL << EF10_STAT_port_tx_lt64) | \
+ (1ULL << EF10_STAT_port_tx_64) | \
+ (1ULL << EF10_STAT_port_tx_65_to_127) |\
+ (1ULL << EF10_STAT_port_tx_128_to_255) |\
+ (1ULL << EF10_STAT_port_tx_256_to_511) |\
+ (1ULL << EF10_STAT_port_tx_512_to_1023) |\
+ (1ULL << EF10_STAT_port_tx_1024_to_15xx) |\
+ (1ULL << EF10_STAT_port_tx_15xx_to_jumbo))
/* These statistics are only provided by the 40G MAC. For a 10G/40G
* switchable port we do expose these because the errors will otherwise
* be silent.
*/
-#define HUNT_40G_EXTRA_STAT_MASK ((1ULL << EF10_STAT_rx_align_error) | \
- (1ULL << EF10_STAT_rx_length_error))
+#define HUNT_40G_EXTRA_STAT_MASK ((1ULL << EF10_STAT_port_rx_align_error) |\
+ (1ULL << EF10_STAT_port_rx_length_error))
/* These statistics are only provided if the firmware supports the
* capability PM_AND_RXDP_COUNTERS.
*/
#define HUNT_PM_AND_RXDP_STAT_MASK ( \
- (1ULL << EF10_STAT_rx_pm_trunc_bb_overflow) | \
- (1ULL << EF10_STAT_rx_pm_discard_bb_overflow) | \
- (1ULL << EF10_STAT_rx_pm_trunc_vfifo_full) | \
- (1ULL << EF10_STAT_rx_pm_discard_vfifo_full) | \
- (1ULL << EF10_STAT_rx_pm_trunc_qbb) | \
- (1ULL << EF10_STAT_rx_pm_discard_qbb) | \
- (1ULL << EF10_STAT_rx_pm_discard_mapping) | \
- (1ULL << EF10_STAT_rx_dp_q_disabled_packets) | \
- (1ULL << EF10_STAT_rx_dp_di_dropped_packets) | \
- (1ULL << EF10_STAT_rx_dp_streaming_packets) | \
- (1ULL << EF10_STAT_rx_dp_hlb_fetch) | \
- (1ULL << EF10_STAT_rx_dp_hlb_wait))
+ (1ULL << EF10_STAT_port_rx_pm_trunc_bb_overflow) | \
+ (1ULL << EF10_STAT_port_rx_pm_discard_bb_overflow) | \
+ (1ULL << EF10_STAT_port_rx_pm_trunc_vfifo_full) | \
+ (1ULL << EF10_STAT_port_rx_pm_discard_vfifo_full) | \
+ (1ULL << EF10_STAT_port_rx_pm_trunc_qbb) | \
+ (1ULL << EF10_STAT_port_rx_pm_discard_qbb) | \
+ (1ULL << EF10_STAT_port_rx_pm_discard_mapping) | \
+ (1ULL << EF10_STAT_port_rx_dp_q_disabled_packets) | \
+ (1ULL << EF10_STAT_port_rx_dp_di_dropped_packets) | \
+ (1ULL << EF10_STAT_port_rx_dp_streaming_packets) | \
+ (1ULL << EF10_STAT_port_rx_dp_hlb_fetch) | \
+ (1ULL << EF10_STAT_port_rx_dp_hlb_wait))
static u64 efx_ef10_raw_stat_mask(struct efx_nic *efx)
{
@@ -894,6 +1164,10 @@ static u64 efx_ef10_raw_stat_mask(struct efx_nic *efx)
u32 port_caps = efx_mcdi_phy_get_caps(efx);
struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ if (!(efx->mcdi->fn_flags &
+ 1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL))
+ return 0;
+
if (port_caps & (1 << MC_CMD_PHY_CAP_40000FDX_LBN))
raw_mask |= HUNT_40G_EXTRA_STAT_MASK;
else
@@ -908,13 +1182,28 @@ static u64 efx_ef10_raw_stat_mask(struct efx_nic *efx)
static void efx_ef10_get_stat_mask(struct efx_nic *efx, unsigned long *mask)
{
- u64 raw_mask = efx_ef10_raw_stat_mask(efx);
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ u64 raw_mask[2];
+
+ raw_mask[0] = efx_ef10_raw_stat_mask(efx);
+
+ /* Only show vadaptor stats when EVB capability is present */
+ if (nic_data->datapath_caps &
+ (1 << MC_CMD_GET_CAPABILITIES_OUT_EVB_LBN)) {
+ raw_mask[0] |= ~((1ULL << EF10_STAT_rx_unicast) - 1);
+ raw_mask[1] = (1ULL << (EF10_STAT_COUNT - 63)) - 1;
+ } else {
+ raw_mask[1] = 0;
+ }
#if BITS_PER_LONG == 64
- mask[0] = raw_mask;
+ mask[0] = raw_mask[0];
+ mask[1] = raw_mask[1];
#else
- mask[0] = raw_mask & 0xffffffff;
- mask[1] = raw_mask >> 32;
+ mask[0] = raw_mask[0] & 0xffffffff;
+ mask[1] = raw_mask[0] >> 32;
+ mask[2] = raw_mask[1] & 0xffffffff;
+ mask[3] = raw_mask[1] >> 32;
#endif
}
@@ -927,7 +1216,51 @@ static size_t efx_ef10_describe_stats(struct efx_nic *efx, u8 *names)
mask, names);
}
-static int efx_ef10_try_update_nic_stats(struct efx_nic *efx)
+static size_t efx_ef10_update_stats_common(struct efx_nic *efx, u64 *full_stats,
+ struct rtnl_link_stats64 *core_stats)
+{
+ DECLARE_BITMAP(mask, EF10_STAT_COUNT);
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ u64 *stats = nic_data->stats;
+ size_t stats_count = 0, index;
+
+ efx_ef10_get_stat_mask(efx, mask);
+
+ if (full_stats) {
+ for_each_set_bit(index, mask, EF10_STAT_COUNT) {
+ if (efx_ef10_stat_desc[index].name) {
+ *full_stats++ = stats[index];
+ ++stats_count;
+ }
+ }
+ }
+
+ if (core_stats) {
+ core_stats->rx_packets = stats[EF10_STAT_rx_unicast] +
+ stats[EF10_STAT_rx_multicast] +
+ stats[EF10_STAT_rx_broadcast];
+ core_stats->tx_packets = stats[EF10_STAT_tx_unicast] +
+ stats[EF10_STAT_tx_multicast] +
+ stats[EF10_STAT_tx_broadcast];
+ core_stats->rx_bytes = stats[EF10_STAT_rx_unicast_bytes] +
+ stats[EF10_STAT_rx_multicast_bytes] +
+ stats[EF10_STAT_rx_broadcast_bytes];
+ core_stats->tx_bytes = stats[EF10_STAT_tx_unicast_bytes] +
+ stats[EF10_STAT_tx_multicast_bytes] +
+ stats[EF10_STAT_tx_broadcast_bytes];
+ core_stats->rx_dropped = stats[GENERIC_STAT_rx_nodesc_trunc] +
+ stats[GENERIC_STAT_rx_noskb_drops];
+ core_stats->multicast = stats[EF10_STAT_rx_multicast];
+ core_stats->rx_crc_errors = stats[EF10_STAT_rx_bad];
+ core_stats->rx_fifo_errors = stats[EF10_STAT_rx_overflow];
+ core_stats->rx_errors = core_stats->rx_crc_errors;
+ core_stats->tx_errors = stats[EF10_STAT_tx_bad];
+ }
+
+ return stats_count;
+}
+
+static int efx_ef10_try_update_nic_stats_pf(struct efx_nic *efx)
{
struct efx_ef10_nic_data *nic_data = efx->nic_data;
DECLARE_BITMAP(mask, EF10_STAT_COUNT);
@@ -952,67 +1285,114 @@ static int efx_ef10_try_update_nic_stats(struct efx_nic *efx)
return -EAGAIN;
/* Update derived statistics */
- efx_nic_fix_nodesc_drop_stat(efx, &stats[EF10_STAT_rx_nodesc_drops]);
- stats[EF10_STAT_rx_good_bytes] =
- stats[EF10_STAT_rx_bytes] -
- stats[EF10_STAT_rx_bytes_minus_good_bytes];
- efx_update_diff_stat(&stats[EF10_STAT_rx_bad_bytes],
- stats[EF10_STAT_rx_bytes_minus_good_bytes]);
+ efx_nic_fix_nodesc_drop_stat(efx,
+ &stats[EF10_STAT_port_rx_nodesc_drops]);
+ stats[EF10_STAT_port_rx_good_bytes] =
+ stats[EF10_STAT_port_rx_bytes] -
+ stats[EF10_STAT_port_rx_bytes_minus_good_bytes];
+ efx_update_diff_stat(&stats[EF10_STAT_port_rx_bad_bytes],
+ stats[EF10_STAT_port_rx_bytes_minus_good_bytes]);
efx_update_sw_stats(efx, stats);
return 0;
}
-static size_t efx_ef10_update_stats(struct efx_nic *efx, u64 *full_stats,
- struct rtnl_link_stats64 *core_stats)
+static size_t efx_ef10_update_stats_pf(struct efx_nic *efx, u64 *full_stats,
+ struct rtnl_link_stats64 *core_stats)
{
- DECLARE_BITMAP(mask, EF10_STAT_COUNT);
- struct efx_ef10_nic_data *nic_data = efx->nic_data;
- u64 *stats = nic_data->stats;
- size_t stats_count = 0, index;
int retry;
- efx_ef10_get_stat_mask(efx, mask);
-
/* If we're unlucky enough to read statistics during the DMA, wait
* up to 10ms for it to finish (typically takes <500us)
*/
for (retry = 0; retry < 100; ++retry) {
- if (efx_ef10_try_update_nic_stats(efx) == 0)
+ if (efx_ef10_try_update_nic_stats_pf(efx) == 0)
break;
udelay(100);
}
- if (full_stats) {
- for_each_set_bit(index, mask, EF10_STAT_COUNT) {
- if (efx_ef10_stat_desc[index].name) {
- *full_stats++ = stats[index];
- ++stats_count;
- }
- }
+ return efx_ef10_update_stats_common(efx, full_stats, core_stats);
+}
+
+static int efx_ef10_try_update_nic_stats_vf(struct efx_nic *efx)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_MAC_STATS_IN_LEN);
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ DECLARE_BITMAP(mask, EF10_STAT_COUNT);
+ __le64 generation_start, generation_end;
+ u64 *stats = nic_data->stats;
+ u32 dma_len = MC_CMD_MAC_NSTATS * sizeof(u64);
+ struct efx_buffer stats_buf;
+ __le64 *dma_stats;
+ int rc;
+
+ spin_unlock_bh(&efx->stats_lock);
+
+ if (in_interrupt()) {
+ /* If in atomic context, cannot update stats. Just update the
+ * software stats and return so the caller can continue.
+ */
+ spin_lock_bh(&efx->stats_lock);
+ efx_update_sw_stats(efx, stats);
+ return 0;
}
- if (core_stats) {
- core_stats->rx_packets = stats[EF10_STAT_rx_packets];
- core_stats->tx_packets = stats[EF10_STAT_tx_packets];
- core_stats->rx_bytes = stats[EF10_STAT_rx_bytes];
- core_stats->tx_bytes = stats[EF10_STAT_tx_bytes];
- core_stats->rx_dropped = stats[EF10_STAT_rx_nodesc_drops] +
- stats[GENERIC_STAT_rx_nodesc_trunc] +
- stats[GENERIC_STAT_rx_noskb_drops];
- core_stats->multicast = stats[EF10_STAT_rx_multicast];
- core_stats->rx_length_errors =
- stats[EF10_STAT_rx_gtjumbo] +
- stats[EF10_STAT_rx_length_error];
- core_stats->rx_crc_errors = stats[EF10_STAT_rx_bad];
- core_stats->rx_frame_errors = stats[EF10_STAT_rx_align_error];
- core_stats->rx_fifo_errors = stats[EF10_STAT_rx_overflow];
- core_stats->rx_errors = (core_stats->rx_length_errors +
- core_stats->rx_crc_errors +
- core_stats->rx_frame_errors);
+ efx_ef10_get_stat_mask(efx, mask);
+
+ rc = efx_nic_alloc_buffer(efx, &stats_buf, dma_len, GFP_ATOMIC);
+ if (rc) {
+ spin_lock_bh(&efx->stats_lock);
+ return rc;
}
- return stats_count;
+ dma_stats = stats_buf.addr;
+ dma_stats[MC_CMD_MAC_GENERATION_END] = EFX_MC_STATS_GENERATION_INVALID;
+
+ MCDI_SET_QWORD(inbuf, MAC_STATS_IN_DMA_ADDR, stats_buf.dma_addr);
+ MCDI_POPULATE_DWORD_1(inbuf, MAC_STATS_IN_CMD,
+ MAC_STATS_IN_DMA, 1);
+ MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_LEN, dma_len);
+ MCDI_SET_DWORD(inbuf, MAC_STATS_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
+
+ rc = efx_mcdi_rpc_quiet(efx, MC_CMD_MAC_STATS, inbuf, sizeof(inbuf),
+ NULL, 0, NULL);
+ spin_lock_bh(&efx->stats_lock);
+ if (rc) {
+ /* Expect ENOENT if DMA queues have not been set up */
+ if (rc != -ENOENT || atomic_read(&efx->active_queues))
+ efx_mcdi_display_error(efx, MC_CMD_MAC_STATS,
+ sizeof(inbuf), NULL, 0, rc);
+ goto out;
+ }
+
+ generation_end = dma_stats[MC_CMD_MAC_GENERATION_END];
+ if (generation_end == EFX_MC_STATS_GENERATION_INVALID) {
+ WARN_ON_ONCE(1);
+ goto out;
+ }
+ rmb();
+ efx_nic_update_stats(efx_ef10_stat_desc, EF10_STAT_COUNT, mask,
+ stats, stats_buf.addr, false);
+ rmb();
+ generation_start = dma_stats[MC_CMD_MAC_GENERATION_START];
+ if (generation_end != generation_start) {
+ rc = -EAGAIN;
+ goto out;
+ }
+
+ efx_update_sw_stats(efx, stats);
+out:
+ efx_nic_free_buffer(efx, &stats_buf);
+ return rc;
+}
+
+static size_t efx_ef10_update_stats_vf(struct efx_nic *efx, u64 *full_stats,
+ struct rtnl_link_stats64 *core_stats)
+{
+ if (efx_ef10_try_update_nic_stats_vf(efx))
+ return 0;
+
+ return efx_ef10_update_stats_common(efx, full_stats, core_stats);
}
static void efx_ef10_push_irq_moderation(struct efx_channel *channel)
@@ -1044,6 +1424,14 @@ static void efx_ef10_push_irq_moderation(struct efx_channel *channel)
}
}
+static void efx_ef10_get_wol_vf(struct efx_nic *efx,
+ struct ethtool_wolinfo *wol) {}
+
+static int efx_ef10_set_wol_vf(struct efx_nic *efx, u32 type)
+{
+ return -EOPNOTSUPP;
+}
+
static void efx_ef10_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol)
{
wol->supported = 0;
@@ -1123,13 +1511,17 @@ static int efx_ef10_mcdi_poll_reboot(struct efx_nic *efx)
/* All our allocations have been reset */
efx_ef10_reset_mc_allocations(efx);
+ /* Driver-created vswitches and vports must be re-created */
+ nic_data->must_probe_vswitching = true;
+ nic_data->vport_id = EVB_PORT_ID_ASSIGNED;
+
/* The datapath firmware might have been changed */
nic_data->must_check_datapath_caps = true;
/* MAC statistics have been cleared on the NIC; clear the local
* statistic that we update with efx_update_diff_stat().
*/
- nic_data->stats[EF10_STAT_rx_bad_bytes] = 0;
+ nic_data->stats[EF10_STAT_port_rx_bad_bytes] = 0;
return -EIO;
}
@@ -1232,16 +1624,17 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_INIT_TXQ_IN_LEN(EFX_MAX_DMAQ_SIZE * 8 /
EFX_BUF_SIZE));
- MCDI_DECLARE_BUF(outbuf, MC_CMD_INIT_TXQ_OUT_LEN);
bool csum_offload = tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD;
size_t entries = tx_queue->txd.buf.len / EFX_BUF_SIZE;
struct efx_channel *channel = tx_queue->channel;
struct efx_nic *efx = tx_queue->efx;
- size_t inlen, outlen;
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ size_t inlen;
dma_addr_t dma_addr;
efx_qword_t *txd;
int rc;
int i;
+ BUILD_BUG_ON(MC_CMD_INIT_TXQ_OUT_LEN != 0);
MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_SIZE, tx_queue->ptr_mask + 1);
MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_TARGET_EVQ, channel->channel);
@@ -1251,7 +1644,7 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
INIT_TXQ_IN_FLAG_IP_CSUM_DIS, !csum_offload,
INIT_TXQ_IN_FLAG_TCP_CSUM_DIS, !csum_offload);
MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_OWNER_ID, 0);
- MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
+ MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_PORT_ID, nic_data->vport_id);
dma_addr = tx_queue->txd.buf.dma_addr;
@@ -1266,7 +1659,7 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
inlen = MC_CMD_INIT_TXQ_IN_LEN(entries);
rc = efx_mcdi_rpc(efx, MC_CMD_INIT_TXQ, inbuf, inlen,
- outbuf, sizeof(outbuf), &outlen);
+ NULL, 0, NULL);
if (rc)
goto fail;
@@ -1299,7 +1692,7 @@ fail:
static void efx_ef10_tx_fini(struct efx_tx_queue *tx_queue)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_FINI_TXQ_IN_LEN);
- MCDI_DECLARE_BUF(outbuf, MC_CMD_FINI_TXQ_OUT_LEN);
+ MCDI_DECLARE_BUF_ERR(outbuf);
struct efx_nic *efx = tx_queue->efx;
size_t outlen;
int rc;
@@ -1378,19 +1771,33 @@ static void efx_ef10_tx_write(struct efx_tx_queue *tx_queue)
}
}
-static int efx_ef10_alloc_rss_context(struct efx_nic *efx, u32 *context)
+static int efx_ef10_alloc_rss_context(struct efx_nic *efx, u32 *context,
+ bool exclusive, unsigned *context_size)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN);
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
size_t outlen;
int rc;
+ u32 alloc_type = exclusive ?
+ MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE :
+ MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_SHARED;
+ unsigned rss_spread = exclusive ?
+ efx->rss_spread :
+ min(rounddown_pow_of_two(efx->rss_spread),
+ EFX_EF10_MAX_SHARED_RSS_CONTEXT_SIZE);
+
+ if (!exclusive && rss_spread == 1) {
+ *context = EFX_EF10_RSS_CONTEXT_INVALID;
+ if (context_size)
+ *context_size = 1;
+ return 0;
+ }
MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID,
- EVB_PORT_ID_ASSIGNED);
- MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_TYPE,
- MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE);
- MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES,
- EFX_MAX_CHANNELS);
+ nic_data->vport_id);
+ MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_TYPE, alloc_type);
+ MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, rss_spread);
rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_ALLOC, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), &outlen);
@@ -1402,6 +1809,9 @@ static int efx_ef10_alloc_rss_context(struct efx_nic *efx, u32 *context)
*context = MCDI_DWORD(outbuf, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID);
+ if (context_size)
+ *context_size = rss_spread;
+
return 0;
}
@@ -1418,7 +1828,8 @@ static void efx_ef10_free_rss_context(struct efx_nic *efx, u32 context)
WARN_ON(rc != 0);
}
-static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context)
+static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context,
+ const u32 *rx_indir_table)
{
MCDI_DECLARE_BUF(tablebuf, MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN);
MCDI_DECLARE_BUF(keybuf, MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN);
@@ -1432,7 +1843,7 @@ static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context)
for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); ++i)
MCDI_PTR(tablebuf,
RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE)[i] =
- (u8) efx->rx_indir_table[i];
+ (u8) rx_indir_table[i];
rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_SET_TABLE, tablebuf,
sizeof(tablebuf), NULL, 0, NULL);
@@ -1460,27 +1871,119 @@ static void efx_ef10_rx_free_indir_table(struct efx_nic *efx)
nic_data->rx_rss_context = EFX_EF10_RSS_CONTEXT_INVALID;
}
-static void efx_ef10_rx_push_rss_config(struct efx_nic *efx)
+static int efx_ef10_rx_push_shared_rss_config(struct efx_nic *efx,
+ unsigned *context_size)
{
+ u32 new_rx_rss_context;
struct efx_ef10_nic_data *nic_data = efx->nic_data;
- int rc;
+ int rc = efx_ef10_alloc_rss_context(efx, &new_rx_rss_context,
+ false, context_size);
- netif_dbg(efx, drv, efx->net_dev, "pushing RSS config\n");
+ if (rc != 0)
+ return rc;
- if (nic_data->rx_rss_context == EFX_EF10_RSS_CONTEXT_INVALID) {
- rc = efx_ef10_alloc_rss_context(efx, &nic_data->rx_rss_context);
- if (rc != 0)
- goto fail;
+ nic_data->rx_rss_context = new_rx_rss_context;
+ nic_data->rx_rss_context_exclusive = false;
+ efx_set_default_rx_indir_table(efx);
+ return 0;
+}
+
+static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx,
+ const u32 *rx_indir_table)
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ int rc;
+ u32 new_rx_rss_context;
+
+ if (nic_data->rx_rss_context == EFX_EF10_RSS_CONTEXT_INVALID ||
+ !nic_data->rx_rss_context_exclusive) {
+ rc = efx_ef10_alloc_rss_context(efx, &new_rx_rss_context,
+ true, NULL);
+ if (rc == -EOPNOTSUPP)
+ return rc;
+ else if (rc != 0)
+ goto fail1;
+ } else {
+ new_rx_rss_context = nic_data->rx_rss_context;
}
- rc = efx_ef10_populate_rss_table(efx, nic_data->rx_rss_context);
+ rc = efx_ef10_populate_rss_table(efx, new_rx_rss_context,
+ rx_indir_table);
if (rc != 0)
- goto fail;
+ goto fail2;
- return;
+ if (nic_data->rx_rss_context != new_rx_rss_context)
+ efx_ef10_rx_free_indir_table(efx);
+ nic_data->rx_rss_context = new_rx_rss_context;
+ nic_data->rx_rss_context_exclusive = true;
+ if (rx_indir_table != efx->rx_indir_table)
+ memcpy(efx->rx_indir_table, rx_indir_table,
+ sizeof(efx->rx_indir_table));
+ return 0;
-fail:
+fail2:
+ if (new_rx_rss_context != nic_data->rx_rss_context)
+ efx_ef10_free_rss_context(efx, new_rx_rss_context);
+fail1:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
+ return rc;
+}
+
+static int efx_ef10_pf_rx_push_rss_config(struct efx_nic *efx, bool user,
+ const u32 *rx_indir_table)
+{
+ int rc;
+
+ if (efx->rss_spread == 1)
+ return 0;
+
+ rc = efx_ef10_rx_push_exclusive_rss_config(efx, rx_indir_table);
+
+ if (rc == -ENOBUFS && !user) {
+ unsigned context_size;
+ bool mismatch = false;
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table) && !mismatch;
+ i++)
+ mismatch = rx_indir_table[i] !=
+ ethtool_rxfh_indir_default(i, efx->rss_spread);
+
+ rc = efx_ef10_rx_push_shared_rss_config(efx, &context_size);
+ if (rc == 0) {
+ if (context_size != efx->rss_spread)
+ netif_warn(efx, probe, efx->net_dev,
+ "Could not allocate an exclusive RSS"
+ " context; allocated a shared one of"
+ " different size."
+ " Wanted %u, got %u.\n",
+ efx->rss_spread, context_size);
+ else if (mismatch)
+ netif_warn(efx, probe, efx->net_dev,
+ "Could not allocate an exclusive RSS"
+ " context; allocated a shared one but"
+ " could not apply custom"
+ " indirection.\n");
+ else
+ netif_info(efx, probe, efx->net_dev,
+ "Could not allocate an exclusive RSS"
+ " context; allocated a shared one.\n");
+ }
+ }
+ return rc;
+}
+
+static int efx_ef10_vf_rx_push_rss_config(struct efx_nic *efx, bool user,
+ const u32 *rx_indir_table
+ __attribute__ ((unused)))
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+
+ if (user)
+ return -EOPNOTSUPP;
+ if (nic_data->rx_rss_context != EFX_EF10_RSS_CONTEXT_INVALID)
+ return 0;
+ return efx_ef10_rx_push_shared_rss_config(efx, NULL);
}
static int efx_ef10_rx_probe(struct efx_rx_queue *rx_queue)
@@ -1496,14 +1999,15 @@ static void efx_ef10_rx_init(struct efx_rx_queue *rx_queue)
MCDI_DECLARE_BUF(inbuf,
MC_CMD_INIT_RXQ_IN_LEN(EFX_MAX_DMAQ_SIZE * 8 /
EFX_BUF_SIZE));
- MCDI_DECLARE_BUF(outbuf, MC_CMD_INIT_RXQ_OUT_LEN);
struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
size_t entries = rx_queue->rxd.buf.len / EFX_BUF_SIZE;
struct efx_nic *efx = rx_queue->efx;
- size_t inlen, outlen;
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ size_t inlen;
dma_addr_t dma_addr;
int rc;
int i;
+ BUILD_BUG_ON(MC_CMD_INIT_RXQ_OUT_LEN != 0);
rx_queue->scatter_n = 0;
rx_queue->scatter_len = 0;
@@ -1517,7 +2021,7 @@ static void efx_ef10_rx_init(struct efx_rx_queue *rx_queue)
INIT_RXQ_IN_FLAG_PREFIX, 1,
INIT_RXQ_IN_FLAG_TIMESTAMP, 1);
MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_OWNER_ID, 0);
- MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
+ MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_PORT_ID, nic_data->vport_id);
dma_addr = rx_queue->rxd.buf.dma_addr;
@@ -1532,7 +2036,7 @@ static void efx_ef10_rx_init(struct efx_rx_queue *rx_queue)
inlen = MC_CMD_INIT_RXQ_IN_LEN(entries);
rc = efx_mcdi_rpc(efx, MC_CMD_INIT_RXQ, inbuf, inlen,
- outbuf, sizeof(outbuf), &outlen);
+ NULL, 0, NULL);
if (rc)
netdev_WARN(efx->net_dev, "failed to initialise RXQ %d\n",
efx_rx_queue_index(rx_queue));
@@ -1541,7 +2045,7 @@ static void efx_ef10_rx_init(struct efx_rx_queue *rx_queue)
static void efx_ef10_rx_fini(struct efx_rx_queue *rx_queue)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_FINI_RXQ_IN_LEN);
- MCDI_DECLARE_BUF(outbuf, MC_CMD_FINI_RXQ_OUT_LEN);
+ MCDI_DECLARE_BUF_ERR(outbuf);
struct efx_nic *efx = rx_queue->efx;
size_t outlen;
int rc;
@@ -1703,7 +2207,7 @@ static int efx_ef10_ev_init(struct efx_channel *channel)
static void efx_ef10_ev_fini(struct efx_channel *channel)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_FINI_EVQ_IN_LEN);
- MCDI_DECLARE_BUF(outbuf, MC_CMD_FINI_EVQ_OUT_LEN);
+ MCDI_DECLARE_BUF_ERR(outbuf);
struct efx_nic *efx = channel->efx;
size_t outlen;
int rc;
@@ -2286,11 +2790,12 @@ static void efx_ef10_filter_push_prep(struct efx_nic *efx,
match_fields);
}
- MCDI_SET_DWORD(inbuf, FILTER_OP_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
+ MCDI_SET_DWORD(inbuf, FILTER_OP_IN_PORT_ID, nic_data->vport_id);
MCDI_SET_DWORD(inbuf, FILTER_OP_IN_RX_DEST,
spec->dmaq_id == EFX_FILTER_RX_DMAQ_ID_DROP ?
MC_CMD_FILTER_OP_IN_RX_DEST_DROP :
MC_CMD_FILTER_OP_IN_RX_DEST_HOST);
+ MCDI_SET_DWORD(inbuf, FILTER_OP_IN_TX_DOMAIN, 0);
MCDI_SET_DWORD(inbuf, FILTER_OP_IN_TX_DEST,
MC_CMD_FILTER_OP_IN_TX_DEST_DEFAULT);
MCDI_SET_DWORD(inbuf, FILTER_OP_IN_RX_QUEUE,
@@ -3055,6 +3560,9 @@ fail:
return rc;
}
+/* Caller must hold efx->filter_sem for read if race against
+ * efx_ef10_filter_table_remove() is possible
+ */
static void efx_ef10_filter_table_restore(struct efx_nic *efx)
{
struct efx_ef10_filter_table *table = efx->filter_state;
@@ -3064,9 +3572,14 @@ static void efx_ef10_filter_table_restore(struct efx_nic *efx)
bool failed = false;
int rc;
+ WARN_ON(!rwsem_is_locked(&efx->filter_sem));
+
if (!nic_data->must_restore_filters)
return;
+ if (!table)
+ return;
+
spin_lock_bh(&efx->filter_lock);
for (filter_idx = 0; filter_idx < HUNT_FILTER_TBL_ROWS; filter_idx++) {
@@ -3102,6 +3615,7 @@ static void efx_ef10_filter_table_restore(struct efx_nic *efx)
nic_data->must_restore_filters = false;
}
+/* Caller must hold efx->filter_sem for write */
static void efx_ef10_filter_table_remove(struct efx_nic *efx)
{
struct efx_ef10_filter_table *table = efx->filter_state;
@@ -3110,6 +3624,10 @@ static void efx_ef10_filter_table_remove(struct efx_nic *efx)
unsigned int filter_idx;
int rc;
+ efx->filter_state = NULL;
+ if (!table)
+ return;
+
for (filter_idx = 0; filter_idx < HUNT_FILTER_TBL_ROWS; filter_idx++) {
spec = efx_ef10_filter_entry_spec(table, filter_idx);
if (!spec)
@@ -3135,6 +3653,9 @@ static void efx_ef10_filter_table_remove(struct efx_nic *efx)
kfree(table);
}
+/* Caller must hold efx->filter_sem for read if race against
+ * efx_ef10_filter_table_remove() is possible
+ */
static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
{
struct efx_ef10_filter_table *table = efx->filter_state;
@@ -3149,6 +3670,9 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
if (!efx_dev_registered(efx))
return;
+ if (!table)
+ return;
+
/* Mark old filters that may need to be removed */
spin_lock_bh(&efx->filter_lock);
n = table->dev_uc_count < 0 ? 1 : table->dev_uc_count;
@@ -3280,6 +3804,78 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
WARN_ON(remove_failed);
}
+static int efx_ef10_set_mac_address(struct efx_nic *efx)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_SET_MAC_IN_LEN);
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ bool was_enabled = efx->port_enabled;
+ int rc;
+
+ efx_device_detach_sync(efx);
+ efx_net_stop(efx->net_dev);
+ down_write(&efx->filter_sem);
+ efx_ef10_filter_table_remove(efx);
+
+ ether_addr_copy(MCDI_PTR(inbuf, VADAPTOR_SET_MAC_IN_MACADDR),
+ efx->net_dev->dev_addr);
+ MCDI_SET_DWORD(inbuf, VADAPTOR_SET_MAC_IN_UPSTREAM_PORT_ID,
+ nic_data->vport_id);
+ rc = efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_SET_MAC, inbuf,
+ sizeof(inbuf), NULL, 0, NULL);
+
+ efx_ef10_filter_table_probe(efx);
+ up_write(&efx->filter_sem);
+ if (was_enabled)
+ efx_net_open(efx->net_dev);
+ netif_device_attach(efx->net_dev);
+
+#if !defined(CONFIG_SFC_SRIOV)
+ if (rc == -EPERM)
+ netif_err(efx, drv, efx->net_dev,
+ "Cannot change MAC address; use sfboot to enable mac-spoofing"
+ " on this interface\n");
+#else
+ if (rc == -EPERM) {
+ struct pci_dev *pci_dev_pf = efx->pci_dev->physfn;
+
+ /* Switch to PF and change MAC address on vport */
+ if (efx->pci_dev->is_virtfn && pci_dev_pf) {
+ struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf);
+
+ if (!efx_ef10_sriov_set_vf_mac(efx_pf,
+ nic_data->vf_index,
+ efx->net_dev->dev_addr))
+ return 0;
+ }
+ netif_err(efx, drv, efx->net_dev,
+ "Cannot change MAC address; use sfboot to enable mac-spoofing"
+ " on this interface\n");
+ } else if (efx->pci_dev->is_virtfn) {
+ /* Successfully changed by VF (with MAC spoofing), so update the
+ * parent PF if possible.
+ */
+ struct pci_dev *pci_dev_pf = efx->pci_dev->physfn;
+
+ if (pci_dev_pf) {
+ struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf);
+ struct efx_ef10_nic_data *nic_data = efx_pf->nic_data;
+ unsigned int i;
+
+ for (i = 0; i < efx_pf->vf_count; ++i) {
+ struct ef10_vf *vf = nic_data->vf + i;
+
+ if (vf->efx == efx) {
+ ether_addr_copy(vf->mac,
+ efx->net_dev->dev_addr);
+ return 0;
+ }
+ }
+ }
+ }
+#endif
+ return rc;
+}
+
static int efx_ef10_mac_reconfigure(struct efx_nic *efx)
{
efx_ef10_filter_sync_rx_mode(efx);
@@ -3287,6 +3883,13 @@ static int efx_ef10_mac_reconfigure(struct efx_nic *efx)
return efx_mcdi_set_mac(efx);
}
+static int efx_ef10_mac_reconfigure_vf(struct efx_nic *efx)
+{
+ efx_ef10_filter_sync_rx_mode(efx);
+
+ return 0;
+}
+
static int efx_ef10_start_bist(struct efx_nic *efx, u32 bist_type)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_START_BIST_IN_LEN);
@@ -3494,6 +4097,9 @@ static void efx_ef10_ptp_write_host_time(struct efx_nic *efx, u32 host_time)
_efx_writed(efx, cpu_to_le32(host_time), ER_DZ_MC_DB_LWRD);
}
+static void efx_ef10_ptp_write_host_time_vf(struct efx_nic *efx,
+ u32 host_time) {}
+
static int efx_ef10_rx_enable_timestamping(struct efx_channel *channel,
bool temp)
{
@@ -3571,6 +4177,12 @@ static int efx_ef10_ptp_set_ts_sync_events(struct efx_nic *efx, bool en,
return 0;
}
+static int efx_ef10_ptp_set_ts_config_vf(struct efx_nic *efx,
+ struct hwtstamp_config *init)
+{
+ return -EOPNOTSUPP;
+}
+
static int efx_ef10_ptp_set_ts_config(struct efx_nic *efx,
struct hwtstamp_config *init)
{
@@ -3607,14 +4219,118 @@ static int efx_ef10_ptp_set_ts_config(struct efx_nic *efx,
}
}
+const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
+ .is_vf = true,
+ .mem_bar = EFX_MEM_VF_BAR,
+ .mem_map_size = efx_ef10_mem_map_size,
+ .probe = efx_ef10_probe_vf,
+ .remove = efx_ef10_remove,
+ .dimension_resources = efx_ef10_dimension_resources,
+ .init = efx_ef10_init_nic,
+ .fini = efx_port_dummy_op_void,
+ .map_reset_reason = efx_ef10_map_reset_reason,
+ .map_reset_flags = efx_ef10_map_reset_flags,
+ .reset = efx_ef10_reset,
+ .probe_port = efx_mcdi_port_probe,
+ .remove_port = efx_mcdi_port_remove,
+ .fini_dmaq = efx_ef10_fini_dmaq,
+ .prepare_flr = efx_ef10_prepare_flr,
+ .finish_flr = efx_port_dummy_op_void,
+ .describe_stats = efx_ef10_describe_stats,
+ .update_stats = efx_ef10_update_stats_vf,
+ .start_stats = efx_port_dummy_op_void,
+ .pull_stats = efx_port_dummy_op_void,
+ .stop_stats = efx_port_dummy_op_void,
+ .set_id_led = efx_mcdi_set_id_led,
+ .push_irq_moderation = efx_ef10_push_irq_moderation,
+ .reconfigure_mac = efx_ef10_mac_reconfigure_vf,
+ .check_mac_fault = efx_mcdi_mac_check_fault,
+ .reconfigure_port = efx_mcdi_port_reconfigure,
+ .get_wol = efx_ef10_get_wol_vf,
+ .set_wol = efx_ef10_set_wol_vf,
+ .resume_wol = efx_port_dummy_op_void,
+ .mcdi_request = efx_ef10_mcdi_request,
+ .mcdi_poll_response = efx_ef10_mcdi_poll_response,
+ .mcdi_read_response = efx_ef10_mcdi_read_response,
+ .mcdi_poll_reboot = efx_ef10_mcdi_poll_reboot,
+ .irq_enable_master = efx_port_dummy_op_void,
+ .irq_test_generate = efx_ef10_irq_test_generate,
+ .irq_disable_non_ev = efx_port_dummy_op_void,
+ .irq_handle_msi = efx_ef10_msi_interrupt,
+ .irq_handle_legacy = efx_ef10_legacy_interrupt,
+ .tx_probe = efx_ef10_tx_probe,
+ .tx_init = efx_ef10_tx_init,
+ .tx_remove = efx_ef10_tx_remove,
+ .tx_write = efx_ef10_tx_write,
+ .rx_push_rss_config = efx_ef10_vf_rx_push_rss_config,
+ .rx_probe = efx_ef10_rx_probe,
+ .rx_init = efx_ef10_rx_init,
+ .rx_remove = efx_ef10_rx_remove,
+ .rx_write = efx_ef10_rx_write,
+ .rx_defer_refill = efx_ef10_rx_defer_refill,
+ .ev_probe = efx_ef10_ev_probe,
+ .ev_init = efx_ef10_ev_init,
+ .ev_fini = efx_ef10_ev_fini,
+ .ev_remove = efx_ef10_ev_remove,
+ .ev_process = efx_ef10_ev_process,
+ .ev_read_ack = efx_ef10_ev_read_ack,
+ .ev_test_generate = efx_ef10_ev_test_generate,
+ .filter_table_probe = efx_ef10_filter_table_probe,
+ .filter_table_restore = efx_ef10_filter_table_restore,
+ .filter_table_remove = efx_ef10_filter_table_remove,
+ .filter_update_rx_scatter = efx_ef10_filter_update_rx_scatter,
+ .filter_insert = efx_ef10_filter_insert,
+ .filter_remove_safe = efx_ef10_filter_remove_safe,
+ .filter_get_safe = efx_ef10_filter_get_safe,
+ .filter_clear_rx = efx_ef10_filter_clear_rx,
+ .filter_count_rx_used = efx_ef10_filter_count_rx_used,
+ .filter_get_rx_id_limit = efx_ef10_filter_get_rx_id_limit,
+ .filter_get_rx_ids = efx_ef10_filter_get_rx_ids,
+#ifdef CONFIG_RFS_ACCEL
+ .filter_rfs_insert = efx_ef10_filter_rfs_insert,
+ .filter_rfs_expire_one = efx_ef10_filter_rfs_expire_one,
+#endif
+#ifdef CONFIG_SFC_MTD
+ .mtd_probe = efx_port_dummy_op_int,
+#endif
+ .ptp_write_host_time = efx_ef10_ptp_write_host_time_vf,
+ .ptp_set_ts_config = efx_ef10_ptp_set_ts_config_vf,
+#ifdef CONFIG_SFC_SRIOV
+ .vswitching_probe = efx_ef10_vswitching_probe_vf,
+ .vswitching_restore = efx_ef10_vswitching_restore_vf,
+ .vswitching_remove = efx_ef10_vswitching_remove_vf,
+ .sriov_get_phys_port_id = efx_ef10_sriov_get_phys_port_id,
+#endif
+ .get_mac_address = efx_ef10_get_mac_address_vf,
+ .set_mac_address = efx_ef10_set_mac_address,
+
+ .revision = EFX_REV_HUNT_A0,
+ .max_dma_mask = DMA_BIT_MASK(ESF_DZ_TX_KER_BUF_ADDR_WIDTH),
+ .rx_prefix_size = ES_DZ_RX_PREFIX_SIZE,
+ .rx_hash_offset = ES_DZ_RX_PREFIX_HASH_OFST,
+ .rx_ts_offset = ES_DZ_RX_PREFIX_TSTAMP_OFST,
+ .can_rx_scatter = true,
+ .always_rx_scatter = true,
+ .max_interrupt_mode = EFX_INT_MODE_MSIX,
+ .timer_period_max = 1 << ERF_DD_EVQ_IND_TIMER_VAL_WIDTH,
+ .offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_RXHASH | NETIF_F_NTUPLE),
+ .mcdi_max_ver = 2,
+ .max_rx_ip_filters = HUNT_FILTER_TBL_ROWS,
+ .hwtstamp_filters = 1 << HWTSTAMP_FILTER_NONE |
+ 1 << HWTSTAMP_FILTER_ALL,
+};
+
const struct efx_nic_type efx_hunt_a0_nic_type = {
+ .is_vf = false,
+ .mem_bar = EFX_MEM_BAR,
.mem_map_size = efx_ef10_mem_map_size,
- .probe = efx_ef10_probe,
+ .probe = efx_ef10_probe_pf,
.remove = efx_ef10_remove,
.dimension_resources = efx_ef10_dimension_resources,
.init = efx_ef10_init_nic,
.fini = efx_port_dummy_op_void,
- .map_reset_reason = efx_mcdi_map_reset_reason,
+ .map_reset_reason = efx_ef10_map_reset_reason,
.map_reset_flags = efx_ef10_map_reset_flags,
.reset = efx_ef10_reset,
.probe_port = efx_mcdi_port_probe,
@@ -3623,7 +4339,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.prepare_flr = efx_ef10_prepare_flr,
.finish_flr = efx_port_dummy_op_void,
.describe_stats = efx_ef10_describe_stats,
- .update_stats = efx_ef10_update_stats,
+ .update_stats = efx_ef10_update_stats_pf,
.start_stats = efx_mcdi_mac_start_stats,
.pull_stats = efx_mcdi_mac_pull_stats,
.stop_stats = efx_mcdi_mac_stop_stats,
@@ -3650,7 +4366,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.tx_init = efx_ef10_tx_init,
.tx_remove = efx_ef10_tx_remove,
.tx_write = efx_ef10_tx_write,
- .rx_push_rss_config = efx_ef10_rx_push_rss_config,
+ .rx_push_rss_config = efx_ef10_pf_rx_push_rss_config,
.rx_probe = efx_ef10_rx_probe,
.rx_init = efx_ef10_rx_init,
.rx_remove = efx_ef10_rx_remove,
@@ -3689,11 +4405,24 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.ptp_write_host_time = efx_ef10_ptp_write_host_time,
.ptp_set_ts_sync_events = efx_ef10_ptp_set_ts_sync_events,
.ptp_set_ts_config = efx_ef10_ptp_set_ts_config,
+#ifdef CONFIG_SFC_SRIOV
+ .sriov_configure = efx_ef10_sriov_configure,
.sriov_init = efx_ef10_sriov_init,
.sriov_fini = efx_ef10_sriov_fini,
- .sriov_mac_address_changed = efx_ef10_sriov_mac_address_changed,
.sriov_wanted = efx_ef10_sriov_wanted,
.sriov_reset = efx_ef10_sriov_reset,
+ .sriov_flr = efx_ef10_sriov_flr,
+ .sriov_set_vf_mac = efx_ef10_sriov_set_vf_mac,
+ .sriov_set_vf_vlan = efx_ef10_sriov_set_vf_vlan,
+ .sriov_set_vf_spoofchk = efx_ef10_sriov_set_vf_spoofchk,
+ .sriov_get_vf_config = efx_ef10_sriov_get_vf_config,
+ .sriov_set_vf_link_state = efx_ef10_sriov_set_vf_link_state,
+ .vswitching_probe = efx_ef10_vswitching_probe_pf,
+ .vswitching_restore = efx_ef10_vswitching_restore_pf,
+ .vswitching_remove = efx_ef10_vswitching_remove_pf,
+#endif
+ .get_mac_address = efx_ef10_get_mac_address_pf,
+ .set_mac_address = efx_ef10_set_mac_address,
.revision = EFX_REV_HUNT_A0,
.max_dma_mask = DMA_BIT_MASK(ESF_DZ_TX_KER_BUF_ADDR_WIDTH),
diff --git a/drivers/net/ethernet/sfc/ef10_sriov.c b/drivers/net/ethernet/sfc/ef10_sriov.c
new file mode 100644
index 000000000000..6c9b6e45509a
--- /dev/null
+++ b/drivers/net/ethernet/sfc/ef10_sriov.c
@@ -0,0 +1,783 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers and boards
+ * Copyright 2015 Solarflare Communications 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, incorporated herein by reference.
+ */
+#include <linux/pci.h>
+#include <linux/module.h>
+#include "net_driver.h"
+#include "ef10_sriov.h"
+#include "efx.h"
+#include "nic.h"
+#include "mcdi_pcol.h"
+
+static int efx_ef10_evb_port_assign(struct efx_nic *efx, unsigned int port_id,
+ unsigned int vf_fn)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_EVB_PORT_ASSIGN_IN_LEN);
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+
+ MCDI_SET_DWORD(inbuf, EVB_PORT_ASSIGN_IN_PORT_ID, port_id);
+ MCDI_POPULATE_DWORD_2(inbuf, EVB_PORT_ASSIGN_IN_FUNCTION,
+ EVB_PORT_ASSIGN_IN_PF, nic_data->pf_index,
+ EVB_PORT_ASSIGN_IN_VF, vf_fn);
+
+ return efx_mcdi_rpc(efx, MC_CMD_EVB_PORT_ASSIGN, inbuf, sizeof(inbuf),
+ NULL, 0, NULL);
+}
+
+static int efx_ef10_vport_add_mac(struct efx_nic *efx,
+ unsigned int port_id, u8 *mac)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN);
+
+ MCDI_SET_DWORD(inbuf, VPORT_ADD_MAC_ADDRESS_IN_VPORT_ID, port_id);
+ ether_addr_copy(MCDI_PTR(inbuf, VPORT_ADD_MAC_ADDRESS_IN_MACADDR), mac);
+
+ return efx_mcdi_rpc(efx, MC_CMD_VPORT_ADD_MAC_ADDRESS, inbuf,
+ sizeof(inbuf), NULL, 0, NULL);
+}
+
+static int efx_ef10_vport_del_mac(struct efx_nic *efx,
+ unsigned int port_id, u8 *mac)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN);
+
+ MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id);
+ ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), mac);
+
+ return efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf,
+ sizeof(inbuf), NULL, 0, NULL);
+}
+
+static int efx_ef10_vswitch_alloc(struct efx_nic *efx, unsigned int port_id,
+ unsigned int vswitch_type)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_VSWITCH_ALLOC_IN_LEN);
+ int rc;
+
+ MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_UPSTREAM_PORT_ID, port_id);
+ MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_TYPE, vswitch_type);
+ MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_NUM_VLAN_TAGS, 2);
+ MCDI_POPULATE_DWORD_1(inbuf, VSWITCH_ALLOC_IN_FLAGS,
+ VSWITCH_ALLOC_IN_FLAG_AUTO_PORT, 0);
+
+ /* Quietly try to allocate 2 VLAN tags */
+ rc = efx_mcdi_rpc_quiet(efx, MC_CMD_VSWITCH_ALLOC, inbuf, sizeof(inbuf),
+ NULL, 0, NULL);
+
+ /* If 2 VLAN tags is too many, revert to trying with 1 VLAN tags */
+ if (rc == -EPROTO) {
+ MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_NUM_VLAN_TAGS, 1);
+ rc = efx_mcdi_rpc(efx, MC_CMD_VSWITCH_ALLOC, inbuf,
+ sizeof(inbuf), NULL, 0, NULL);
+ } else if (rc) {
+ efx_mcdi_display_error(efx, MC_CMD_VSWITCH_ALLOC,
+ MC_CMD_VSWITCH_ALLOC_IN_LEN,
+ NULL, 0, rc);
+ }
+ return rc;
+}
+
+static int efx_ef10_vswitch_free(struct efx_nic *efx, unsigned int port_id)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_VSWITCH_FREE_IN_LEN);
+
+ MCDI_SET_DWORD(inbuf, VSWITCH_FREE_IN_UPSTREAM_PORT_ID, port_id);
+
+ return efx_mcdi_rpc(efx, MC_CMD_VSWITCH_FREE, inbuf, sizeof(inbuf),
+ NULL, 0, NULL);
+}
+
+static int efx_ef10_vport_alloc(struct efx_nic *efx,
+ unsigned int port_id_in,
+ unsigned int vport_type,
+ u16 vlan,
+ unsigned int *port_id_out)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ALLOC_IN_LEN);
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_VPORT_ALLOC_OUT_LEN);
+ size_t outlen;
+ int rc;
+
+ EFX_WARN_ON_PARANOID(!port_id_out);
+
+ MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_UPSTREAM_PORT_ID, port_id_in);
+ MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_TYPE, vport_type);
+ MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_NUM_VLAN_TAGS,
+ (vlan != EFX_EF10_NO_VLAN));
+ MCDI_POPULATE_DWORD_1(inbuf, VPORT_ALLOC_IN_FLAGS,
+ VPORT_ALLOC_IN_FLAG_AUTO_PORT, 0);
+ if (vlan != EFX_EF10_NO_VLAN)
+ MCDI_POPULATE_DWORD_1(inbuf, VPORT_ALLOC_IN_VLAN_TAGS,
+ VPORT_ALLOC_IN_VLAN_TAG_0, vlan);
+
+ rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_ALLOC, inbuf, sizeof(inbuf),
+ outbuf, sizeof(outbuf), &outlen);
+ if (rc)
+ return rc;
+ if (outlen < MC_CMD_VPORT_ALLOC_OUT_LEN)
+ return -EIO;
+
+ *port_id_out = MCDI_DWORD(outbuf, VPORT_ALLOC_OUT_VPORT_ID);
+ return 0;
+}
+
+static int efx_ef10_vport_free(struct efx_nic *efx, unsigned int port_id)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_FREE_IN_LEN);
+
+ MCDI_SET_DWORD(inbuf, VPORT_FREE_IN_VPORT_ID, port_id);
+
+ return efx_mcdi_rpc(efx, MC_CMD_VPORT_FREE, inbuf, sizeof(inbuf),
+ NULL, 0, NULL);
+}
+
+static int efx_ef10_vadaptor_alloc(struct efx_nic *efx, unsigned int port_id)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_ALLOC_IN_LEN);
+
+ MCDI_SET_DWORD(inbuf, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id);
+ return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_ALLOC, inbuf, sizeof(inbuf),
+ NULL, 0, NULL);
+}
+
+static int efx_ef10_vadaptor_free(struct efx_nic *efx, unsigned int port_id)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_FREE_IN_LEN);
+
+ MCDI_SET_DWORD(inbuf, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id);
+ return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_FREE, inbuf, sizeof(inbuf),
+ NULL, 0, NULL);
+}
+
+static void efx_ef10_sriov_free_vf_vports(struct efx_nic *efx)
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ int i;
+
+ if (!nic_data->vf)
+ return;
+
+ for (i = 0; i < efx->vf_count; i++) {
+ struct ef10_vf *vf = nic_data->vf + i;
+
+ /* If VF is assigned, do not free the vport */
+ if (vf->pci_dev &&
+ vf->pci_dev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
+ continue;
+
+ if (vf->vport_assigned) {
+ efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, i);
+ vf->vport_assigned = 0;
+ }
+
+ if (!is_zero_ether_addr(vf->mac)) {
+ efx_ef10_vport_del_mac(efx, vf->vport_id, vf->mac);
+ eth_zero_addr(vf->mac);
+ }
+
+ if (vf->vport_id) {
+ efx_ef10_vport_free(efx, vf->vport_id);
+ vf->vport_id = 0;
+ }
+
+ vf->efx = NULL;
+ }
+}
+
+static void efx_ef10_sriov_free_vf_vswitching(struct efx_nic *efx)
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+
+ efx_ef10_sriov_free_vf_vports(efx);
+ kfree(nic_data->vf);
+ nic_data->vf = NULL;
+}
+
+static int efx_ef10_sriov_assign_vf_vport(struct efx_nic *efx,
+ unsigned int vf_i)
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ struct ef10_vf *vf = nic_data->vf + vf_i;
+ int rc;
+
+ if (WARN_ON_ONCE(!nic_data->vf))
+ return -EOPNOTSUPP;
+
+ rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED,
+ MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL,
+ vf->vlan, &vf->vport_id);
+ if (rc)
+ return rc;
+
+ rc = efx_ef10_vport_add_mac(efx, vf->vport_id, vf->mac);
+ if (rc) {
+ eth_zero_addr(vf->mac);
+ return rc;
+ }
+
+ rc = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i);
+ if (rc)
+ return rc;
+
+ vf->vport_assigned = 1;
+ return 0;
+}
+
+static int efx_ef10_sriov_alloc_vf_vswitching(struct efx_nic *efx)
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ unsigned int i;
+ int rc;
+
+ nic_data->vf = kcalloc(efx->vf_count, sizeof(struct ef10_vf),
+ GFP_KERNEL);
+ if (!nic_data->vf)
+ return -ENOMEM;
+
+ for (i = 0; i < efx->vf_count; i++) {
+ random_ether_addr(nic_data->vf[i].mac);
+ nic_data->vf[i].efx = NULL;
+ nic_data->vf[i].vlan = EFX_EF10_NO_VLAN;
+
+ rc = efx_ef10_sriov_assign_vf_vport(efx, i);
+ if (rc)
+ goto fail;
+ }
+
+ return 0;
+fail:
+ efx_ef10_sriov_free_vf_vports(efx);
+ kfree(nic_data->vf);
+ nic_data->vf = NULL;
+ return rc;
+}
+
+static int efx_ef10_sriov_restore_vf_vswitching(struct efx_nic *efx)
+{
+ unsigned int i;
+ int rc;
+
+ for (i = 0; i < efx->vf_count; i++) {
+ rc = efx_ef10_sriov_assign_vf_vport(efx, i);
+ if (rc)
+ goto fail;
+ }
+
+ return 0;
+fail:
+ efx_ef10_sriov_free_vf_vswitching(efx);
+ return rc;
+}
+
+/* On top of the default firmware vswitch setup, create a VEB vswitch and
+ * expansion vport for use by this function.
+ */
+int efx_ef10_vswitching_probe_pf(struct efx_nic *efx)
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ struct net_device *net_dev = efx->net_dev;
+ int rc;
+
+ if (pci_sriov_get_totalvfs(efx->pci_dev) <= 0) {
+ /* vswitch not needed as we have no VFs */
+ efx_ef10_vadaptor_alloc(efx, nic_data->vport_id);
+ return 0;
+ }
+
+ rc = efx_ef10_vswitch_alloc(efx, EVB_PORT_ID_ASSIGNED,
+ MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VEB);
+ if (rc)
+ goto fail1;
+
+ rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED,
+ MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL,
+ EFX_EF10_NO_VLAN, &nic_data->vport_id);
+ if (rc)
+ goto fail2;
+
+ rc = efx_ef10_vport_add_mac(efx, nic_data->vport_id, net_dev->dev_addr);
+ if (rc)
+ goto fail3;
+ ether_addr_copy(nic_data->vport_mac, net_dev->dev_addr);
+
+ rc = efx_ef10_vadaptor_alloc(efx, nic_data->vport_id);
+ if (rc)
+ goto fail4;
+
+ return 0;
+fail4:
+ efx_ef10_vport_del_mac(efx, nic_data->vport_id, nic_data->vport_mac);
+ eth_zero_addr(nic_data->vport_mac);
+fail3:
+ efx_ef10_vport_free(efx, nic_data->vport_id);
+ nic_data->vport_id = EVB_PORT_ID_ASSIGNED;
+fail2:
+ efx_ef10_vswitch_free(efx, EVB_PORT_ID_ASSIGNED);
+fail1:
+ return rc;
+}
+
+int efx_ef10_vswitching_probe_vf(struct efx_nic *efx)
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+
+ return efx_ef10_vadaptor_alloc(efx, nic_data->vport_id);
+}
+
+int efx_ef10_vswitching_restore_pf(struct efx_nic *efx)
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ int rc;
+
+ if (!nic_data->must_probe_vswitching)
+ return 0;
+
+ rc = efx_ef10_vswitching_probe_pf(efx);
+ if (rc)
+ goto fail;
+
+ rc = efx_ef10_sriov_restore_vf_vswitching(efx);
+ if (rc)
+ goto fail;
+
+ nic_data->must_probe_vswitching = false;
+fail:
+ return rc;
+}
+
+int efx_ef10_vswitching_restore_vf(struct efx_nic *efx)
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ int rc;
+
+ if (!nic_data->must_probe_vswitching)
+ return 0;
+
+ rc = efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED);
+ if (rc)
+ return rc;
+
+ nic_data->must_probe_vswitching = false;
+ return 0;
+}
+
+void efx_ef10_vswitching_remove_pf(struct efx_nic *efx)
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+
+ efx_ef10_sriov_free_vf_vswitching(efx);
+
+ efx_ef10_vadaptor_free(efx, nic_data->vport_id);
+
+ if (nic_data->vport_id == EVB_PORT_ID_ASSIGNED)
+ return; /* No vswitch was ever created */
+
+ if (!is_zero_ether_addr(nic_data->vport_mac)) {
+ efx_ef10_vport_del_mac(efx, nic_data->vport_id,
+ efx->net_dev->dev_addr);
+ eth_zero_addr(nic_data->vport_mac);
+ }
+ efx_ef10_vport_free(efx, nic_data->vport_id);
+ nic_data->vport_id = EVB_PORT_ID_ASSIGNED;
+
+ /* Only free the vswitch if no VFs are assigned */
+ if (!pci_vfs_assigned(efx->pci_dev))
+ efx_ef10_vswitch_free(efx, nic_data->vport_id);
+}
+
+void efx_ef10_vswitching_remove_vf(struct efx_nic *efx)
+{
+ efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED);
+}
+
+static int efx_ef10_pci_sriov_enable(struct efx_nic *efx, int num_vfs)
+{
+ int rc = 0;
+ struct pci_dev *dev = efx->pci_dev;
+
+ efx->vf_count = num_vfs;
+
+ rc = efx_ef10_sriov_alloc_vf_vswitching(efx);
+ if (rc)
+ goto fail1;
+
+ rc = pci_enable_sriov(dev, num_vfs);
+ if (rc)
+ goto fail2;
+
+ return 0;
+fail2:
+ efx_ef10_sriov_free_vf_vswitching(efx);
+fail1:
+ efx->vf_count = 0;
+ netif_err(efx, probe, efx->net_dev,
+ "Failed to enable SRIOV VFs\n");
+ return rc;
+}
+
+static int efx_ef10_pci_sriov_disable(struct efx_nic *efx, bool force)
+{
+ struct pci_dev *dev = efx->pci_dev;
+ unsigned int vfs_assigned = 0;
+
+ vfs_assigned = pci_vfs_assigned(dev);
+
+ if (vfs_assigned && !force) {
+ netif_info(efx, drv, efx->net_dev, "VFs are assigned to guests; "
+ "please detach them before disabling SR-IOV\n");
+ return -EBUSY;
+ }
+
+ if (!vfs_assigned)
+ pci_disable_sriov(dev);
+
+ efx_ef10_sriov_free_vf_vswitching(efx);
+ efx->vf_count = 0;
+ return 0;
+}
+
+int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs)
+{
+ if (num_vfs == 0)
+ return efx_ef10_pci_sriov_disable(efx, false);
+ else
+ return efx_ef10_pci_sriov_enable(efx, num_vfs);
+}
+
+int efx_ef10_sriov_init(struct efx_nic *efx)
+{
+ return 0;
+}
+
+void efx_ef10_sriov_fini(struct efx_nic *efx)
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ unsigned int i;
+ int rc;
+
+ if (!nic_data->vf) {
+ /* Remove any un-assigned orphaned VFs */
+ if (pci_num_vf(efx->pci_dev) && !pci_vfs_assigned(efx->pci_dev))
+ pci_disable_sriov(efx->pci_dev);
+ return;
+ }
+
+ /* Remove any VFs in the host */
+ for (i = 0; i < efx->vf_count; ++i) {
+ struct efx_nic *vf_efx = nic_data->vf[i].efx;
+
+ if (vf_efx)
+ vf_efx->pci_dev->driver->remove(vf_efx->pci_dev);
+ }
+
+ rc = efx_ef10_pci_sriov_disable(efx, true);
+ if (rc)
+ netif_dbg(efx, drv, efx->net_dev,
+ "Disabling SRIOV was not successful rc=%d\n", rc);
+ else
+ netif_dbg(efx, drv, efx->net_dev, "SRIOV disabled\n");
+}
+
+static int efx_ef10_vport_del_vf_mac(struct efx_nic *efx, unsigned int port_id,
+ u8 *mac)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN);
+ MCDI_DECLARE_BUF_ERR(outbuf);
+ size_t outlen;
+ int rc;
+
+ MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id);
+ ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), mac);
+
+ rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf,
+ sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
+
+ return rc;
+}
+
+int efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf_i, u8 *mac)
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ struct ef10_vf *vf;
+ int rc;
+
+ if (!nic_data->vf)
+ return -EOPNOTSUPP;
+
+ if (vf_i >= efx->vf_count)
+ return -EINVAL;
+ vf = nic_data->vf + vf_i;
+
+ if (vf->efx) {
+ efx_device_detach_sync(vf->efx);
+ efx_net_stop(vf->efx->net_dev);
+
+ down_write(&vf->efx->filter_sem);
+ vf->efx->type->filter_table_remove(vf->efx);
+
+ rc = efx_ef10_vadaptor_free(vf->efx, EVB_PORT_ID_ASSIGNED);
+ if (rc) {
+ up_write(&vf->efx->filter_sem);
+ return rc;
+ }
+ }
+
+ rc = efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, vf_i);
+ if (rc)
+ return rc;
+
+ if (!is_zero_ether_addr(vf->mac)) {
+ rc = efx_ef10_vport_del_vf_mac(efx, vf->vport_id, vf->mac);
+ if (rc)
+ return rc;
+ }
+
+ if (!is_zero_ether_addr(mac)) {
+ rc = efx_ef10_vport_add_mac(efx, vf->vport_id, mac);
+ if (rc) {
+ eth_zero_addr(vf->mac);
+ goto fail;
+ }
+ if (vf->efx)
+ ether_addr_copy(vf->efx->net_dev->dev_addr, mac);
+ }
+
+ ether_addr_copy(vf->mac, mac);
+
+ rc = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i);
+ if (rc)
+ goto fail;
+
+ if (vf->efx) {
+ /* VF cannot use the vport_id that the PF created */
+ rc = efx_ef10_vadaptor_alloc(vf->efx, EVB_PORT_ID_ASSIGNED);
+ if (rc) {
+ up_write(&vf->efx->filter_sem);
+ return rc;
+ }
+ vf->efx->type->filter_table_probe(vf->efx);
+ up_write(&vf->efx->filter_sem);
+ efx_net_open(vf->efx->net_dev);
+ netif_device_attach(vf->efx->net_dev);
+ }
+
+ return 0;
+
+fail:
+ memset(vf->mac, 0, ETH_ALEN);
+ return rc;
+}
+
+int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan,
+ u8 qos)
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ struct ef10_vf *vf;
+ u16 old_vlan, new_vlan;
+ int rc = 0, rc2 = 0;
+
+ if (vf_i >= efx->vf_count)
+ return -EINVAL;
+ if (qos != 0)
+ return -EINVAL;
+
+ vf = nic_data->vf + vf_i;
+
+ new_vlan = (vlan == 0) ? EFX_EF10_NO_VLAN : vlan;
+ if (new_vlan == vf->vlan)
+ return 0;
+
+ if (vf->efx) {
+ efx_device_detach_sync(vf->efx);
+ efx_net_stop(vf->efx->net_dev);
+
+ down_write(&vf->efx->filter_sem);
+ vf->efx->type->filter_table_remove(vf->efx);
+
+ rc = efx_ef10_vadaptor_free(vf->efx, EVB_PORT_ID_ASSIGNED);
+ if (rc)
+ goto restore_filters;
+ }
+
+ if (vf->vport_assigned) {
+ rc = efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, vf_i);
+ if (rc) {
+ netif_warn(efx, drv, efx->net_dev,
+ "Failed to change vlan on VF %d.\n", vf_i);
+ netif_warn(efx, drv, efx->net_dev,
+ "This is likely because the VF is bound to a driver in a VM.\n");
+ netif_warn(efx, drv, efx->net_dev,
+ "Please unload the driver in the VM.\n");
+ goto restore_vadaptor;
+ }
+ vf->vport_assigned = 0;
+ }
+
+ if (!is_zero_ether_addr(vf->mac)) {
+ rc = efx_ef10_vport_del_mac(efx, vf->vport_id, vf->mac);
+ if (rc)
+ goto restore_evb_port;
+ }
+
+ if (vf->vport_id) {
+ rc = efx_ef10_vport_free(efx, vf->vport_id);
+ if (rc)
+ goto restore_mac;
+ vf->vport_id = 0;
+ }
+
+ /* Do the actual vlan change */
+ old_vlan = vf->vlan;
+ vf->vlan = new_vlan;
+
+ /* Restore everything in reverse order */
+ rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED,
+ MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL,
+ vf->vlan, &vf->vport_id);
+ if (rc)
+ goto reset_nic;
+
+restore_mac:
+ if (!is_zero_ether_addr(vf->mac)) {
+ rc2 = efx_ef10_vport_add_mac(efx, vf->vport_id, vf->mac);
+ if (rc2) {
+ eth_zero_addr(vf->mac);
+ goto reset_nic;
+ }
+ }
+
+restore_evb_port:
+ rc2 = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i);
+ if (rc2)
+ goto reset_nic;
+ else
+ vf->vport_assigned = 1;
+
+restore_vadaptor:
+ if (vf->efx) {
+ rc2 = efx_ef10_vadaptor_alloc(vf->efx, EVB_PORT_ID_ASSIGNED);
+ if (rc2)
+ goto reset_nic;
+ }
+
+restore_filters:
+ if (vf->efx) {
+ rc2 = vf->efx->type->filter_table_probe(vf->efx);
+ if (rc2)
+ goto reset_nic;
+
+ up_write(&vf->efx->filter_sem);
+
+ rc2 = efx_net_open(vf->efx->net_dev);
+ if (rc2)
+ goto reset_nic;
+
+ netif_device_attach(vf->efx->net_dev);
+ }
+ return rc;
+
+reset_nic:
+ if (vf->efx) {
+ up_write(&vf->efx->filter_sem);
+ netif_err(efx, drv, efx->net_dev,
+ "Failed to restore VF - scheduling reset.\n");
+ efx_schedule_reset(vf->efx, RESET_TYPE_DATAPATH);
+ } else {
+ netif_err(efx, drv, efx->net_dev,
+ "Failed to restore the VF and cannot reset the VF "
+ "- VF is not functional.\n");
+ netif_err(efx, drv, efx->net_dev,
+ "Please reload the driver attached to the VF.\n");
+ }
+
+ return rc ? rc : rc2;
+}
+
+int efx_ef10_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf_i,
+ bool spoofchk)
+{
+ return spoofchk ? -EOPNOTSUPP : 0;
+}
+
+int efx_ef10_sriov_set_vf_link_state(struct efx_nic *efx, int vf_i,
+ int link_state)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_LINK_STATE_MODE_IN_LEN);
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+
+ BUILD_BUG_ON(IFLA_VF_LINK_STATE_AUTO !=
+ MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_AUTO);
+ BUILD_BUG_ON(IFLA_VF_LINK_STATE_ENABLE !=
+ MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_UP);
+ BUILD_BUG_ON(IFLA_VF_LINK_STATE_DISABLE !=
+ MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_DOWN);
+ MCDI_POPULATE_DWORD_2(inbuf, LINK_STATE_MODE_IN_FUNCTION,
+ LINK_STATE_MODE_IN_FUNCTION_PF,
+ nic_data->pf_index,
+ LINK_STATE_MODE_IN_FUNCTION_VF, vf_i);
+ MCDI_SET_DWORD(inbuf, LINK_STATE_MODE_IN_NEW_MODE, link_state);
+ return efx_mcdi_rpc(efx, MC_CMD_LINK_STATE_MODE, inbuf, sizeof(inbuf),
+ NULL, 0, NULL); /* don't care what old mode was */
+}
+
+int efx_ef10_sriov_get_vf_config(struct efx_nic *efx, int vf_i,
+ struct ifla_vf_info *ivf)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_LINK_STATE_MODE_IN_LEN);
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_LINK_STATE_MODE_OUT_LEN);
+
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ struct ef10_vf *vf;
+ size_t outlen;
+ int rc;
+
+ if (vf_i >= efx->vf_count)
+ return -EINVAL;
+
+ if (!nic_data->vf)
+ return -EOPNOTSUPP;
+
+ vf = nic_data->vf + vf_i;
+
+ ivf->vf = vf_i;
+ ivf->min_tx_rate = 0;
+ ivf->max_tx_rate = 0;
+ ether_addr_copy(ivf->mac, vf->mac);
+ ivf->vlan = (vf->vlan == EFX_EF10_NO_VLAN) ? 0 : vf->vlan;
+ ivf->qos = 0;
+
+ MCDI_POPULATE_DWORD_2(inbuf, LINK_STATE_MODE_IN_FUNCTION,
+ LINK_STATE_MODE_IN_FUNCTION_PF,
+ nic_data->pf_index,
+ LINK_STATE_MODE_IN_FUNCTION_VF, vf_i);
+ MCDI_SET_DWORD(inbuf, LINK_STATE_MODE_IN_NEW_MODE,
+ MC_CMD_LINK_STATE_MODE_IN_DO_NOT_CHANGE);
+ rc = efx_mcdi_rpc(efx, MC_CMD_LINK_STATE_MODE, inbuf, sizeof(inbuf),
+ outbuf, sizeof(outbuf), &outlen);
+ if (rc)
+ return rc;
+ if (outlen < MC_CMD_LINK_STATE_MODE_OUT_LEN)
+ return -EIO;
+ ivf->linkstate = MCDI_DWORD(outbuf, LINK_STATE_MODE_OUT_OLD_MODE);
+
+ return 0;
+}
+
+int efx_ef10_sriov_get_phys_port_id(struct efx_nic *efx,
+ struct netdev_phys_item_id *ppid)
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+
+ if (!is_valid_ether_addr(nic_data->port_id))
+ return -EOPNOTSUPP;
+
+ ppid->id_len = ETH_ALEN;
+ memcpy(ppid->id, nic_data->port_id, ppid->id_len);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/sfc/ef10_sriov.h b/drivers/net/ethernet/sfc/ef10_sriov.h
new file mode 100644
index 000000000000..db4ef537c610
--- /dev/null
+++ b/drivers/net/ethernet/sfc/ef10_sriov.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers and boards
+ * Copyright 2015 Solarflare Communications 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, incorporated herein by reference.
+ */
+
+#ifndef EF10_SRIOV_H
+#define EF10_SRIOV_H
+
+#include "net_driver.h"
+
+/**
+ * struct ef10_vf - PF's store of VF data
+ * @efx: efx_nic struct for the current VF
+ * @pci_dev: the pci_dev struct for the VF, retained while the VF is assigned
+ * @vport_id: vport ID for the VF
+ * @vport_assigned: record whether the vport is currently assigned to the VF
+ * @mac: MAC address for the VF, zero when address is removed from the vport
+ * @vlan: Default VLAN for the VF or #EFX_EF10_NO_VLAN
+ */
+struct ef10_vf {
+ struct efx_nic *efx;
+ struct pci_dev *pci_dev;
+ unsigned int vport_id;
+ unsigned int vport_assigned;
+ u8 mac[ETH_ALEN];
+ u16 vlan;
+#define EFX_EF10_NO_VLAN 0
+};
+
+static inline bool efx_ef10_sriov_wanted(struct efx_nic *efx)
+{
+ return false;
+}
+
+int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs);
+int efx_ef10_sriov_init(struct efx_nic *efx);
+static inline void efx_ef10_sriov_reset(struct efx_nic *efx) {}
+void efx_ef10_sriov_fini(struct efx_nic *efx);
+static inline void efx_ef10_sriov_flr(struct efx_nic *efx, unsigned vf_i) {}
+
+int efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf, u8 *mac);
+
+int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i,
+ u16 vlan, u8 qos);
+
+int efx_ef10_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf,
+ bool spoofchk);
+
+int efx_ef10_sriov_get_vf_config(struct efx_nic *efx, int vf_i,
+ struct ifla_vf_info *ivf);
+
+int efx_ef10_sriov_set_vf_link_state(struct efx_nic *efx, int vf_i,
+ int link_state);
+
+int efx_ef10_sriov_get_phys_port_id(struct efx_nic *efx,
+ struct netdev_phys_item_id *ppid);
+
+int efx_ef10_vswitching_probe_pf(struct efx_nic *efx);
+int efx_ef10_vswitching_probe_vf(struct efx_nic *efx);
+int efx_ef10_vswitching_restore_pf(struct efx_nic *efx);
+int efx_ef10_vswitching_restore_vf(struct efx_nic *efx);
+void efx_ef10_vswitching_remove_pf(struct efx_nic *efx);
+void efx_ef10_vswitching_remove_vf(struct efx_nic *efx);
+
+#endif /* EF10_SRIOV_H */
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 65944dd8bf6b..804b9ad553d3 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -26,6 +26,7 @@
#include "efx.h"
#include "nic.h"
#include "selftest.h"
+#include "sriov.h"
#include "mcdi.h"
#include "workarounds.h"
@@ -76,6 +77,7 @@ const char *const efx_reset_type_names[] = {
[RESET_TYPE_RECOVER_OR_ALL] = "RECOVER_OR_ALL",
[RESET_TYPE_WORLD] = "WORLD",
[RESET_TYPE_RECOVER_OR_DISABLE] = "RECOVER_OR_DISABLE",
+ [RESET_TYPE_DATAPATH] = "DATAPATH",
[RESET_TYPE_MC_BIST] = "MC_BIST",
[RESET_TYPE_DISABLE] = "DISABLE",
[RESET_TYPE_TX_WATCHDOG] = "TX_WATCHDOG",
@@ -948,6 +950,16 @@ void efx_link_set_wanted_fc(struct efx_nic *efx, u8 wanted_fc)
static void efx_fini_port(struct efx_nic *efx);
+/* We assume that efx->type->reconfigure_mac will always try to sync RX
+ * filters and therefore needs to read-lock the filter table against freeing
+ */
+void efx_mac_reconfigure(struct efx_nic *efx)
+{
+ down_read(&efx->filter_sem);
+ efx->type->reconfigure_mac(efx);
+ up_read(&efx->filter_sem);
+}
+
/* Push loopback/power/transmit disable settings to the PHY, and reconfigure
* the MAC appropriately. All other PHY configuration changes are pushed
* through phy_op->set_settings(), and pushed asynchronously to the MAC
@@ -1001,7 +1013,7 @@ static void efx_mac_work(struct work_struct *data)
mutex_lock(&efx->mac_lock);
if (efx->port_enabled)
- efx->type->reconfigure_mac(efx);
+ efx_mac_reconfigure(efx);
mutex_unlock(&efx->mac_lock);
}
@@ -1041,11 +1053,11 @@ static int efx_init_port(struct efx_nic *efx)
/* Reconfigure the MAC before creating dma queues (required for
* Falcon/A1 where RX_INGR_EN/TX_DRAIN_EN isn't supported) */
- efx->type->reconfigure_mac(efx);
+ efx_mac_reconfigure(efx);
/* Ensure the PHY advertises the correct flow control settings */
rc = efx->phy_op->reconfigure(efx);
- if (rc)
+ if (rc && rc != -EPERM)
goto fail2;
mutex_unlock(&efx->mac_lock);
@@ -1067,7 +1079,7 @@ static void efx_start_port(struct efx_nic *efx)
efx->port_enabled = true;
/* Ensure MAC ingress/egress is enabled */
- efx->type->reconfigure_mac(efx);
+ efx_mac_reconfigure(efx);
mutex_unlock(&efx->mac_lock);
}
@@ -1200,10 +1212,12 @@ static int efx_init_io(struct efx_nic *efx)
struct pci_dev *pci_dev = efx->pci_dev;
dma_addr_t dma_mask = efx->type->max_dma_mask;
unsigned int mem_map_size = efx->type->mem_map_size(efx);
- int rc;
+ int rc, bar;
netif_dbg(efx, probe, efx->net_dev, "initialising I/O\n");
+ bar = efx->type->mem_bar;
+
rc = pci_enable_device(pci_dev);
if (rc) {
netif_err(efx, probe, efx->net_dev,
@@ -1234,8 +1248,8 @@ static int efx_init_io(struct efx_nic *efx)
netif_dbg(efx, probe, efx->net_dev,
"using DMA mask %llx\n", (unsigned long long) dma_mask);
- efx->membase_phys = pci_resource_start(efx->pci_dev, EFX_MEM_BAR);
- rc = pci_request_region(pci_dev, EFX_MEM_BAR, "sfc");
+ efx->membase_phys = pci_resource_start(efx->pci_dev, bar);
+ rc = pci_request_region(pci_dev, bar, "sfc");
if (rc) {
netif_err(efx, probe, efx->net_dev,
"request for memory BAR failed\n");
@@ -1258,7 +1272,7 @@ static int efx_init_io(struct efx_nic *efx)
return 0;
fail4:
- pci_release_region(efx->pci_dev, EFX_MEM_BAR);
+ pci_release_region(efx->pci_dev, bar);
fail3:
efx->membase_phys = 0;
fail2:
@@ -1269,6 +1283,8 @@ static int efx_init_io(struct efx_nic *efx)
static void efx_fini_io(struct efx_nic *efx)
{
+ int bar;
+
netif_dbg(efx, drv, efx->net_dev, "shutting down I/O\n");
if (efx->membase) {
@@ -1277,11 +1293,23 @@ static void efx_fini_io(struct efx_nic *efx)
}
if (efx->membase_phys) {
- pci_release_region(efx->pci_dev, EFX_MEM_BAR);
+ bar = efx->type->mem_bar;
+ pci_release_region(efx->pci_dev, bar);
efx->membase_phys = 0;
}
- pci_disable_device(efx->pci_dev);
+ /* Don't disable bus-mastering if VFs are assigned */
+ if (!pci_vfs_assigned(efx->pci_dev))
+ pci_disable_device(efx->pci_dev);
+}
+
+void efx_set_default_rx_indir_table(struct efx_nic *efx)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++)
+ efx->rx_indir_table[i] =
+ ethtool_rxfh_indir_default(i, efx->rss_spread);
}
static unsigned int efx_wanted_parallelism(struct efx_nic *efx)
@@ -1314,15 +1342,19 @@ static unsigned int efx_wanted_parallelism(struct efx_nic *efx)
/* If RSS is requested for the PF *and* VFs then we can't write RSS
* table entries that are inaccessible to VFs
*/
- if (efx->type->sriov_wanted(efx) && efx_vf_size(efx) > 1 &&
- count > efx_vf_size(efx)) {
- netif_warn(efx, probe, efx->net_dev,
- "Reducing number of RSS channels from %u to %u for "
- "VF support. Increase vf-msix-limit to use more "
- "channels on the PF.\n",
- count, efx_vf_size(efx));
- count = efx_vf_size(efx);
+#ifdef CONFIG_SFC_SRIOV
+ if (efx->type->sriov_wanted) {
+ if (efx->type->sriov_wanted(efx) && efx_vf_size(efx) > 1 &&
+ count > efx_vf_size(efx)) {
+ netif_warn(efx, probe, efx->net_dev,
+ "Reducing number of RSS channels from %u to %u for "
+ "VF support. Increase vf-msix-limit to use more "
+ "channels on the PF.\n",
+ count, efx_vf_size(efx));
+ count = efx_vf_size(efx);
+ }
}
+#endif
return count;
}
@@ -1426,10 +1458,15 @@ static int efx_probe_interrupts(struct efx_nic *efx)
}
/* RSS might be usable on VFs even if it is disabled on the PF */
-
- efx->rss_spread = ((efx->n_rx_channels > 1 ||
- !efx->type->sriov_wanted(efx)) ?
- efx->n_rx_channels : efx_vf_size(efx));
+#ifdef CONFIG_SFC_SRIOV
+ if (efx->type->sriov_wanted) {
+ efx->rss_spread = ((efx->n_rx_channels > 1 ||
+ !efx->type->sriov_wanted(efx)) ?
+ efx->n_rx_channels : efx_vf_size(efx));
+ return 0;
+ }
+#endif
+ efx->rss_spread = efx->n_rx_channels;
return 0;
}
@@ -1593,7 +1630,6 @@ static void efx_set_channels(struct efx_nic *efx)
static int efx_probe_nic(struct efx_nic *efx)
{
- size_t i;
int rc;
netif_dbg(efx, probe, efx->net_dev, "creating NIC\n");
@@ -1616,10 +1652,9 @@ static int efx_probe_nic(struct efx_nic *efx)
goto fail2;
if (efx->n_channels > 1)
- netdev_rss_key_fill(&efx->rx_hash_key, sizeof(efx->rx_hash_key));
- for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++)
- efx->rx_indir_table[i] =
- ethtool_rxfh_indir_default(i, efx->rss_spread);
+ netdev_rss_key_fill(&efx->rx_hash_key,
+ sizeof(efx->rx_hash_key));
+ efx_set_default_rx_indir_table(efx);
netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels);
netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels);
@@ -1650,10 +1685,11 @@ static int efx_probe_filters(struct efx_nic *efx)
int rc;
spin_lock_init(&efx->filter_lock);
-
+ init_rwsem(&efx->filter_sem);
+ down_write(&efx->filter_sem);
rc = efx->type->filter_table_probe(efx);
if (rc)
- return rc;
+ goto out_unlock;
#ifdef CONFIG_RFS_ACCEL
if (efx->type->offload_features & NETIF_F_NTUPLE) {
@@ -1662,12 +1698,14 @@ static int efx_probe_filters(struct efx_nic *efx)
GFP_KERNEL);
if (!efx->rps_flow_id) {
efx->type->filter_table_remove(efx);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto out_unlock;
}
}
#endif
-
- return 0;
+out_unlock:
+ up_write(&efx->filter_sem);
+ return rc;
}
static void efx_remove_filters(struct efx_nic *efx)
@@ -1675,12 +1713,16 @@ static void efx_remove_filters(struct efx_nic *efx)
#ifdef CONFIG_RFS_ACCEL
kfree(efx->rps_flow_id);
#endif
+ down_write(&efx->filter_sem);
efx->type->filter_table_remove(efx);
+ up_write(&efx->filter_sem);
}
static void efx_restore_filters(struct efx_nic *efx)
{
+ down_read(&efx->filter_sem);
efx->type->filter_table_restore(efx);
+ up_read(&efx->filter_sem);
}
/**************************************************************************
@@ -1712,21 +1754,33 @@ static int efx_probe_all(struct efx_nic *efx)
}
efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE;
+#ifdef CONFIG_SFC_SRIOV
+ rc = efx->type->vswitching_probe(efx);
+ if (rc) /* not fatal; the PF will still work fine */
+ netif_warn(efx, probe, efx->net_dev,
+ "failed to setup vswitching rc=%d;"
+ " VFs may not function\n", rc);
+#endif
+
rc = efx_probe_filters(efx);
if (rc) {
netif_err(efx, probe, efx->net_dev,
"failed to create filter tables\n");
- goto fail3;
+ goto fail4;
}
rc = efx_probe_channels(efx);
if (rc)
- goto fail4;
+ goto fail5;
return 0;
- fail4:
+ fail5:
efx_remove_filters(efx);
+ fail4:
+#ifdef CONFIG_SFC_SRIOV
+ efx->type->vswitching_remove(efx);
+#endif
fail3:
efx_remove_port(efx);
fail2:
@@ -1816,6 +1870,9 @@ static void efx_remove_all(struct efx_nic *efx)
{
efx_remove_channels(efx);
efx_remove_filters(efx);
+#ifdef CONFIG_SFC_SRIOV
+ efx->type->vswitching_remove(efx);
+#endif
efx_remove_port(efx);
efx_remove_nic(efx);
}
@@ -2059,7 +2116,7 @@ static int efx_busy_poll(struct napi_struct *napi)
*************************************************************************/
/* Context: process, rtnl_lock() held. */
-static int efx_net_open(struct net_device *net_dev)
+int efx_net_open(struct net_device *net_dev)
{
struct efx_nic *efx = netdev_priv(net_dev);
int rc;
@@ -2088,7 +2145,7 @@ static int efx_net_open(struct net_device *net_dev)
* Note that the kernel will ignore our return code; this method
* should really be a void.
*/
-static int efx_net_stop(struct net_device *net_dev)
+int efx_net_stop(struct net_device *net_dev)
{
struct efx_nic *efx = netdev_priv(net_dev);
@@ -2146,7 +2203,7 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
mutex_lock(&efx->mac_lock);
net_dev->mtu = new_mtu;
- efx->type->reconfigure_mac(efx);
+ efx_mac_reconfigure(efx);
mutex_unlock(&efx->mac_lock);
efx_start_all(efx);
@@ -2159,6 +2216,8 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
struct efx_nic *efx = netdev_priv(net_dev);
struct sockaddr *addr = data;
u8 *new_addr = addr->sa_data;
+ u8 old_addr[6];
+ int rc;
if (!is_valid_ether_addr(new_addr)) {
netif_err(efx, drv, efx->net_dev,
@@ -2167,12 +2226,20 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
return -EADDRNOTAVAIL;
}
+ /* save old address */
+ ether_addr_copy(old_addr, net_dev->dev_addr);
ether_addr_copy(net_dev->dev_addr, new_addr);
- efx->type->sriov_mac_address_changed(efx);
+ if (efx->type->set_mac_address) {
+ rc = efx->type->set_mac_address(efx);
+ if (rc) {
+ ether_addr_copy(net_dev->dev_addr, old_addr);
+ return rc;
+ }
+ }
/* Reconfigure the MAC */
mutex_lock(&efx->mac_lock);
- efx->type->reconfigure_mac(efx);
+ efx_mac_reconfigure(efx);
mutex_unlock(&efx->mac_lock);
return 0;
@@ -2199,7 +2266,7 @@ static int efx_set_features(struct net_device *net_dev, netdev_features_t data)
return 0;
}
-static const struct net_device_ops efx_farch_netdev_ops = {
+static const struct net_device_ops efx_netdev_ops = {
.ndo_open = efx_net_open,
.ndo_stop = efx_net_stop,
.ndo_get_stats64 = efx_net_stats,
@@ -2212,10 +2279,12 @@ static const struct net_device_ops efx_farch_netdev_ops = {
.ndo_set_rx_mode = efx_set_rx_mode,
.ndo_set_features = efx_set_features,
#ifdef CONFIG_SFC_SRIOV
- .ndo_set_vf_mac = efx_siena_sriov_set_vf_mac,
- .ndo_set_vf_vlan = efx_siena_sriov_set_vf_vlan,
- .ndo_set_vf_spoofchk = efx_siena_sriov_set_vf_spoofchk,
- .ndo_get_vf_config = efx_siena_sriov_get_vf_config,
+ .ndo_set_vf_mac = efx_sriov_set_vf_mac,
+ .ndo_set_vf_vlan = efx_sriov_set_vf_vlan,
+ .ndo_set_vf_spoofchk = efx_sriov_set_vf_spoofchk,
+ .ndo_get_vf_config = efx_sriov_get_vf_config,
+ .ndo_set_vf_link_state = efx_sriov_set_vf_link_state,
+ .ndo_get_phys_port_id = efx_sriov_get_phys_port_id,
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = efx_netpoll,
@@ -2229,29 +2298,6 @@ static const struct net_device_ops efx_farch_netdev_ops = {
#endif
};
-static const struct net_device_ops efx_ef10_netdev_ops = {
- .ndo_open = efx_net_open,
- .ndo_stop = efx_net_stop,
- .ndo_get_stats64 = efx_net_stats,
- .ndo_tx_timeout = efx_watchdog,
- .ndo_start_xmit = efx_hard_start_xmit,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_do_ioctl = efx_ioctl,
- .ndo_change_mtu = efx_change_mtu,
- .ndo_set_mac_address = efx_set_mac_address,
- .ndo_set_rx_mode = efx_set_rx_mode,
- .ndo_set_features = efx_set_features,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = efx_netpoll,
-#endif
-#ifdef CONFIG_NET_RX_BUSY_POLL
- .ndo_busy_poll = efx_busy_poll,
-#endif
-#ifdef CONFIG_RFS_ACCEL
- .ndo_rx_flow_steer = efx_filter_rfs,
-#endif
-};
-
static void efx_update_name(struct efx_nic *efx)
{
strcpy(efx->name, efx->net_dev->name);
@@ -2264,8 +2310,7 @@ static int efx_netdev_event(struct notifier_block *this,
{
struct net_device *net_dev = netdev_notifier_info_to_dev(ptr);
- if ((net_dev->netdev_ops == &efx_farch_netdev_ops ||
- net_dev->netdev_ops == &efx_ef10_netdev_ops) &&
+ if ((net_dev->netdev_ops == &efx_netdev_ops) &&
event == NETDEV_CHANGENAME)
efx_update_name(netdev_priv(net_dev));
@@ -2284,6 +2329,28 @@ show_phy_type(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(phy_type, 0444, show_phy_type, NULL);
+#ifdef CONFIG_SFC_MCDI_LOGGING
+static ssize_t show_mcdi_log(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+ struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", mcdi->logging_enabled);
+}
+static ssize_t set_mcdi_log(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+ struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
+ bool enable = count > 0 && *buf != '0';
+
+ mcdi->logging_enabled = enable;
+ return count;
+}
+static DEVICE_ATTR(mcdi_logging, 0644, show_mcdi_log, set_mcdi_log);
+#endif
+
static int efx_register_netdev(struct efx_nic *efx)
{
struct net_device *net_dev = efx->net_dev;
@@ -2292,12 +2359,9 @@ static int efx_register_netdev(struct efx_nic *efx)
net_dev->watchdog_timeo = 5 * HZ;
net_dev->irq = efx->pci_dev->irq;
- if (efx_nic_rev(efx) >= EFX_REV_HUNT_A0) {
- net_dev->netdev_ops = &efx_ef10_netdev_ops;
+ net_dev->netdev_ops = &efx_netdev_ops;
+ if (efx_nic_rev(efx) >= EFX_REV_HUNT_A0)
net_dev->priv_flags |= IFF_UNICAST_FLT;
- } else {
- net_dev->netdev_ops = &efx_farch_netdev_ops;
- }
net_dev->ethtool_ops = &efx_ethtool_ops;
net_dev->gso_max_segs = EFX_TSO_MAX_SEGS;
@@ -2344,9 +2408,21 @@ static int efx_register_netdev(struct efx_nic *efx)
"failed to init net dev attributes\n");
goto fail_registered;
}
+#ifdef CONFIG_SFC_MCDI_LOGGING
+ rc = device_create_file(&efx->pci_dev->dev, &dev_attr_mcdi_logging);
+ if (rc) {
+ netif_err(efx, drv, efx->net_dev,
+ "failed to init net dev attributes\n");
+ goto fail_attr_mcdi_logging;
+ }
+#endif
return 0;
+#ifdef CONFIG_SFC_MCDI_LOGGING
+fail_attr_mcdi_logging:
+ device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_type);
+#endif
fail_registered:
rtnl_lock();
efx_dissociate(efx);
@@ -2365,13 +2441,14 @@ static void efx_unregister_netdev(struct efx_nic *efx)
BUG_ON(netdev_priv(efx->net_dev) != efx);
- strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name));
- device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_type);
-
- rtnl_lock();
- unregister_netdevice(efx->net_dev);
- efx->state = STATE_UNINIT;
- rtnl_unlock();
+ if (efx_dev_registered(efx)) {
+ strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name));
+#ifdef CONFIG_SFC_MCDI_LOGGING
+ device_remove_file(&efx->pci_dev->dev, &dev_attr_mcdi_logging);
+#endif
+ device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_type);
+ unregister_netdev(efx->net_dev);
+ }
}
/**************************************************************************
@@ -2393,7 +2470,8 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method)
efx_disable_interrupts(efx);
mutex_lock(&efx->mac_lock);
- if (efx->port_initialized && method != RESET_TYPE_INVISIBLE)
+ if (efx->port_initialized && method != RESET_TYPE_INVISIBLE &&
+ method != RESET_TYPE_DATAPATH)
efx->phy_op->fini(efx);
efx->type->fini(efx);
}
@@ -2422,11 +2500,13 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
if (!ok)
goto fail;
- if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) {
+ if (efx->port_initialized && method != RESET_TYPE_INVISIBLE &&
+ method != RESET_TYPE_DATAPATH) {
rc = efx->phy_op->init(efx);
if (rc)
goto fail;
- if (efx->phy_op->reconfigure(efx))
+ rc = efx->phy_op->reconfigure(efx);
+ if (rc && rc != -EPERM)
netif_err(efx, drv, efx->net_dev,
"could not restore PHY settings\n");
}
@@ -2434,8 +2514,20 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
rc = efx_enable_interrupts(efx);
if (rc)
goto fail;
+
+#ifdef CONFIG_SFC_SRIOV
+ rc = efx->type->vswitching_restore(efx);
+ if (rc) /* not fatal; the PF will still work fine */
+ netif_warn(efx, probe, efx->net_dev,
+ "failed to restore vswitching rc=%d;"
+ " VFs may not function\n", rc);
+#endif
+
+ down_read(&efx->filter_sem);
efx_restore_filters(efx);
- efx->type->sriov_reset(efx);
+ up_read(&efx->filter_sem);
+ if (efx->type->sriov_reset)
+ efx->type->sriov_reset(efx);
mutex_unlock(&efx->mac_lock);
@@ -2605,6 +2697,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
case RESET_TYPE_WORLD:
case RESET_TYPE_DISABLE:
case RESET_TYPE_RECOVER_OR_DISABLE:
+ case RESET_TYPE_DATAPATH:
case RESET_TYPE_MC_BIST:
case RESET_TYPE_MCDI_TIMEOUT:
method = type;
@@ -2655,6 +2748,8 @@ static const struct pci_device_id efx_pci_table[] = {
.driver_data = (unsigned long) &siena_a0_nic_type},
{PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x0903), /* SFC9120 PF */
.driver_data = (unsigned long) &efx_hunt_a0_nic_type},
+ {PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x1903), /* SFC9120 VF */
+ .driver_data = (unsigned long) &efx_hunt_a0_vf_nic_type},
{PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x0923), /* SFC9140 PF */
.driver_data = (unsigned long) &efx_hunt_a0_nic_type},
{0} /* end of list */
@@ -2809,7 +2904,8 @@ static void efx_pci_remove_main(struct efx_nic *efx)
}
/* Final NIC shutdown
- * This is called only at module unload (or hotplug removal).
+ * This is called only at module unload (or hotplug removal). A PF can call
+ * this on its VFs to ensure they are unbound first.
*/
static void efx_pci_remove(struct pci_dev *pci_dev)
{
@@ -2824,9 +2920,12 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
efx_dissociate(efx);
dev_close(efx->net_dev);
efx_disable_interrupts(efx);
+ efx->state = STATE_UNINIT;
rtnl_unlock();
- efx->type->sriov_fini(efx);
+ if (efx->type->sriov_fini)
+ efx->type->sriov_fini(efx);
+
efx_unregister_netdev(efx);
efx_mtd_remove(efx);
@@ -3008,7 +3107,8 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
netif_info(efx, probe, efx->net_dev,
"Solarflare NIC detected\n");
- efx_probe_vpd_strings(efx);
+ if (!efx->type->is_vf)
+ efx_probe_vpd_strings(efx);
/* Set up basic I/O (BAR mappings etc) */
rc = efx_init_io(efx);
@@ -3023,10 +3123,12 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
if (rc)
goto fail4;
- rc = efx->type->sriov_init(efx);
- if (rc)
- netif_err(efx, probe, efx->net_dev,
- "SR-IOV can't be enabled rc %d\n", rc);
+ if (efx->type->sriov_init) {
+ rc = efx->type->sriov_init(efx);
+ if (rc)
+ netif_err(efx, probe, efx->net_dev,
+ "SR-IOV can't be enabled rc %d\n", rc);
+ }
netif_dbg(efx, probe, efx->net_dev, "initialisation successful\n");
@@ -3058,6 +3160,26 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
return rc;
}
+/* efx_pci_sriov_configure returns the actual number of Virtual Functions
+ * enabled on success
+ */
+#ifdef CONFIG_SFC_SRIOV
+static int efx_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
+{
+ int rc;
+ struct efx_nic *efx = pci_get_drvdata(dev);
+
+ if (efx->type->sriov_configure) {
+ rc = efx->type->sriov_configure(efx, num_vfs);
+ if (rc)
+ return rc;
+ else
+ return num_vfs;
+ } else
+ return -EOPNOTSUPP;
+}
+#endif
+
static int efx_pm_freeze(struct device *dev)
{
struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
@@ -3280,6 +3402,9 @@ static struct pci_driver efx_pci_driver = {
.remove = efx_pci_remove,
.driver.pm = &efx_pm_ops,
.err_handler = &efx_err_handlers,
+#ifdef CONFIG_SFC_SRIOV
+ .sriov_configure = efx_pci_sriov_configure,
+#endif
};
/**************************************************************************
@@ -3302,9 +3427,11 @@ static int __init efx_init_module(void)
if (rc)
goto err_notifier;
+#ifdef CONFIG_SFC_SRIOV
rc = efx_init_sriov();
if (rc)
goto err_sriov;
+#endif
reset_workqueue = create_singlethread_workqueue("sfc_reset");
if (!reset_workqueue) {
@@ -3321,8 +3448,10 @@ static int __init efx_init_module(void)
err_pci:
destroy_workqueue(reset_workqueue);
err_reset:
+#ifdef CONFIG_SFC_SRIOV
efx_fini_sriov();
err_sriov:
+#endif
unregister_netdevice_notifier(&efx_netdev_notifier);
err_notifier:
return rc;
@@ -3334,7 +3463,9 @@ static void __exit efx_exit_module(void)
pci_unregister_driver(&efx_pci_driver);
destroy_workqueue(reset_workqueue);
+#ifdef CONFIG_SFC_SRIOV
efx_fini_sriov();
+#endif
unregister_netdevice_notifier(&efx_netdev_notifier);
}
diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h
index 2587c582a821..acb1e0718485 100644
--- a/drivers/net/ethernet/sfc/efx.h
+++ b/drivers/net/ethernet/sfc/efx.h
@@ -15,7 +15,12 @@
#include "filter.h"
/* All controllers use BAR 0 for I/O space and BAR 2(&3) for memory */
+/* All VFs use BAR 0/1 for memory */
#define EFX_MEM_BAR 2
+#define EFX_MEM_VF_BAR 0
+
+int efx_net_open(struct net_device *net_dev);
+int efx_net_stop(struct net_device *net_dev);
/* TX */
int efx_probe_tx_queue(struct efx_tx_queue *tx_queue);
@@ -32,6 +37,7 @@ unsigned int efx_tx_max_skb_descs(struct efx_nic *efx);
extern unsigned int efx_piobuf_size;
/* RX */
+void efx_set_default_rx_indir_table(struct efx_nic *efx);
void efx_rx_config_page_split(struct efx_nic *efx);
int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
void efx_remove_rx_queue(struct efx_rx_queue *rx_queue);
@@ -71,6 +77,8 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue);
/* Filters */
+void efx_mac_reconfigure(struct efx_nic *efx);
+
/**
* efx_filter_insert_filter - add or replace a filter
* @efx: NIC in which to insert the filter
@@ -220,6 +228,13 @@ static inline void efx_mtd_rename(struct efx_nic *efx) {}
static inline void efx_mtd_remove(struct efx_nic *efx) {}
#endif
+#ifdef CONFIG_SFC_SRIOV
+static inline unsigned int efx_vf_size(struct efx_nic *efx)
+{
+ return 1 << efx->vi_scale;
+}
+#endif
+
static inline void efx_schedule_channel(struct efx_channel *channel)
{
netif_vdbg(channel->efx, intr, channel->efx->net_dev,
diff --git a/drivers/net/ethernet/sfc/enum.h b/drivers/net/ethernet/sfc/enum.h
index d1dbb5fb31bb..c94f56271dd4 100644
--- a/drivers/net/ethernet/sfc/enum.h
+++ b/drivers/net/ethernet/sfc/enum.h
@@ -143,6 +143,7 @@ enum efx_loopback_mode {
* @RESET_TYPE_WORLD: Reset as much as possible
* @RESET_TYPE_RECOVER_OR_DISABLE: Try to recover. Apply RESET_TYPE_DISABLE if
* unsuccessful.
+ * @RESET_TYPE_DATAPATH: Reset datapath only.
* @RESET_TYPE_MC_BIST: MC entering BIST mode.
* @RESET_TYPE_DISABLE: Reset datapath, MAC and PHY; leave NIC disabled
* @RESET_TYPE_TX_WATCHDOG: reset due to TX watchdog
@@ -159,6 +160,7 @@ enum reset_type {
RESET_TYPE_ALL,
RESET_TYPE_WORLD,
RESET_TYPE_RECOVER_OR_DISABLE,
+ RESET_TYPE_DATAPATH,
RESET_TYPE_MC_BIST,
RESET_TYPE_DISABLE,
RESET_TYPE_MAX_METHOD,
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index 4835bc0d0de8..034797661f96 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -734,7 +734,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
/* Reconfigure the MAC. The PHY *may* generate a link state change event
* if the user just changed the advertised capabilities, but there's no
* harm doing this twice */
- efx->type->reconfigure_mac(efx);
+ efx_mac_reconfigure(efx);
out:
mutex_unlock(&efx->mac_lock);
@@ -1109,9 +1109,8 @@ static int efx_ethtool_set_rxfh(struct net_device *net_dev, const u32 *indir,
return -EOPNOTSUPP;
if (!indir)
return 0;
- memcpy(efx->rx_indir_table, indir, sizeof(efx->rx_indir_table));
- efx->type->rx_push_rss_config(efx);
- return 0;
+
+ return efx->type->rx_push_rss_config(efx, true, indir);
}
static int efx_ethtool_get_ts_info(struct net_device *net_dev,
diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c
index f166c8ef38a3..80e69af21642 100644
--- a/drivers/net/ethernet/sfc/falcon.c
+++ b/drivers/net/ethernet/sfc/falcon.c
@@ -477,16 +477,29 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
*
**************************************************************************
*/
+static int dummy_rx_push_rss_config(struct efx_nic *efx, bool user,
+ const u32 *rx_indir_table)
+{
+ (void) efx;
+ (void) user;
+ (void) rx_indir_table;
+ return -ENOSYS;
+}
-static void falcon_b0_rx_push_rss_config(struct efx_nic *efx)
+static int falcon_b0_rx_push_rss_config(struct efx_nic *efx, bool user,
+ const u32 *rx_indir_table)
{
efx_oword_t temp;
+ (void) user;
/* Set hash key for IPv4 */
memcpy(&temp, efx->rx_hash_key, sizeof(temp));
efx_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY);
+ memcpy(efx->rx_indir_table, rx_indir_table,
+ sizeof(efx->rx_indir_table));
efx_farch_rx_push_indir_table(efx);
+ return 0;
}
/**************************************************************************
@@ -2507,7 +2520,7 @@ static int falcon_init_nic(struct efx_nic *efx)
falcon_init_rx_cfg(efx);
if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
- falcon_b0_rx_push_rss_config(efx);
+ falcon_b0_rx_push_rss_config(efx, false, efx->rx_indir_table);
/* Set destination of both TX and RX Flush events */
EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0);
@@ -2687,6 +2700,8 @@ static int falcon_set_wol(struct efx_nic *efx, u32 type)
*/
const struct efx_nic_type falcon_a1_nic_type = {
+ .is_vf = false,
+ .mem_bar = EFX_MEM_BAR,
.mem_map_size = falcon_a1_mem_map_size,
.probe = falcon_probe_nic,
.remove = falcon_remove_nic,
@@ -2729,7 +2744,7 @@ const struct efx_nic_type falcon_a1_nic_type = {
.tx_init = efx_farch_tx_init,
.tx_remove = efx_farch_tx_remove,
.tx_write = efx_farch_tx_write,
- .rx_push_rss_config = efx_port_dummy_op_void,
+ .rx_push_rss_config = dummy_rx_push_rss_config,
.rx_probe = efx_farch_rx_probe,
.rx_init = efx_farch_rx_init,
.rx_remove = efx_farch_rx_remove,
@@ -2766,11 +2781,6 @@ const struct efx_nic_type falcon_a1_nic_type = {
.mtd_write = falcon_mtd_write,
.mtd_sync = falcon_mtd_sync,
#endif
- .sriov_init = efx_falcon_sriov_init,
- .sriov_fini = efx_falcon_sriov_fini,
- .sriov_mac_address_changed = efx_falcon_sriov_mac_address_changed,
- .sriov_wanted = efx_falcon_sriov_wanted,
- .sriov_reset = efx_falcon_sriov_reset,
.revision = EFX_REV_FALCON_A1,
.txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER,
@@ -2788,6 +2798,8 @@ const struct efx_nic_type falcon_a1_nic_type = {
};
const struct efx_nic_type falcon_b0_nic_type = {
+ .is_vf = false,
+ .mem_bar = EFX_MEM_BAR,
.mem_map_size = falcon_b0_mem_map_size,
.probe = falcon_probe_nic,
.remove = falcon_remove_nic,
@@ -2867,11 +2879,6 @@ const struct efx_nic_type falcon_b0_nic_type = {
.mtd_write = falcon_mtd_write,
.mtd_sync = falcon_mtd_sync,
#endif
- .sriov_init = efx_falcon_sriov_init,
- .sriov_fini = efx_falcon_sriov_fini,
- .sriov_mac_address_changed = efx_falcon_sriov_mac_address_changed,
- .sriov_wanted = efx_falcon_sriov_wanted,
- .sriov_reset = efx_falcon_sriov_reset,
.revision = EFX_REV_FALCON_B0,
.txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL,
diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c
index bb89e96a125e..f08266f0eca2 100644
--- a/drivers/net/ethernet/sfc/farch.c
+++ b/drivers/net/ethernet/sfc/farch.c
@@ -20,6 +20,8 @@
#include "efx.h"
#include "nic.h"
#include "farch_regs.h"
+#include "sriov.h"
+#include "siena_sriov.h"
#include "io.h"
#include "workarounds.h"
@@ -1198,13 +1200,17 @@ efx_farch_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
netif_vdbg(efx, hw, efx->net_dev, "channel %d TXQ %d flushed\n",
channel->channel, ev_sub_data);
efx_farch_handle_tx_flush_done(efx, event);
+#ifdef CONFIG_SFC_SRIOV
efx_siena_sriov_tx_flush_done(efx, event);
+#endif
break;
case FSE_AZ_RX_DESCQ_FLS_DONE_EV:
netif_vdbg(efx, hw, efx->net_dev, "channel %d RXQ %d flushed\n",
channel->channel, ev_sub_data);
efx_farch_handle_rx_flush_done(efx, event);
+#ifdef CONFIG_SFC_SRIOV
efx_siena_sriov_rx_flush_done(efx, event);
+#endif
break;
case FSE_AZ_EVQ_INIT_DONE_EV:
netif_dbg(efx, hw, efx->net_dev,
@@ -1242,8 +1248,11 @@ efx_farch_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
" RX Q %d is disabled.\n", ev_sub_data,
ev_sub_data);
efx_schedule_reset(efx, RESET_TYPE_DMA_ERROR);
- } else
+ }
+#ifdef CONFIG_SFC_SRIOV
+ else
efx_siena_sriov_desc_fetch_err(efx, ev_sub_data);
+#endif
break;
case FSE_BZ_TX_DSC_ERROR_EV:
if (ev_sub_data < EFX_VI_BASE) {
@@ -1252,8 +1261,11 @@ efx_farch_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
" TX Q %d is disabled.\n", ev_sub_data,
ev_sub_data);
efx_schedule_reset(efx, RESET_TYPE_DMA_ERROR);
- } else
+ }
+#ifdef CONFIG_SFC_SRIOV
+ else
efx_siena_sriov_desc_fetch_err(efx, ev_sub_data);
+#endif
break;
default:
netif_vdbg(efx, hw, efx->net_dev,
@@ -1317,9 +1329,11 @@ int efx_farch_ev_process(struct efx_channel *channel, int budget)
case FSE_AZ_EV_CODE_DRIVER_EV:
efx_farch_handle_driver_event(channel, &event);
break;
+#ifdef CONFIG_SFC_SRIOV
case FSE_CZ_EV_CODE_USER_EV:
efx_siena_sriov_event(channel, &event);
break;
+#endif
case FSE_CZ_EV_CODE_MCDI_EV:
efx_mcdi_process_event(channel, &event);
break;
@@ -1685,28 +1699,32 @@ void efx_farch_dimension_resources(struct efx_nic *efx, unsigned sram_lim_qw)
vi_count = max(efx->n_channels, efx->n_tx_channels * EFX_TXQ_TYPES);
#ifdef CONFIG_SFC_SRIOV
- if (efx->type->sriov_wanted(efx)) {
- unsigned vi_dc_entries, buftbl_free, entries_per_vf, vf_limit;
-
- nic_data->vf_buftbl_base = buftbl_min;
-
- vi_dc_entries = RX_DC_ENTRIES + TX_DC_ENTRIES;
- vi_count = max(vi_count, EFX_VI_BASE);
- buftbl_free = (sram_lim_qw - buftbl_min -
- vi_count * vi_dc_entries);
-
- entries_per_vf = ((vi_dc_entries + EFX_VF_BUFTBL_PER_VI) *
- efx_vf_size(efx));
- vf_limit = min(buftbl_free / entries_per_vf,
- (1024U - EFX_VI_BASE) >> efx->vi_scale);
-
- if (efx->vf_count > vf_limit) {
- netif_err(efx, probe, efx->net_dev,
- "Reducing VF count from from %d to %d\n",
- efx->vf_count, vf_limit);
- efx->vf_count = vf_limit;
+ if (efx->type->sriov_wanted) {
+ if (efx->type->sriov_wanted(efx)) {
+ unsigned vi_dc_entries, buftbl_free;
+ unsigned entries_per_vf, vf_limit;
+
+ nic_data->vf_buftbl_base = buftbl_min;
+
+ vi_dc_entries = RX_DC_ENTRIES + TX_DC_ENTRIES;
+ vi_count = max(vi_count, EFX_VI_BASE);
+ buftbl_free = (sram_lim_qw - buftbl_min -
+ vi_count * vi_dc_entries);
+
+ entries_per_vf = ((vi_dc_entries +
+ EFX_VF_BUFTBL_PER_VI) *
+ efx_vf_size(efx));
+ vf_limit = min(buftbl_free / entries_per_vf,
+ (1024U - EFX_VI_BASE) >> efx->vi_scale);
+
+ if (efx->vf_count > vf_limit) {
+ netif_err(efx, probe, efx->net_dev,
+ "Reducing VF count from from %d to %d\n",
+ efx->vf_count, vf_limit);
+ efx->vf_count = vf_limit;
+ }
+ vi_count += efx->vf_count * efx_vf_size(efx);
}
- vi_count += efx->vf_count * efx_vf_size(efx);
}
#endif
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index d37928f01949..81640f8bb811 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -8,6 +8,7 @@
*/
#include <linux/delay.h>
+#include <linux/moduleparam.h>
#include <asm/cmpxchg.h>
#include "net_driver.h"
#include "nic.h"
@@ -54,18 +55,32 @@ static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
static bool efx_mcdi_poll_once(struct efx_nic *efx);
static void efx_mcdi_abandon(struct efx_nic *efx);
+#ifdef CONFIG_SFC_MCDI_LOGGING
+static bool mcdi_logging_default;
+module_param(mcdi_logging_default, bool, 0644);
+MODULE_PARM_DESC(mcdi_logging_default,
+ "Enable MCDI logging on newly-probed functions");
+#endif
+
int efx_mcdi_init(struct efx_nic *efx)
{
struct efx_mcdi_iface *mcdi;
bool already_attached;
- int rc;
+ int rc = -ENOMEM;
efx->mcdi = kzalloc(sizeof(*efx->mcdi), GFP_KERNEL);
if (!efx->mcdi)
- return -ENOMEM;
+ goto fail;
mcdi = efx_mcdi(efx);
mcdi->efx = efx;
+#ifdef CONFIG_SFC_MCDI_LOGGING
+ /* consuming code assumes buffer is page-sized */
+ mcdi->logging_buffer = (char *)__get_free_page(GFP_KERNEL);
+ if (!mcdi->logging_buffer)
+ goto fail1;
+ mcdi->logging_enabled = mcdi_logging_default;
+#endif
init_waitqueue_head(&mcdi->wq);
spin_lock_init(&mcdi->iface_lock);
mcdi->state = MCDI_STATE_QUIESCENT;
@@ -81,7 +96,7 @@ int efx_mcdi_init(struct efx_nic *efx)
/* Recover from a failed assertion before probing */
rc = efx_mcdi_handle_assertion(efx);
if (rc)
- return rc;
+ goto fail2;
/* Let the MC (and BMC, if this is a LOM) know that the driver
* is loaded. We should do this before we reset the NIC.
@@ -90,7 +105,7 @@ int efx_mcdi_init(struct efx_nic *efx)
if (rc) {
netif_err(efx, probe, efx->net_dev,
"Unable to register driver with MCPU\n");
- return rc;
+ goto fail2;
}
if (already_attached)
/* Not a fatal error */
@@ -102,6 +117,15 @@ int efx_mcdi_init(struct efx_nic *efx)
efx->primary = efx;
return 0;
+fail2:
+#ifdef CONFIG_SFC_MCDI_LOGGING
+ free_page((unsigned long)mcdi->logging_buffer);
+fail1:
+#endif
+ kfree(efx->mcdi);
+ efx->mcdi = NULL;
+fail:
+ return rc;
}
void efx_mcdi_fini(struct efx_nic *efx)
@@ -114,6 +138,10 @@ void efx_mcdi_fini(struct efx_nic *efx)
/* Relinquish the device (back to the BMC, if this is a LOM) */
efx_mcdi_drv_attach(efx, false, NULL);
+#ifdef CONFIG_SFC_MCDI_LOGGING
+ free_page((unsigned long)efx->mcdi->iface.logging_buffer);
+#endif
+
kfree(efx->mcdi);
}
@@ -121,6 +149,9 @@ static void efx_mcdi_send_request(struct efx_nic *efx, unsigned cmd,
const efx_dword_t *inbuf, size_t inlen)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
+#ifdef CONFIG_SFC_MCDI_LOGGING
+ char *buf = mcdi->logging_buffer; /* page-sized */
+#endif
efx_dword_t hdr[2];
size_t hdr_len;
u32 xflags, seqno;
@@ -165,6 +196,31 @@ static void efx_mcdi_send_request(struct efx_nic *efx, unsigned cmd,
hdr_len = 8;
}
+#ifdef CONFIG_SFC_MCDI_LOGGING
+ if (mcdi->logging_enabled && !WARN_ON_ONCE(!buf)) {
+ int bytes = 0;
+ int i;
+ /* Lengths should always be a whole number of dwords, so scream
+ * if they're not.
+ */
+ WARN_ON_ONCE(hdr_len % 4);
+ WARN_ON_ONCE(inlen % 4);
+
+ /* We own the logging buffer, as only one MCDI can be in
+ * progress on a NIC at any one time. So no need for locking.
+ */
+ for (i = 0; i < hdr_len / 4 && bytes < PAGE_SIZE; i++)
+ bytes += snprintf(buf + bytes, PAGE_SIZE - bytes,
+ " %08x", le32_to_cpu(hdr[i].u32[0]));
+
+ for (i = 0; i < inlen / 4 && bytes < PAGE_SIZE; i++)
+ bytes += snprintf(buf + bytes, PAGE_SIZE - bytes,
+ " %08x", le32_to_cpu(inbuf[i].u32[0]));
+
+ netif_info(efx, hw, efx->net_dev, "MCDI RPC REQ:%s\n", buf);
+ }
+#endif
+
efx->type->mcdi_request(efx, hdr, hdr_len, inbuf, inlen);
mcdi->new_epoch = false;
@@ -206,6 +262,9 @@ static void efx_mcdi_read_response_header(struct efx_nic *efx)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
unsigned int respseq, respcmd, error;
+#ifdef CONFIG_SFC_MCDI_LOGGING
+ char *buf = mcdi->logging_buffer; /* page-sized */
+#endif
efx_dword_t hdr;
efx->type->mcdi_read_response(efx, &hdr, 0, 4);
@@ -223,6 +282,39 @@ static void efx_mcdi_read_response_header(struct efx_nic *efx)
EFX_DWORD_FIELD(hdr, MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
}
+#ifdef CONFIG_SFC_MCDI_LOGGING
+ if (mcdi->logging_enabled && !WARN_ON_ONCE(!buf)) {
+ size_t hdr_len, data_len;
+ int bytes = 0;
+ int i;
+
+ WARN_ON_ONCE(mcdi->resp_hdr_len % 4);
+ hdr_len = mcdi->resp_hdr_len / 4;
+ /* MCDI_DECLARE_BUF ensures that underlying buffer is padded
+ * to dword size, and the MCDI buffer is always dword size
+ */
+ data_len = DIV_ROUND_UP(mcdi->resp_data_len, 4);
+
+ /* We own the logging buffer, as only one MCDI can be in
+ * progress on a NIC at any one time. So no need for locking.
+ */
+ for (i = 0; i < hdr_len && bytes < PAGE_SIZE; i++) {
+ efx->type->mcdi_read_response(efx, &hdr, (i * 4), 4);
+ bytes += snprintf(buf + bytes, PAGE_SIZE - bytes,
+ " %08x", le32_to_cpu(hdr.u32[0]));
+ }
+
+ for (i = 0; i < data_len && bytes < PAGE_SIZE; i++) {
+ efx->type->mcdi_read_response(efx, &hdr,
+ mcdi->resp_hdr_len + (i * 4), 4);
+ bytes += snprintf(buf + bytes, PAGE_SIZE - bytes,
+ " %08x", le32_to_cpu(hdr.u32[0]));
+ }
+
+ netif_info(efx, hw, efx->net_dev, "MCDI RPC RESP:%s\n", buf);
+ }
+#endif
+
if (error && mcdi->resp_data_len == 0) {
netif_err(efx, hw, efx->net_dev, "MC rebooted\n");
mcdi->resprc = -EIO;
@@ -406,7 +498,7 @@ static bool efx_mcdi_complete_async(struct efx_mcdi_iface *mcdi, bool timeout)
struct efx_mcdi_async_param *async;
size_t hdr_len, data_len, err_len;
efx_dword_t *outbuf;
- MCDI_DECLARE_BUF_OUT_OR_ERR(errbuf, 0);
+ MCDI_DECLARE_BUF_ERR(errbuf);
int rc;
if (cmpxchg(&mcdi->state,
@@ -534,7 +626,7 @@ static int _efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
size_t *outlen_actual, bool quiet)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
- MCDI_DECLARE_BUF_OUT_OR_ERR(errbuf, 0);
+ MCDI_DECLARE_BUF_ERR(errbuf);
int rc;
if (mcdi->mode == MCDI_MODE_POLL)
@@ -1035,7 +1127,9 @@ void efx_mcdi_process_event(struct efx_channel *channel,
/* MAC stats are gather lazily. We can ignore this. */
break;
case MCDI_EVENT_CODE_FLR:
- efx_siena_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF));
+ if (efx->type->sriov_flr)
+ efx->type->sriov_flr(efx,
+ MCDI_EVENT_FIELD(*event, FLR_VF));
break;
case MCDI_EVENT_CODE_PTP_RX:
case MCDI_EVENT_CODE_PTP_FAULT:
@@ -1081,9 +1175,7 @@ void efx_mcdi_process_event(struct efx_channel *channel,
void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len)
{
- MCDI_DECLARE_BUF(outbuf,
- max(MC_CMD_GET_VERSION_OUT_LEN,
- MC_CMD_GET_CAPABILITIES_OUT_LEN));
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_OUT_LEN);
size_t outlength;
const __le16 *ver_words;
size_t offset;
@@ -1108,19 +1200,11 @@ void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len)
* single version. Report which variants are running.
*/
if (efx_nic_rev(efx) >= EFX_REV_HUNT_A0) {
- BUILD_BUG_ON(MC_CMD_GET_CAPABILITIES_IN_LEN != 0);
- rc = efx_mcdi_rpc(efx, MC_CMD_GET_CAPABILITIES, NULL, 0,
- outbuf, sizeof(outbuf), &outlength);
- if (rc || outlength < MC_CMD_GET_CAPABILITIES_OUT_LEN)
- offset += snprintf(
- buf + offset, len - offset, " rx? tx?");
- else
- offset += snprintf(
- buf + offset, len - offset, " rx%x tx%x",
- MCDI_WORD(outbuf,
- GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID),
- MCDI_WORD(outbuf,
- GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID));
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+
+ offset += snprintf(buf + offset, len - offset, " rx%x tx%x",
+ nic_data->rx_dpcpu_fw_id,
+ nic_data->tx_dpcpu_fw_id);
/* It's theoretically possible for the string to exceed 31
* characters, though in practice the first three version
@@ -1150,10 +1234,26 @@ static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_UPDATE, 1);
MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_LOW_LATENCY);
- rc = efx_mcdi_rpc(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf),
- outbuf, sizeof(outbuf), &outlen);
- if (rc)
+ rc = efx_mcdi_rpc_quiet(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf),
+ outbuf, sizeof(outbuf), &outlen);
+ /* If we're not the primary PF, trying to ATTACH with a FIRMWARE_ID
+ * specified will fail with EPERM, and we have to tell the MC we don't
+ * care what firmware we get.
+ */
+ if (rc == -EPERM) {
+ netif_dbg(efx, probe, efx->net_dev,
+ "efx_mcdi_drv_attach with fw-variant setting failed EPERM, trying without it\n");
+ MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_FIRMWARE_ID,
+ MC_CMD_FW_DONT_CARE);
+ rc = efx_mcdi_rpc_quiet(efx, MC_CMD_DRV_ATTACH, inbuf,
+ sizeof(inbuf), outbuf, sizeof(outbuf),
+ &outlen);
+ }
+ if (rc) {
+ efx_mcdi_display_error(efx, MC_CMD_DRV_ATTACH, sizeof(inbuf),
+ outbuf, outlen, rc);
goto fail;
+ }
if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) {
rc = -EIO;
goto fail;
@@ -1178,16 +1278,6 @@ static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
* and are completely trusted by firmware. Abort probing
* if that's not true for this function.
*/
- if (driver_operating &&
- (efx->mcdi->fn_flags &
- (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL |
- 1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED)) !=
- (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL |
- 1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED)) {
- netif_err(efx, probe, efx->net_dev,
- "This driver version only supports one function per port\n");
- return -ENODEV;
- }
if (was_attached != NULL)
*was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE);
@@ -1385,10 +1475,13 @@ fail1:
return rc;
}
+/* Returns 1 if an assertion was read, 0 if no assertion had fired,
+ * negative on error.
+ */
static int efx_mcdi_read_assertion(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_ASSERTS_IN_LEN);
- MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN);
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN);
unsigned int flags, index;
const char *reason;
size_t outlen;
@@ -1406,6 +1499,8 @@ static int efx_mcdi_read_assertion(struct efx_nic *efx)
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_GET_ASSERTS,
inbuf, MC_CMD_GET_ASSERTS_IN_LEN,
outbuf, sizeof(outbuf), &outlen);
+ if (rc == -EPERM)
+ return 0;
} while ((rc == -EINTR || rc == -EIO) && retry-- > 0);
if (rc) {
@@ -1443,24 +1538,31 @@ static int efx_mcdi_read_assertion(struct efx_nic *efx)
MCDI_ARRAY_DWORD(outbuf, GET_ASSERTS_OUT_GP_REGS_OFFS,
index));
- return 0;
+ return 1;
}
-static void efx_mcdi_exit_assertion(struct efx_nic *efx)
+static int efx_mcdi_exit_assertion(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN);
+ int rc;
/* If the MC is running debug firmware, it might now be
* waiting for a debugger to attach, but we just want it to
* reboot. We set a flag that makes the command a no-op if it
- * has already done so. We don't know what return code to
- * expect (0 or -EIO), so ignore it.
+ * has already done so.
+ * The MCDI will thus return either 0 or -EIO.
*/
BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS,
MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION);
- (void) efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN,
- NULL, 0, NULL);
+ rc = efx_mcdi_rpc_quiet(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN,
+ NULL, 0, NULL);
+ if (rc == -EIO)
+ rc = 0;
+ if (rc)
+ efx_mcdi_display_error(efx, MC_CMD_REBOOT, MC_CMD_REBOOT_IN_LEN,
+ NULL, 0, rc);
+ return rc;
}
int efx_mcdi_handle_assertion(struct efx_nic *efx)
@@ -1468,12 +1570,10 @@ int efx_mcdi_handle_assertion(struct efx_nic *efx)
int rc;
rc = efx_mcdi_read_assertion(efx);
- if (rc)
+ if (rc <= 0)
return rc;
- efx_mcdi_exit_assertion(efx);
-
- return 0;
+ return efx_mcdi_exit_assertion(efx);
}
void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
@@ -1550,7 +1650,9 @@ int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method)
if (rc)
return rc;
- if (method == RESET_TYPE_WORLD)
+ if (method == RESET_TYPE_DATAPATH)
+ return 0;
+ else if (method == RESET_TYPE_WORLD)
return efx_mcdi_reset_mc(efx);
else
return efx_mcdi_reset_func(efx);
@@ -1688,6 +1790,36 @@ int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled)
NULL, 0, NULL);
}
+int efx_mcdi_get_workarounds(struct efx_nic *efx, unsigned int *impl_out,
+ unsigned int *enabled_out)
+{
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_WORKAROUNDS_OUT_LEN);
+ size_t outlen;
+ int rc;
+
+ rc = efx_mcdi_rpc(efx, MC_CMD_GET_WORKAROUNDS, NULL, 0,
+ outbuf, sizeof(outbuf), &outlen);
+ if (rc)
+ goto fail;
+
+ if (outlen < MC_CMD_GET_WORKAROUNDS_OUT_LEN) {
+ rc = -EIO;
+ goto fail;
+ }
+
+ if (impl_out)
+ *impl_out = MCDI_DWORD(outbuf, GET_WORKAROUNDS_OUT_IMPLEMENTED);
+
+ if (enabled_out)
+ *enabled_out = MCDI_DWORD(outbuf, GET_WORKAROUNDS_OUT_ENABLED);
+
+ return 0;
+
+fail:
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
+ return rc;
+}
+
#ifdef CONFIG_SFC_MTD
#define EFX_MCDI_NVRAM_LEN_MAX 128
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index 56465f7465a2..1838afe2da92 100644
--- a/drivers/net/ethernet/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
@@ -58,6 +58,8 @@ enum efx_mcdi_mode {
* enabled
* @async_list: Queue of asynchronous requests
* @async_timer: Timer for asynchronous request timeout
+ * @logging_buffer: buffer that may be used to build MCDI tracing messages
+ * @logging_enabled: whether to trace MCDI
*/
struct efx_mcdi_iface {
struct efx_nic *efx;
@@ -74,6 +76,10 @@ struct efx_mcdi_iface {
spinlock_t async_lock;
struct list_head async_list;
struct timer_list async_timer;
+#ifdef CONFIG_SFC_MCDI_LOGGING
+ char *logging_buffer;
+ bool logging_enabled;
+#endif
};
struct efx_mcdi_mon {
@@ -176,10 +182,12 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
* 32-bit-aligned. Also, on Siena we must copy to the MC shared
* memory strictly 32 bits at a time, so add any necessary padding.
*/
-#define MCDI_DECLARE_BUF(_name, _len) \
+#define _MCDI_DECLARE_BUF(_name, _len) \
efx_dword_t _name[DIV_ROUND_UP(_len, 4)]
-#define MCDI_DECLARE_BUF_OUT_OR_ERR(_name, _len) \
- MCDI_DECLARE_BUF(_name, max_t(size_t, _len, 8))
+#define MCDI_DECLARE_BUF(_name, _len) \
+ _MCDI_DECLARE_BUF(_name, _len) = {{{0}}}
+#define MCDI_DECLARE_BUF_ERR(_name) \
+ MCDI_DECLARE_BUF(_name, 8)
#define _MCDI_PTR(_buf, _offset) \
((u8 *)(_buf) + (_offset))
#define MCDI_PTR(_buf, _field) \
@@ -339,6 +347,8 @@ bool efx_mcdi_mac_check_fault(struct efx_nic *efx);
enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason);
int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method);
int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled);
+int efx_mcdi_get_workarounds(struct efx_nic *efx, unsigned int *impl_out,
+ unsigned int *enabled_out);
#ifdef CONFIG_SFC_MCDI_MON
int efx_mcdi_mon_probe(struct efx_nic *efx);
diff --git a/drivers/net/ethernet/sfc/mcdi_pcol.h b/drivers/net/ethernet/sfc/mcdi_pcol.h
index e028de10e1b7..45fca9fc66b7 100644
--- a/drivers/net/ethernet/sfc/mcdi_pcol.h
+++ b/drivers/net/ethernet/sfc/mcdi_pcol.h
@@ -638,6 +638,8 @@
*/
#define MC_CMD_READ32 0x1
+#define MC_CMD_0x1_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_READ32_IN msgrequest */
#define MC_CMD_READ32_IN_LEN 8
#define MC_CMD_READ32_IN_ADDR_OFST 0
@@ -659,6 +661,8 @@
*/
#define MC_CMD_WRITE32 0x2
+#define MC_CMD_0x2_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_WRITE32_IN msgrequest */
#define MC_CMD_WRITE32_IN_LENMIN 8
#define MC_CMD_WRITE32_IN_LENMAX 252
@@ -679,6 +683,8 @@
*/
#define MC_CMD_COPYCODE 0x3
+#define MC_CMD_0x3_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_COPYCODE_IN msgrequest */
#define MC_CMD_COPYCODE_IN_LEN 16
/* Source address */
@@ -717,6 +723,8 @@
*/
#define MC_CMD_SET_FUNC 0x4
+#define MC_CMD_0x4_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_SET_FUNC_IN msgrequest */
#define MC_CMD_SET_FUNC_IN_LEN 4
/* Set function */
@@ -732,6 +740,8 @@
*/
#define MC_CMD_GET_BOOT_STATUS 0x5
+#define MC_CMD_0x5_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_GET_BOOT_STATUS_IN msgrequest */
#define MC_CMD_GET_BOOT_STATUS_IN_LEN 0
@@ -758,6 +768,8 @@
*/
#define MC_CMD_GET_ASSERTS 0x6
+#define MC_CMD_0x6_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_GET_ASSERTS_IN msgrequest */
#define MC_CMD_GET_ASSERTS_IN_LEN 4
/* Set to clear assertion */
@@ -794,6 +806,8 @@
*/
#define MC_CMD_LOG_CTRL 0x7
+#define MC_CMD_0x7_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_LOG_CTRL_IN msgrequest */
#define MC_CMD_LOG_CTRL_IN_LEN 8
/* Log destination */
@@ -814,6 +828,8 @@
*/
#define MC_CMD_GET_VERSION 0x8
+#define MC_CMD_0x8_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_VERSION_IN msgrequest */
#define MC_CMD_GET_VERSION_IN_LEN 0
@@ -870,6 +886,8 @@
*/
#define MC_CMD_PTP 0xb
+#define MC_CMD_0xb_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_PTP_IN msgrequest */
#define MC_CMD_PTP_IN_LEN 1
/* PTP operation code */
@@ -1404,6 +1422,8 @@
*/
#define MC_CMD_CSR_READ32 0xc
+#define MC_CMD_0xc_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_CSR_READ32_IN msgrequest */
#define MC_CMD_CSR_READ32_IN_LEN 12
/* Address */
@@ -1428,6 +1448,8 @@
*/
#define MC_CMD_CSR_WRITE32 0xd
+#define MC_CMD_0xd_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_CSR_WRITE32_IN msgrequest */
#define MC_CMD_CSR_WRITE32_IN_LENMIN 12
#define MC_CMD_CSR_WRITE32_IN_LENMAX 252
@@ -1452,6 +1474,8 @@
*/
#define MC_CMD_HP 0x54
+#define MC_CMD_0x54_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_HP_IN msgrequest */
#define MC_CMD_HP_IN_LEN 16
/* HP OCSD sub-command. When address is not NULL, request activation of OCSD at
@@ -1493,6 +1517,8 @@
*/
#define MC_CMD_STACKINFO 0xf
+#define MC_CMD_0xf_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_STACKINFO_IN msgrequest */
#define MC_CMD_STACKINFO_IN_LEN 0
@@ -1513,6 +1539,8 @@
*/
#define MC_CMD_MDIO_READ 0x10
+#define MC_CMD_0x10_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_MDIO_READ_IN msgrequest */
#define MC_CMD_MDIO_READ_IN_LEN 16
/* Bus number; there are two MDIO buses: one for the internal PHY, and one for
@@ -1552,6 +1580,8 @@
*/
#define MC_CMD_MDIO_WRITE 0x11
+#define MC_CMD_0x11_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_MDIO_WRITE_IN msgrequest */
#define MC_CMD_MDIO_WRITE_IN_LEN 20
/* Bus number; there are two MDIO buses: one for the internal PHY, and one for
@@ -1591,6 +1621,8 @@
*/
#define MC_CMD_DBI_WRITE 0x12
+#define MC_CMD_0x12_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_DBI_WRITE_IN msgrequest */
#define MC_CMD_DBI_WRITE_IN_LENMIN 12
#define MC_CMD_DBI_WRITE_IN_LENMAX 252
@@ -1739,6 +1771,8 @@
*/
#define MC_CMD_GET_BOARD_CFG 0x18
+#define MC_CMD_0x18_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_BOARD_CFG_IN msgrequest */
#define MC_CMD_GET_BOARD_CFG_IN_LEN 0
@@ -1778,6 +1812,8 @@
*/
#define MC_CMD_DBI_READX 0x19
+#define MC_CMD_0x19_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_DBI_READX_IN msgrequest */
#define MC_CMD_DBI_READX_IN_LENMIN 8
#define MC_CMD_DBI_READX_IN_LENMAX 248
@@ -1822,6 +1858,8 @@
*/
#define MC_CMD_SET_RAND_SEED 0x1a
+#define MC_CMD_0x1a_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_SET_RAND_SEED_IN msgrequest */
#define MC_CMD_SET_RAND_SEED_IN_LEN 16
/* Seed value. */
@@ -1863,6 +1901,8 @@
*/
#define MC_CMD_DRV_ATTACH 0x1c
+#define MC_CMD_0x1c_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_DRV_ATTACH_IN msgrequest */
#define MC_CMD_DRV_ATTACH_IN_LEN 12
/* new state (0=detached, 1=attached) to set if UPDATE=1 */
@@ -1875,6 +1915,8 @@
#define MC_CMD_FW_FULL_FEATURED 0x0
/* enum: Prefer to use firmware with fewer features but lower latency */
#define MC_CMD_FW_LOW_LATENCY 0x1
+/* enum: Only this option is allowed for non-admin functions */
+#define MC_CMD_FW_DONT_CARE 0xffffffff
/* MC_CMD_DRV_ATTACH_OUT msgresponse */
#define MC_CMD_DRV_ATTACH_OUT_LEN 4
@@ -1920,6 +1962,8 @@
*/
#define MC_CMD_PORT_RESET 0x20
+#define MC_CMD_0x20_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_PORT_RESET_IN msgrequest */
#define MC_CMD_PORT_RESET_IN_LEN 0
@@ -1934,6 +1978,7 @@
* extended version of the deprecated MC_CMD_PORT_RESET with added fields.
*/
#define MC_CMD_ENTITY_RESET 0x20
+/* MC_CMD_0x20_PRIVILEGE_CTG SRIOV_CTG_GENERAL */
/* MC_CMD_ENTITY_RESET_IN msgrequest */
#define MC_CMD_ENTITY_RESET_IN_LEN 4
@@ -2023,6 +2068,8 @@
*/
#define MC_CMD_PUTS 0x23
+#define MC_CMD_0x23_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_PUTS_IN msgrequest */
#define MC_CMD_PUTS_IN_LENMIN 13
#define MC_CMD_PUTS_IN_LENMAX 252
@@ -2050,6 +2097,8 @@
*/
#define MC_CMD_GET_PHY_CFG 0x24
+#define MC_CMD_0x24_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_PHY_CFG_IN msgrequest */
#define MC_CMD_GET_PHY_CFG_IN_LEN 0
@@ -2149,6 +2198,8 @@
*/
#define MC_CMD_START_BIST 0x25
+#define MC_CMD_0x25_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_START_BIST_IN msgrequest */
#define MC_CMD_START_BIST_IN_LEN 4
/* Type of test. */
@@ -2185,6 +2236,8 @@
*/
#define MC_CMD_POLL_BIST 0x26
+#define MC_CMD_0x26_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_POLL_BIST_IN msgrequest */
#define MC_CMD_POLL_BIST_IN_LEN 0
@@ -2344,6 +2397,8 @@
*/
#define MC_CMD_GET_LOOPBACK_MODES 0x28
+#define MC_CMD_0x28_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_LOOPBACK_MODES_IN msgrequest */
#define MC_CMD_GET_LOOPBACK_MODES_IN_LEN 0
@@ -2463,6 +2518,8 @@
*/
#define MC_CMD_GET_LINK 0x29
+#define MC_CMD_0x29_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_LINK_IN msgrequest */
#define MC_CMD_GET_LINK_IN_LEN 0
@@ -2519,6 +2576,8 @@
*/
#define MC_CMD_SET_LINK 0x2a
+#define MC_CMD_0x2a_PRIVILEGE_CTG SRIOV_CTG_LINK
+
/* MC_CMD_SET_LINK_IN msgrequest */
#define MC_CMD_SET_LINK_IN_LEN 16
/* ??? */
@@ -2550,6 +2609,8 @@
*/
#define MC_CMD_SET_ID_LED 0x2b
+#define MC_CMD_0x2b_PRIVILEGE_CTG SRIOV_CTG_LINK
+
/* MC_CMD_SET_ID_LED_IN msgrequest */
#define MC_CMD_SET_ID_LED_IN_LEN 4
/* Set LED state. */
@@ -2568,6 +2629,8 @@
*/
#define MC_CMD_SET_MAC 0x2c
+#define MC_CMD_0x2c_PRIVILEGE_CTG SRIOV_CTG_LINK
+
/* MC_CMD_SET_MAC_IN msgrequest */
#define MC_CMD_SET_MAC_IN_LEN 24
/* The MTU is the MTU programmed directly into the XMAC/GMAC (inclusive of
@@ -2609,6 +2672,8 @@
*/
#define MC_CMD_PHY_STATS 0x2d
+#define MC_CMD_0x2d_PRIVILEGE_CTG SRIOV_CTG_LINK
+
/* MC_CMD_PHY_STATS_IN msgrequest */
#define MC_CMD_PHY_STATS_IN_LEN 8
/* ??? */
@@ -2687,8 +2752,10 @@
*/
#define MC_CMD_MAC_STATS 0x2e
+#define MC_CMD_0x2e_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_MAC_STATS_IN msgrequest */
-#define MC_CMD_MAC_STATS_IN_LEN 16
+#define MC_CMD_MAC_STATS_IN_LEN 20
/* ??? */
#define MC_CMD_MAC_STATS_IN_DMA_ADDR_OFST 0
#define MC_CMD_MAC_STATS_IN_DMA_ADDR_LEN 8
@@ -2710,6 +2777,8 @@
#define MC_CMD_MAC_STATS_IN_PERIOD_MS_LBN 16
#define MC_CMD_MAC_STATS_IN_PERIOD_MS_WIDTH 16
#define MC_CMD_MAC_STATS_IN_DMA_LEN_OFST 12
+/* port id so vadapter stats can be provided */
+#define MC_CMD_MAC_STATS_IN_PORT_ID_OFST 16
/* MC_CMD_MAC_STATS_OUT_DMA msgresponse */
#define MC_CMD_MAC_STATS_OUT_DMA_LEN 0
@@ -2824,11 +2893,31 @@
/* enum: RXDP counter: Number of times an emergency descriptor fetch was
* performed. Valid for EF10 with PM_AND_RXDP_COUNTERS capability only.
*/
-#define MC_CMD_MAC_RXDP_EMERGENCY_FETCH_CONDITIONS 0x47
+#define MC_CMD_MAC_RXDP_HLB_FETCH_CONDITIONS 0x47
/* enum: RXDP counter: Number of times the DPCPU waited for an existing
* descriptor fetch. Valid for EF10 with PM_AND_RXDP_COUNTERS capability only.
*/
-#define MC_CMD_MAC_RXDP_EMERGENCY_WAIT_CONDITIONS 0x48
+#define MC_CMD_MAC_RXDP_HLB_WAIT_CONDITIONS 0x48
+#define MC_CMD_MAC_VADAPTER_RX_DMABUF_START 0x4c /* enum */
+#define MC_CMD_MAC_VADAPTER_RX_UNICAST_PACKETS 0x4c /* enum */
+#define MC_CMD_MAC_VADAPTER_RX_UNICAST_BYTES 0x4d /* enum */
+#define MC_CMD_MAC_VADAPTER_RX_MULTICAST_PACKETS 0x4e /* enum */
+#define MC_CMD_MAC_VADAPTER_RX_MULTICAST_BYTES 0x4f /* enum */
+#define MC_CMD_MAC_VADAPTER_RX_BROADCAST_PACKETS 0x50 /* enum */
+#define MC_CMD_MAC_VADAPTER_RX_BROADCAST_BYTES 0x51 /* enum */
+#define MC_CMD_MAC_VADAPTER_RX_BAD_PACKETS 0x52 /* enum */
+#define MC_CMD_MAC_VADAPTER_RX_BAD_BYTES 0x53 /* enum */
+#define MC_CMD_MAC_VADAPTER_RX_OVERFLOW 0x54 /* enum */
+#define MC_CMD_MAC_VADAPTER_TX_DMABUF_START 0x57 /* enum */
+#define MC_CMD_MAC_VADAPTER_TX_UNICAST_PACKETS 0x57 /* enum */
+#define MC_CMD_MAC_VADAPTER_TX_UNICAST_BYTES 0x58 /* enum */
+#define MC_CMD_MAC_VADAPTER_TX_MULTICAST_PACKETS 0x59 /* enum */
+#define MC_CMD_MAC_VADAPTER_TX_MULTICAST_BYTES 0x5a /* enum */
+#define MC_CMD_MAC_VADAPTER_TX_BROADCAST_PACKETS 0x5b /* enum */
+#define MC_CMD_MAC_VADAPTER_TX_BROADCAST_BYTES 0x5c /* enum */
+#define MC_CMD_MAC_VADAPTER_TX_BAD_PACKETS 0x5d /* enum */
+#define MC_CMD_MAC_VADAPTER_TX_BAD_BYTES 0x5e /* enum */
+#define MC_CMD_MAC_VADAPTER_TX_OVERFLOW 0x5f /* enum */
/* enum: Start of GMAC stats buffer space, for Siena only. */
#define MC_CMD_GMAC_DMABUF_START 0x40
/* enum: End of GMAC stats buffer space, for Siena only. */
@@ -2926,6 +3015,8 @@
*/
#define MC_CMD_WOL_FILTER_SET 0x32
+#define MC_CMD_0x32_PRIVILEGE_CTG SRIOV_CTG_LINK
+
/* MC_CMD_WOL_FILTER_SET_IN msgrequest */
#define MC_CMD_WOL_FILTER_SET_IN_LEN 192
#define MC_CMD_WOL_FILTER_SET_IN_FILTER_MODE_OFST 0
@@ -3020,6 +3111,8 @@
*/
#define MC_CMD_WOL_FILTER_REMOVE 0x33
+#define MC_CMD_0x33_PRIVILEGE_CTG SRIOV_CTG_LINK
+
/* MC_CMD_WOL_FILTER_REMOVE_IN msgrequest */
#define MC_CMD_WOL_FILTER_REMOVE_IN_LEN 4
#define MC_CMD_WOL_FILTER_REMOVE_IN_FILTER_ID_OFST 0
@@ -3035,6 +3128,8 @@
*/
#define MC_CMD_WOL_FILTER_RESET 0x34
+#define MC_CMD_0x34_PRIVILEGE_CTG SRIOV_CTG_LINK
+
/* MC_CMD_WOL_FILTER_RESET_IN msgrequest */
#define MC_CMD_WOL_FILTER_RESET_IN_LEN 4
#define MC_CMD_WOL_FILTER_RESET_IN_MASK_OFST 0
@@ -3069,6 +3164,8 @@
*/
#define MC_CMD_NVRAM_TYPES 0x36
+#define MC_CMD_0x36_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_NVRAM_TYPES_IN msgrequest */
#define MC_CMD_NVRAM_TYPES_IN_LEN 0
@@ -3125,6 +3222,8 @@
*/
#define MC_CMD_NVRAM_INFO 0x37
+#define MC_CMD_0x37_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_NVRAM_INFO_IN msgrequest */
#define MC_CMD_NVRAM_INFO_IN_LEN 4
#define MC_CMD_NVRAM_INFO_IN_TYPE_OFST 0
@@ -3157,6 +3256,8 @@
*/
#define MC_CMD_NVRAM_UPDATE_START 0x38
+#define MC_CMD_0x38_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_NVRAM_UPDATE_START_IN msgrequest */
#define MC_CMD_NVRAM_UPDATE_START_IN_LEN 4
#define MC_CMD_NVRAM_UPDATE_START_IN_TYPE_OFST 0
@@ -3175,6 +3276,8 @@
*/
#define MC_CMD_NVRAM_READ 0x39
+#define MC_CMD_0x39_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_NVRAM_READ_IN msgrequest */
#define MC_CMD_NVRAM_READ_IN_LEN 12
#define MC_CMD_NVRAM_READ_IN_TYPE_OFST 0
@@ -3202,6 +3305,8 @@
*/
#define MC_CMD_NVRAM_WRITE 0x3a
+#define MC_CMD_0x3a_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_NVRAM_WRITE_IN msgrequest */
#define MC_CMD_NVRAM_WRITE_IN_LENMIN 13
#define MC_CMD_NVRAM_WRITE_IN_LENMAX 252
@@ -3228,6 +3333,8 @@
*/
#define MC_CMD_NVRAM_ERASE 0x3b
+#define MC_CMD_0x3b_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_NVRAM_ERASE_IN msgrequest */
#define MC_CMD_NVRAM_ERASE_IN_LEN 12
#define MC_CMD_NVRAM_ERASE_IN_TYPE_OFST 0
@@ -3248,6 +3355,8 @@
*/
#define MC_CMD_NVRAM_UPDATE_FINISH 0x3c
+#define MC_CMD_0x3c_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_NVRAM_UPDATE_FINISH_IN msgrequest */
#define MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN 8
#define MC_CMD_NVRAM_UPDATE_FINISH_IN_TYPE_OFST 0
@@ -3279,6 +3388,8 @@
*/
#define MC_CMD_REBOOT 0x3d
+#define MC_CMD_0x3d_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_REBOOT_IN msgrequest */
#define MC_CMD_REBOOT_IN_LEN 4
#define MC_CMD_REBOOT_IN_FLAGS_OFST 0
@@ -3316,6 +3427,8 @@
*/
#define MC_CMD_REBOOT_MODE 0x3f
+#define MC_CMD_0x3f_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_REBOOT_MODE_IN msgrequest */
#define MC_CMD_REBOOT_MODE_IN_LEN 4
#define MC_CMD_REBOOT_MODE_IN_VALUE_OFST 0
@@ -3368,6 +3481,8 @@
*/
#define MC_CMD_SENSOR_INFO 0x41
+#define MC_CMD_0x41_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_SENSOR_INFO_IN msgrequest */
#define MC_CMD_SENSOR_INFO_IN_LEN 0
@@ -3542,6 +3657,8 @@
*/
#define MC_CMD_READ_SENSORS 0x42
+#define MC_CMD_0x42_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_READ_SENSORS_IN msgrequest */
#define MC_CMD_READ_SENSORS_IN_LEN 8
/* DMA address of host buffer for sensor readings (must be 4Kbyte aligned). */
@@ -3602,6 +3719,8 @@
*/
#define MC_CMD_GET_PHY_STATE 0x43
+#define MC_CMD_0x43_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_PHY_STATE_IN msgrequest */
#define MC_CMD_GET_PHY_STATE_IN_LEN 0
@@ -3636,6 +3755,8 @@
*/
#define MC_CMD_WOL_FILTER_GET 0x45
+#define MC_CMD_0x45_PRIVILEGE_CTG SRIOV_CTG_LINK
+
/* MC_CMD_WOL_FILTER_GET_IN msgrequest */
#define MC_CMD_WOL_FILTER_GET_IN_LEN 0
@@ -3651,6 +3772,8 @@
*/
#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD 0x46
+#define MC_CMD_0x46_PRIVILEGE_CTG SRIOV_CTG_LINK
+
/* MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN msgrequest */
#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_LENMIN 8
#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_LENMAX 252
@@ -3692,6 +3815,8 @@
*/
#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD 0x47
+#define MC_CMD_0x47_PRIVILEGE_CTG SRIOV_CTG_LINK
+
/* MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN msgrequest */
#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_LEN 8
#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_PROTOCOL_OFST 0
@@ -3722,6 +3847,8 @@
*/
#define MC_CMD_TESTASSERT 0x49
+#define MC_CMD_0x49_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_TESTASSERT_IN msgrequest */
#define MC_CMD_TESTASSERT_IN_LEN 0
@@ -3739,6 +3866,8 @@
*/
#define MC_CMD_WORKAROUND 0x4a
+#define MC_CMD_0x4a_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_WORKAROUND_IN msgrequest */
#define MC_CMD_WORKAROUND_IN_LEN 8
#define MC_CMD_WORKAROUND_IN_TYPE_OFST 0
@@ -3765,6 +3894,8 @@
*/
#define MC_CMD_GET_PHY_MEDIA_INFO 0x4b
+#define MC_CMD_0x4b_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_GET_PHY_MEDIA_INFO_IN msgrequest */
#define MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN 4
#define MC_CMD_GET_PHY_MEDIA_INFO_IN_PAGE_OFST 0
@@ -3788,6 +3919,8 @@
*/
#define MC_CMD_NVRAM_TEST 0x4c
+#define MC_CMD_0x4c_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_NVRAM_TEST_IN msgrequest */
#define MC_CMD_NVRAM_TEST_IN_LEN 4
#define MC_CMD_NVRAM_TEST_IN_TYPE_OFST 0
@@ -3849,6 +3982,8 @@
*/
#define MC_CMD_SENSOR_SET_LIMS 0x4e
+#define MC_CMD_0x4e_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_SENSOR_SET_LIMS_IN msgrequest */
#define MC_CMD_SENSOR_SET_LIMS_IN_LEN 20
#define MC_CMD_SENSOR_SET_LIMS_IN_SENSOR_OFST 0
@@ -3890,6 +4025,8 @@
*/
#define MC_CMD_NVRAM_PARTITIONS 0x51
+#define MC_CMD_0x51_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_NVRAM_PARTITIONS_IN msgrequest */
#define MC_CMD_NVRAM_PARTITIONS_IN_LEN 0
@@ -3913,6 +4050,8 @@
*/
#define MC_CMD_NVRAM_METADATA 0x52
+#define MC_CMD_0x52_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_NVRAM_METADATA_IN msgrequest */
#define MC_CMD_NVRAM_METADATA_IN_LEN 4
/* Partition type ID code */
@@ -3958,6 +4097,8 @@
*/
#define MC_CMD_GET_MAC_ADDRESSES 0x55
+#define MC_CMD_0x55_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_MAC_ADDRESSES_IN msgrequest */
#define MC_CMD_GET_MAC_ADDRESSES_IN_LEN 0
@@ -4087,11 +4228,66 @@
/***********************************/
+/* MC_CMD_GET_WORKAROUNDS
+ * Read the list of all implemented and all currently enabled workarounds. The
+ * enums here must correspond with those in MC_CMD_WORKAROUND.
+ */
+#define MC_CMD_GET_WORKAROUNDS 0x59
+
+/* MC_CMD_GET_WORKAROUNDS_OUT msgresponse */
+#define MC_CMD_GET_WORKAROUNDS_OUT_LEN 8
+/* Each workaround is represented by a single bit according to the enums below.
+ */
+#define MC_CMD_GET_WORKAROUNDS_OUT_IMPLEMENTED_OFST 0
+#define MC_CMD_GET_WORKAROUNDS_OUT_ENABLED_OFST 4
+/* enum: Bug 17230 work around. */
+#define MC_CMD_GET_WORKAROUNDS_OUT_BUG17230 0x2
+/* enum: Bug 35388 work around (unsafe EVQ writes). */
+#define MC_CMD_GET_WORKAROUNDS_OUT_BUG35388 0x4
+/* enum: Bug35017 workaround (A64 tables must be identity map) */
+#define MC_CMD_GET_WORKAROUNDS_OUT_BUG35017 0x8
+
+
+/***********************************/
+/* MC_CMD_LINK_STATE_MODE
+ * Read/set link state mode of a VF
+ */
+#define MC_CMD_LINK_STATE_MODE 0x5c
+
+#define MC_CMD_0x5c_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
+/* MC_CMD_LINK_STATE_MODE_IN msgrequest */
+#define MC_CMD_LINK_STATE_MODE_IN_LEN 8
+/* The target function to have its link state mode read or set, must be a VF
+ * e.g. VF 1,3 = 0x00030001
+ */
+#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_OFST 0
+#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_PF_LBN 0
+#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_PF_WIDTH 16
+#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_VF_LBN 16
+#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_VF_WIDTH 16
+/* New link state mode to be set */
+#define MC_CMD_LINK_STATE_MODE_IN_NEW_MODE_OFST 4
+#define MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_AUTO 0x0 /* enum */
+#define MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_UP 0x1 /* enum */
+#define MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_DOWN 0x2 /* enum */
+/* enum: Use this value to just read the existing setting without modifying it.
+ */
+#define MC_CMD_LINK_STATE_MODE_IN_DO_NOT_CHANGE 0xffffffff
+
+/* MC_CMD_LINK_STATE_MODE_OUT msgresponse */
+#define MC_CMD_LINK_STATE_MODE_OUT_LEN 4
+#define MC_CMD_LINK_STATE_MODE_OUT_OLD_MODE_OFST 0
+
+
+/***********************************/
/* MC_CMD_READ_REGS
* Get a dump of the MCPU registers
*/
#define MC_CMD_READ_REGS 0x50
+#define MC_CMD_0x50_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_READ_REGS_IN msgrequest */
#define MC_CMD_READ_REGS_IN_LEN 0
@@ -4115,6 +4311,8 @@
*/
#define MC_CMD_INIT_EVQ 0x80
+#define MC_CMD_0x80_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_INIT_EVQ_IN msgrequest */
#define MC_CMD_INIT_EVQ_IN_LENMIN 44
#define MC_CMD_INIT_EVQ_IN_LENMAX 548
@@ -4213,6 +4411,8 @@
*/
#define MC_CMD_INIT_RXQ 0x81
+#define MC_CMD_0x81_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_INIT_RXQ_IN msgrequest */
#define MC_CMD_INIT_RXQ_IN_LENMIN 36
#define MC_CMD_INIT_RXQ_IN_LENMAX 252
@@ -4265,6 +4465,8 @@
*/
#define MC_CMD_INIT_TXQ 0x82
+#define MC_CMD_0x82_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_INIT_TXQ_IN msgrequest */
#define MC_CMD_INIT_TXQ_IN_LENMIN 36
#define MC_CMD_INIT_TXQ_IN_LENMAX 252
@@ -4322,6 +4524,8 @@
*/
#define MC_CMD_FINI_EVQ 0x83
+#define MC_CMD_0x83_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_FINI_EVQ_IN msgrequest */
#define MC_CMD_FINI_EVQ_IN_LEN 4
/* Instance of EVQ to destroy. Should be the same instance as that previously
@@ -4339,6 +4543,8 @@
*/
#define MC_CMD_FINI_RXQ 0x84
+#define MC_CMD_0x84_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_FINI_RXQ_IN msgrequest */
#define MC_CMD_FINI_RXQ_IN_LEN 4
/* Instance of RXQ to destroy */
@@ -4354,6 +4560,8 @@
*/
#define MC_CMD_FINI_TXQ 0x85
+#define MC_CMD_0x85_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_FINI_TXQ_IN msgrequest */
#define MC_CMD_FINI_TXQ_IN_LEN 4
/* Instance of TXQ to destroy */
@@ -4369,6 +4577,8 @@
*/
#define MC_CMD_DRIVER_EVENT 0x86
+#define MC_CMD_0x86_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_DRIVER_EVENT_IN msgrequest */
#define MC_CMD_DRIVER_EVENT_IN_LEN 12
/* Handle of target EVQ */
@@ -4392,6 +4602,8 @@
*/
#define MC_CMD_PROXY_CMD 0x5b
+#define MC_CMD_0x5b_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_PROXY_CMD_IN msgrequest */
#define MC_CMD_PROXY_CMD_IN_LEN 4
/* The handle of the target function. */
@@ -4414,6 +4626,8 @@
*/
#define MC_CMD_ALLOC_BUFTBL_CHUNK 0x87
+#define MC_CMD_0x87_PRIVILEGE_CTG SRIOV_CTG_ONLOAD
+
/* MC_CMD_ALLOC_BUFTBL_CHUNK_IN msgrequest */
#define MC_CMD_ALLOC_BUFTBL_CHUNK_IN_LEN 8
/* Owner ID to use */
@@ -4437,6 +4651,8 @@
*/
#define MC_CMD_PROGRAM_BUFTBL_ENTRIES 0x88
+#define MC_CMD_0x88_PRIVILEGE_CTG SRIOV_CTG_ONLOAD
+
/* MC_CMD_PROGRAM_BUFTBL_ENTRIES_IN msgrequest */
#define MC_CMD_PROGRAM_BUFTBL_ENTRIES_IN_LENMIN 20
#define MC_CMD_PROGRAM_BUFTBL_ENTRIES_IN_LENMAX 268
@@ -4463,6 +4679,8 @@
*/
#define MC_CMD_FREE_BUFTBL_CHUNK 0x89
+#define MC_CMD_0x89_PRIVILEGE_CTG SRIOV_CTG_ONLOAD
+
/* MC_CMD_FREE_BUFTBL_CHUNK_IN msgrequest */
#define MC_CMD_FREE_BUFTBL_CHUNK_IN_LEN 4
#define MC_CMD_FREE_BUFTBL_CHUNK_IN_HANDLE_OFST 0
@@ -4477,6 +4695,8 @@
*/
#define MC_CMD_FILTER_OP 0x8a
+#define MC_CMD_0x8a_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_FILTER_OP_IN msgrequest */
#define MC_CMD_FILTER_OP_IN_LEN 108
/* identifies the type of operation requested */
@@ -4637,6 +4857,8 @@
*/
#define MC_CMD_GET_PARSER_DISP_INFO 0xe4
+#define MC_CMD_0xe4_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_PARSER_DISP_INFO_IN msgrequest */
#define MC_CMD_GET_PARSER_DISP_INFO_IN_LEN 4
/* identifies the type of operation requested */
@@ -4669,6 +4891,8 @@
*/
#define MC_CMD_PARSER_DISP_RW 0xe5
+#define MC_CMD_0xe5_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_PARSER_DISP_RW_IN msgrequest */
#define MC_CMD_PARSER_DISP_RW_IN_LEN 32
/* identifies the target of the operation */
@@ -4719,6 +4943,8 @@
*/
#define MC_CMD_GET_PF_COUNT 0xb6
+#define MC_CMD_0xb6_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_PF_COUNT_IN msgrequest */
#define MC_CMD_GET_PF_COUNT_IN_LEN 0
@@ -4750,6 +4976,8 @@
*/
#define MC_CMD_GET_PORT_ASSIGNMENT 0xb8
+#define MC_CMD_0xb8_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_PORT_ASSIGNMENT_IN msgrequest */
#define MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN 0
@@ -4765,6 +4993,8 @@
*/
#define MC_CMD_SET_PORT_ASSIGNMENT 0xb9
+#define MC_CMD_0xb9_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_SET_PORT_ASSIGNMENT_IN msgrequest */
#define MC_CMD_SET_PORT_ASSIGNMENT_IN_LEN 4
/* Identifies the port assignment for this function. */
@@ -4780,6 +5010,8 @@
*/
#define MC_CMD_ALLOC_VIS 0x8b
+#define MC_CMD_0x8b_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_ALLOC_VIS_IN msgrequest */
#define MC_CMD_ALLOC_VIS_IN_LEN 8
/* The minimum number of VIs that is acceptable */
@@ -4804,6 +5036,8 @@
*/
#define MC_CMD_FREE_VIS 0x8c
+#define MC_CMD_0x8c_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_FREE_VIS_IN msgrequest */
#define MC_CMD_FREE_VIS_IN_LEN 0
@@ -4817,6 +5051,8 @@
*/
#define MC_CMD_GET_SRIOV_CFG 0xba
+#define MC_CMD_0xba_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_SRIOV_CFG_IN msgrequest */
#define MC_CMD_GET_SRIOV_CFG_IN_LEN 0
@@ -4841,6 +5077,8 @@
*/
#define MC_CMD_SET_SRIOV_CFG 0xbb
+#define MC_CMD_0xbb_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_SET_SRIOV_CFG_IN msgrequest */
#define MC_CMD_SET_SRIOV_CFG_IN_LEN 20
/* Number of VFs currently enabled. */
@@ -4870,6 +5108,8 @@
*/
#define MC_CMD_GET_VI_ALLOC_INFO 0x8d
+#define MC_CMD_0x8d_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_VI_ALLOC_INFO_IN msgrequest */
#define MC_CMD_GET_VI_ALLOC_INFO_IN_LEN 0
@@ -4889,6 +5129,8 @@
*/
#define MC_CMD_DUMP_VI_STATE 0x8e
+#define MC_CMD_0x8e_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_DUMP_VI_STATE_IN msgrequest */
#define MC_CMD_DUMP_VI_STATE_IN_LEN 4
/* The VI number to query. */
@@ -4998,6 +5240,8 @@
*/
#define MC_CMD_ALLOC_PIOBUF 0x8f
+#define MC_CMD_0x8f_PRIVILEGE_CTG SRIOV_CTG_ONLOAD
+
/* MC_CMD_ALLOC_PIOBUF_IN msgrequest */
#define MC_CMD_ALLOC_PIOBUF_IN_LEN 0
@@ -5013,6 +5257,8 @@
*/
#define MC_CMD_FREE_PIOBUF 0x90
+#define MC_CMD_0x90_PRIVILEGE_CTG SRIOV_CTG_ONLOAD
+
/* MC_CMD_FREE_PIOBUF_IN msgrequest */
#define MC_CMD_FREE_PIOBUF_IN_LEN 4
/* Handle for allocated push I/O buffer. */
@@ -5028,6 +5274,8 @@
*/
#define MC_CMD_GET_VI_TLP_PROCESSING 0xb0
+#define MC_CMD_0xb0_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_VI_TLP_PROCESSING_IN msgrequest */
#define MC_CMD_GET_VI_TLP_PROCESSING_IN_LEN 4
/* VI number to get information for. */
@@ -5062,6 +5310,8 @@
*/
#define MC_CMD_SET_VI_TLP_PROCESSING 0xb1
+#define MC_CMD_0xb1_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_SET_VI_TLP_PROCESSING_IN msgrequest */
#define MC_CMD_SET_VI_TLP_PROCESSING_IN_LEN 8
/* VI number to set information for. */
@@ -5096,6 +5346,8 @@
*/
#define MC_CMD_GET_TLP_PROCESSING_GLOBALS 0xbc
+#define MC_CMD_0xbc_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_GET_TLP_PROCESSING_GLOBALS_IN msgrequest */
#define MC_CMD_GET_TLP_PROCESSING_GLOBALS_IN_LEN 4
#define MC_CMD_GET_TLP_PROCESSING_GLOBALS_IN_TLP_GLOBAL_CATEGORY_OFST 0
@@ -5157,6 +5409,8 @@
*/
#define MC_CMD_SET_TLP_PROCESSING_GLOBALS 0xbd
+#define MC_CMD_0xbd_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_SET_TLP_PROCESSING_GLOBALS_IN msgrequest */
#define MC_CMD_SET_TLP_PROCESSING_GLOBALS_IN_LEN 8
#define MC_CMD_SET_TLP_PROCESSING_GLOBALS_IN_TLP_GLOBAL_CATEGORY_OFST 0
@@ -5203,6 +5457,8 @@
*/
#define MC_CMD_SATELLITE_DOWNLOAD 0x91
+#define MC_CMD_0x91_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_SATELLITE_DOWNLOAD_IN msgrequest: The reset requirements for the CPUs
* are subtle, and so downloads must proceed in a number of phases.
*
@@ -5318,6 +5574,7 @@
*/
#define MC_CMD_GET_CAPABILITIES 0xbe
+#define MC_CMD_0xbe_PRIVILEGE_CTG SRIOV_CTG_GENERAL
/* MC_CMD_GET_CAPABILITIES_IN msgrequest */
#define MC_CMD_GET_CAPABILITIES_IN_LEN 0
@@ -5343,6 +5600,8 @@
#define MC_CMD_GET_CAPABILITIES_OUT_MCAST_FILTER_CHAINING_WIDTH 1
#define MC_CMD_GET_CAPABILITIES_OUT_PM_AND_RXDP_COUNTERS_LBN 27
#define MC_CMD_GET_CAPABILITIES_OUT_PM_AND_RXDP_COUNTERS_WIDTH 1
+#define MC_CMD_GET_CAPABILITIES_OUT_EVB_LBN 30
+#define MC_CMD_GET_CAPABILITIES_OUT_EVB_WIDTH 1
/* RxDPCPU firmware id. */
#define MC_CMD_GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID_OFST 4
#define MC_CMD_GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID_LEN 2
@@ -5433,6 +5692,8 @@
*/
#define MC_CMD_TCM_BUCKET_ALLOC 0xb2
+#define MC_CMD_0xb2_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_TCM_BUCKET_ALLOC_IN msgrequest */
#define MC_CMD_TCM_BUCKET_ALLOC_IN_LEN 0
@@ -5448,6 +5709,8 @@
*/
#define MC_CMD_TCM_BUCKET_FREE 0xb3
+#define MC_CMD_0xb3_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_TCM_BUCKET_FREE_IN msgrequest */
#define MC_CMD_TCM_BUCKET_FREE_IN_LEN 4
/* the bucket id */
@@ -5463,6 +5726,8 @@
*/
#define MC_CMD_TCM_BUCKET_INIT 0xb4
+#define MC_CMD_0xb4_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_TCM_BUCKET_INIT_IN msgrequest */
#define MC_CMD_TCM_BUCKET_INIT_IN_LEN 8
/* the bucket id */
@@ -5480,6 +5745,8 @@
*/
#define MC_CMD_TCM_TXQ_INIT 0xb5
+#define MC_CMD_0xb5_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_TCM_TXQ_INIT_IN msgrequest */
#define MC_CMD_TCM_TXQ_INIT_IN_LEN 28
/* the txq id */
@@ -5511,6 +5778,8 @@
*/
#define MC_CMD_LINK_PIOBUF 0x92
+#define MC_CMD_0x92_PRIVILEGE_CTG SRIOV_CTG_ONLOAD
+
/* MC_CMD_LINK_PIOBUF_IN msgrequest */
#define MC_CMD_LINK_PIOBUF_IN_LEN 8
/* Handle for allocated push I/O buffer. */
@@ -5528,6 +5797,8 @@
*/
#define MC_CMD_UNLINK_PIOBUF 0x93
+#define MC_CMD_0x93_PRIVILEGE_CTG SRIOV_CTG_ONLOAD
+
/* MC_CMD_UNLINK_PIOBUF_IN msgrequest */
#define MC_CMD_UNLINK_PIOBUF_IN_LEN 4
/* Function Local Instance (VI) number. */
@@ -5543,6 +5814,8 @@
*/
#define MC_CMD_VSWITCH_ALLOC 0x94
+#define MC_CMD_0x94_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_VSWITCH_ALLOC_IN msgrequest */
#define MC_CMD_VSWITCH_ALLOC_IN_LEN 16
/* The port to connect to the v-switch's upstream port. */
@@ -5572,6 +5845,8 @@
*/
#define MC_CMD_VSWITCH_FREE 0x95
+#define MC_CMD_0x95_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_VSWITCH_FREE_IN msgrequest */
#define MC_CMD_VSWITCH_FREE_IN_LEN 4
/* The port to which the v-switch is connected. */
@@ -5587,6 +5862,8 @@
*/
#define MC_CMD_VPORT_ALLOC 0x96
+#define MC_CMD_0x96_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_VPORT_ALLOC_IN msgrequest */
#define MC_CMD_VPORT_ALLOC_IN_LEN 20
/* The port to which the v-switch is connected. */
@@ -5636,6 +5913,8 @@
*/
#define MC_CMD_VPORT_FREE 0x97
+#define MC_CMD_0x97_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_VPORT_FREE_IN msgrequest */
#define MC_CMD_VPORT_FREE_IN_LEN 4
/* The handle of the v-port */
@@ -5651,8 +5930,10 @@
*/
#define MC_CMD_VADAPTOR_ALLOC 0x98
+#define MC_CMD_0x98_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_VADAPTOR_ALLOC_IN msgrequest */
-#define MC_CMD_VADAPTOR_ALLOC_IN_LEN 16
+#define MC_CMD_VADAPTOR_ALLOC_IN_LEN 30
/* The port to connect to the v-adaptor's port. */
#define MC_CMD_VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID_OFST 0
/* Flags controlling v-adaptor creation */
@@ -5661,6 +5942,19 @@
#define MC_CMD_VADAPTOR_ALLOC_IN_FLAG_AUTO_VADAPTOR_WIDTH 1
/* The number of VLAN tags to strip on receive */
#define MC_CMD_VADAPTOR_ALLOC_IN_NUM_VLANS_OFST 12
+/* The number of VLAN tags to transparently insert/remove. */
+#define MC_CMD_VADAPTOR_ALLOC_IN_NUM_VLAN_TAGS_OFST 16
+/* The actual VLAN tags to insert/remove */
+#define MC_CMD_VADAPTOR_ALLOC_IN_VLAN_TAGS_OFST 20
+#define MC_CMD_VADAPTOR_ALLOC_IN_VLAN_TAG_0_LBN 0
+#define MC_CMD_VADAPTOR_ALLOC_IN_VLAN_TAG_0_WIDTH 16
+#define MC_CMD_VADAPTOR_ALLOC_IN_VLAN_TAG_1_LBN 16
+#define MC_CMD_VADAPTOR_ALLOC_IN_VLAN_TAG_1_WIDTH 16
+/* The MAC address to assign to this v-adaptor */
+#define MC_CMD_VADAPTOR_ALLOC_IN_MACADDR_OFST 24
+#define MC_CMD_VADAPTOR_ALLOC_IN_MACADDR_LEN 6
+/* enum: Derive the MAC address from the upstream port */
+#define MC_CMD_VADAPTOR_ALLOC_IN_AUTO_MAC 0x0
/* MC_CMD_VADAPTOR_ALLOC_OUT msgresponse */
#define MC_CMD_VADAPTOR_ALLOC_OUT_LEN 0
@@ -5672,6 +5966,8 @@
*/
#define MC_CMD_VADAPTOR_FREE 0x99
+#define MC_CMD_0x99_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_VADAPTOR_FREE_IN msgrequest */
#define MC_CMD_VADAPTOR_FREE_IN_LEN 4
/* The port to which the v-adaptor is connected. */
@@ -5682,11 +5978,53 @@
/***********************************/
+/* MC_CMD_VADAPTOR_SET_MAC
+ * assign a new MAC address to a v-adaptor.
+ */
+#define MC_CMD_VADAPTOR_SET_MAC 0x5d
+
+#define MC_CMD_0x5d_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
+/* MC_CMD_VADAPTOR_SET_MAC_IN msgrequest */
+#define MC_CMD_VADAPTOR_SET_MAC_IN_LEN 10
+/* The port to which the v-adaptor is connected. */
+#define MC_CMD_VADAPTOR_SET_MAC_IN_UPSTREAM_PORT_ID_OFST 0
+/* The new MAC address to assign to this v-adaptor */
+#define MC_CMD_VADAPTOR_SET_MAC_IN_MACADDR_OFST 4
+#define MC_CMD_VADAPTOR_SET_MAC_IN_MACADDR_LEN 6
+
+/* MC_CMD_VADAPTOR_SET_MAC_OUT msgresponse */
+#define MC_CMD_VADAPTOR_SET_MAC_OUT_LEN 0
+
+
+/***********************************/
+/* MC_CMD_VADAPTOR_GET_MAC
+ * read the MAC address assigned to a v-adaptor.
+ */
+#define MC_CMD_VADAPTOR_GET_MAC 0x5e
+
+#define MC_CMD_0x5e_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
+/* MC_CMD_VADAPTOR_GET_MAC_IN msgrequest */
+#define MC_CMD_VADAPTOR_GET_MAC_IN_LEN 4
+/* The port to which the v-adaptor is connected. */
+#define MC_CMD_VADAPTOR_GET_MAC_IN_UPSTREAM_PORT_ID_OFST 0
+
+/* MC_CMD_VADAPTOR_GET_MAC_OUT msgresponse */
+#define MC_CMD_VADAPTOR_GET_MAC_OUT_LEN 6
+/* The MAC address assigned to this v-adaptor */
+#define MC_CMD_VADAPTOR_GET_MAC_OUT_MACADDR_OFST 0
+#define MC_CMD_VADAPTOR_GET_MAC_OUT_MACADDR_LEN 6
+
+
+/***********************************/
/* MC_CMD_EVB_PORT_ASSIGN
* assign a port to a PCI function.
*/
#define MC_CMD_EVB_PORT_ASSIGN 0x9a
+#define MC_CMD_0x9a_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_EVB_PORT_ASSIGN_IN msgrequest */
#define MC_CMD_EVB_PORT_ASSIGN_IN_LEN 8
/* The port to assign. */
@@ -5708,6 +6046,8 @@
*/
#define MC_CMD_RDWR_A64_REGIONS 0x9b
+#define MC_CMD_0x9b_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_RDWR_A64_REGIONS_IN msgrequest */
#define MC_CMD_RDWR_A64_REGIONS_IN_LEN 17
#define MC_CMD_RDWR_A64_REGIONS_IN_REGION0_OFST 0
@@ -5736,6 +6076,8 @@
*/
#define MC_CMD_ONLOAD_STACK_ALLOC 0x9c
+#define MC_CMD_0x9c_PRIVILEGE_CTG SRIOV_CTG_ONLOAD
+
/* MC_CMD_ONLOAD_STACK_ALLOC_IN msgrequest */
#define MC_CMD_ONLOAD_STACK_ALLOC_IN_LEN 4
/* The handle of the owning upstream port */
@@ -5753,6 +6095,8 @@
*/
#define MC_CMD_ONLOAD_STACK_FREE 0x9d
+#define MC_CMD_0x9d_PRIVILEGE_CTG SRIOV_CTG_ONLOAD
+
/* MC_CMD_ONLOAD_STACK_FREE_IN msgrequest */
#define MC_CMD_ONLOAD_STACK_FREE_IN_LEN 4
/* The handle of the Onload stack */
@@ -5768,6 +6112,8 @@
*/
#define MC_CMD_RSS_CONTEXT_ALLOC 0x9e
+#define MC_CMD_0x9e_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_RSS_CONTEXT_ALLOC_IN msgrequest */
#define MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN 12
/* The handle of the owning upstream port */
@@ -5800,6 +6146,8 @@
*/
#define MC_CMD_RSS_CONTEXT_FREE 0x9f
+#define MC_CMD_0x9f_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_RSS_CONTEXT_FREE_IN msgrequest */
#define MC_CMD_RSS_CONTEXT_FREE_IN_LEN 4
/* The handle of the RSS context */
@@ -5815,6 +6163,8 @@
*/
#define MC_CMD_RSS_CONTEXT_SET_KEY 0xa0
+#define MC_CMD_0xa0_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_RSS_CONTEXT_SET_KEY_IN msgrequest */
#define MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN 44
/* The handle of the RSS context */
@@ -5833,6 +6183,8 @@
*/
#define MC_CMD_RSS_CONTEXT_GET_KEY 0xa1
+#define MC_CMD_0xa1_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_RSS_CONTEXT_GET_KEY_IN msgrequest */
#define MC_CMD_RSS_CONTEXT_GET_KEY_IN_LEN 4
/* The handle of the RSS context */
@@ -5851,6 +6203,8 @@
*/
#define MC_CMD_RSS_CONTEXT_SET_TABLE 0xa2
+#define MC_CMD_0xa2_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_RSS_CONTEXT_SET_TABLE_IN msgrequest */
#define MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN 132
/* The handle of the RSS context */
@@ -5869,6 +6223,8 @@
*/
#define MC_CMD_RSS_CONTEXT_GET_TABLE 0xa3
+#define MC_CMD_0xa3_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_RSS_CONTEXT_GET_TABLE_IN msgrequest */
#define MC_CMD_RSS_CONTEXT_GET_TABLE_IN_LEN 4
/* The handle of the RSS context */
@@ -5887,6 +6243,8 @@
*/
#define MC_CMD_RSS_CONTEXT_SET_FLAGS 0xe1
+#define MC_CMD_0xe1_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_RSS_CONTEXT_SET_FLAGS_IN msgrequest */
#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN 8
/* The handle of the RSS context */
@@ -5912,6 +6270,8 @@
*/
#define MC_CMD_RSS_CONTEXT_GET_FLAGS 0xe2
+#define MC_CMD_0xe2_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_RSS_CONTEXT_GET_FLAGS_IN msgrequest */
#define MC_CMD_RSS_CONTEXT_GET_FLAGS_IN_LEN 4
/* The handle of the RSS context */
@@ -5937,6 +6297,8 @@
*/
#define MC_CMD_DOT1P_MAPPING_ALLOC 0xa4
+#define MC_CMD_0xa4_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_DOT1P_MAPPING_ALLOC_IN msgrequest */
#define MC_CMD_DOT1P_MAPPING_ALLOC_IN_LEN 8
/* The handle of the owning upstream port */
@@ -5959,6 +6321,8 @@
*/
#define MC_CMD_DOT1P_MAPPING_FREE 0xa5
+#define MC_CMD_0xa5_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_DOT1P_MAPPING_FREE_IN msgrequest */
#define MC_CMD_DOT1P_MAPPING_FREE_IN_LEN 4
/* The handle of the .1p mapping */
@@ -5974,6 +6338,8 @@
*/
#define MC_CMD_DOT1P_MAPPING_SET_TABLE 0xa6
+#define MC_CMD_0xa6_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_DOT1P_MAPPING_SET_TABLE_IN msgrequest */
#define MC_CMD_DOT1P_MAPPING_SET_TABLE_IN_LEN 36
/* The handle of the .1p mapping */
@@ -5994,6 +6360,8 @@
*/
#define MC_CMD_DOT1P_MAPPING_GET_TABLE 0xa7
+#define MC_CMD_0xa7_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_DOT1P_MAPPING_GET_TABLE_IN msgrequest */
#define MC_CMD_DOT1P_MAPPING_GET_TABLE_IN_LEN 4
/* The handle of the .1p mapping */
@@ -6014,6 +6382,8 @@
*/
#define MC_CMD_GET_VECTOR_CFG 0xbf
+#define MC_CMD_0xbf_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_VECTOR_CFG_IN msgrequest */
#define MC_CMD_GET_VECTOR_CFG_IN_LEN 0
@@ -6033,6 +6403,8 @@
*/
#define MC_CMD_SET_VECTOR_CFG 0xc0
+#define MC_CMD_0xc0_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_SET_VECTOR_CFG_IN msgrequest */
#define MC_CMD_SET_VECTOR_CFG_IN_LEN 12
/* Base absolute interrupt vector number, or MC_CMD_RESOURCE_INSTANCE_ANY to
@@ -6423,6 +6795,8 @@
*/
#define MC_CMD_VPORT_ADD_MAC_ADDRESS 0xa8
+#define MC_CMD_0xa8_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_VPORT_ADD_MAC_ADDRESS_IN msgrequest */
#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN 10
/* The handle of the v-port */
@@ -6441,6 +6815,8 @@
*/
#define MC_CMD_VPORT_DEL_MAC_ADDRESS 0xa9
+#define MC_CMD_0xa9_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_VPORT_DEL_MAC_ADDRESS_IN msgrequest */
#define MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN 10
/* The handle of the v-port */
@@ -6459,6 +6835,8 @@
*/
#define MC_CMD_VPORT_GET_MAC_ADDRESSES 0xaa
+#define MC_CMD_0xaa_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_VPORT_GET_MAC_ADDRESSES_IN msgrequest */
#define MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN 4
/* The handle of the v-port */
@@ -6486,6 +6864,8 @@
*/
#define MC_CMD_DUMP_BUFTBL_ENTRIES 0xab
+#define MC_CMD_0xab_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_DUMP_BUFTBL_ENTRIES_IN msgrequest */
#define MC_CMD_DUMP_BUFTBL_ENTRIES_IN_LEN 8
/* Index of the first buffer table entry. */
@@ -6510,6 +6890,8 @@
*/
#define MC_CMD_SET_RXDP_CONFIG 0xc1
+#define MC_CMD_0xc1_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_SET_RXDP_CONFIG_IN msgrequest */
#define MC_CMD_SET_RXDP_CONFIG_IN_LEN 4
#define MC_CMD_SET_RXDP_CONFIG_IN_DATA_OFST 0
@@ -6526,6 +6908,8 @@
*/
#define MC_CMD_GET_RXDP_CONFIG 0xc2
+#define MC_CMD_0xc2_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_GET_RXDP_CONFIG_IN msgrequest */
#define MC_CMD_GET_RXDP_CONFIG_IN_LEN 0
@@ -6890,6 +7274,8 @@
*/
#define MC_CMD_GET_CLOCK 0xac
+#define MC_CMD_0xac_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_CLOCK_IN msgrequest */
#define MC_CMD_GET_CLOCK_IN_LEN 0
@@ -6907,6 +7293,8 @@
*/
#define MC_CMD_SET_CLOCK 0xad
+#define MC_CMD_0xad_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_SET_CLOCK_IN msgrequest */
#define MC_CMD_SET_CLOCK_IN_LEN 12
/* Requested system frequency in MHz; 0 leaves unchanged. */
@@ -6932,6 +7320,8 @@
*/
#define MC_CMD_DPCPU_RPC 0xae
+#define MC_CMD_0xae_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_DPCPU_RPC_IN msgrequest */
#define MC_CMD_DPCPU_RPC_IN_LEN 36
#define MC_CMD_DPCPU_RPC_IN_CPU_OFST 0
@@ -7016,6 +7406,8 @@
*/
#define MC_CMD_TRIGGER_INTERRUPT 0xe3
+#define MC_CMD_0xe3_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_TRIGGER_INTERRUPT_IN msgrequest */
#define MC_CMD_TRIGGER_INTERRUPT_IN_LEN 4
/* Interrupt level relative to base for function. */
@@ -7031,6 +7423,8 @@
*/
#define MC_CMD_CAP_BLK_READ 0xe7
+#define MC_CMD_0xe7_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_CAP_BLK_READ_IN msgrequest */
#define MC_CMD_CAP_BLK_READ_IN_LEN 12
#define MC_CMD_CAP_BLK_READ_IN_CAP_REG_OFST 0
@@ -7055,6 +7449,8 @@
*/
#define MC_CMD_DUMP_DO 0xe8
+#define MC_CMD_0xe8_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_DUMP_DO_IN msgrequest */
#define MC_CMD_DUMP_DO_IN_LEN 52
#define MC_CMD_DUMP_DO_IN_PADDING_OFST 0
@@ -7108,6 +7504,8 @@
*/
#define MC_CMD_DUMP_CONFIGURE_UNSOLICITED 0xe9
+#define MC_CMD_0xe9_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_DUMP_CONFIGURE_UNSOLICITED_IN msgrequest */
#define MC_CMD_DUMP_CONFIGURE_UNSOLICITED_IN_LEN 52
#define MC_CMD_DUMP_CONFIGURE_UNSOLICITED_IN_ENABLE_OFST 0
@@ -7151,6 +7549,8 @@
*/
#define MC_CMD_SET_PSU 0xea
+#define MC_CMD_0xea_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_SET_PSU_IN msgrequest */
#define MC_CMD_SET_PSU_IN_LEN 12
#define MC_CMD_SET_PSU_IN_PARAM_OFST 0
@@ -7171,6 +7571,8 @@
*/
#define MC_CMD_GET_FUNCTION_INFO 0xec
+#define MC_CMD_0xec_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_FUNCTION_INFO_IN msgrequest */
#define MC_CMD_GET_FUNCTION_INFO_IN_LEN 0
@@ -7188,6 +7590,8 @@
*/
#define MC_CMD_ENABLE_OFFLINE_BIST 0xed
+#define MC_CMD_0xed_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_ENABLE_OFFLINE_BIST_IN msgrequest */
#define MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN 0
@@ -7203,6 +7607,8 @@
*/
#define MC_CMD_UART_SEND_DATA 0xee
+#define MC_CMD_0xee_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_UART_SEND_DATA_OUT msgrequest */
#define MC_CMD_UART_SEND_DATA_OUT_LENMIN 16
#define MC_CMD_UART_SEND_DATA_OUT_LENMAX 252
@@ -7231,6 +7637,8 @@
*/
#define MC_CMD_UART_RECV_DATA 0xef
+#define MC_CMD_0xef_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_UART_RECV_DATA_OUT msgrequest */
#define MC_CMD_UART_RECV_DATA_OUT_LEN 16
/* CRC32 over OFFSET, LENGTH, RESERVED */
@@ -7266,6 +7674,8 @@
*/
#define MC_CMD_READ_FUSES 0xf0
+#define MC_CMD_0xf0_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_READ_FUSES_IN msgrequest */
#define MC_CMD_READ_FUSES_IN_LEN 8
/* Offset in OTP to read */
@@ -7292,6 +7702,8 @@
*/
#define MC_CMD_KR_TUNE 0xf1
+#define MC_CMD_0xf1_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_KR_TUNE_IN msgrequest */
#define MC_CMD_KR_TUNE_IN_LENMIN 4
#define MC_CMD_KR_TUNE_IN_LENMAX 252
@@ -7550,6 +7962,8 @@
*/
#define MC_CMD_PCIE_TUNE 0xf2
+#define MC_CMD_0xf2_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_PCIE_TUNE_IN msgrequest */
#define MC_CMD_PCIE_TUNE_IN_LENMIN 4
#define MC_CMD_PCIE_TUNE_IN_LENMAX 252
@@ -7711,6 +8125,8 @@
*/
#define MC_CMD_LICENSING 0xf3
+#define MC_CMD_0xf3_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_LICENSING_IN msgrequest */
#define MC_CMD_LICENSING_IN_LEN 4
/* identifies the type of operation requested */
@@ -7756,6 +8172,8 @@
*/
#define MC_CMD_MC2MC_PROXY 0xf4
+#define MC_CMD_0xf4_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_MC2MC_PROXY_IN msgrequest */
#define MC_CMD_MC2MC_PROXY_IN_LEN 0
@@ -7771,6 +8189,8 @@
*/
#define MC_CMD_GET_LICENSED_APP_STATE 0xf5
+#define MC_CMD_0xf5_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_GET_LICENSED_APP_STATE_IN msgrequest */
#define MC_CMD_GET_LICENSED_APP_STATE_IN_LEN 4
/* application ID to query (LICENSED_APP_ID_xxx) */
@@ -7792,6 +8212,8 @@
*/
#define MC_CMD_LICENSED_APP_OP 0xf6
+#define MC_CMD_0xf6_PRIVILEGE_CTG SRIOV_CTG_GENERAL
+
/* MC_CMD_LICENSED_APP_OP_IN msgrequest */
#define MC_CMD_LICENSED_APP_OP_IN_LENMIN 8
#define MC_CMD_LICENSED_APP_OP_IN_LENMAX 252
@@ -7847,6 +8269,8 @@
*/
#define MC_CMD_SET_PORT_SNIFF_CONFIG 0xf7
+#define MC_CMD_0xf7_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_SET_PORT_SNIFF_CONFIG_IN msgrequest */
#define MC_CMD_SET_PORT_SNIFF_CONFIG_IN_LEN 16
/* configuration flags */
@@ -7881,6 +8305,8 @@
*/
#define MC_CMD_GET_PORT_SNIFF_CONFIG 0xf8
+#define MC_CMD_0xf8_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
/* MC_CMD_GET_PORT_SNIFF_CONFIG_IN msgrequest */
#define MC_CMD_GET_PORT_SNIFF_CONFIG_IN_LEN 0
diff --git a/drivers/net/ethernet/sfc/mcdi_port.c b/drivers/net/ethernet/sfc/mcdi_port.c
index fb19b70eac01..7f295c4d7b80 100644
--- a/drivers/net/ethernet/sfc/mcdi_port.c
+++ b/drivers/net/ethernet/sfc/mcdi_port.c
@@ -865,6 +865,7 @@ int efx_mcdi_set_mac(struct efx_nic *efx)
BUILD_BUG_ON(MC_CMD_SET_MAC_OUT_LEN != 0);
+ /* This has no effect on EF10 */
ether_addr_copy(MCDI_PTR(cmdbytes, SET_MAC_IN_ADDR),
efx->net_dev->dev_addr);
@@ -923,6 +924,7 @@ enum efx_stats_action {
static int efx_mcdi_mac_stats(struct efx_nic *efx,
enum efx_stats_action action, int clear)
{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
MCDI_DECLARE_BUF(inbuf, MC_CMD_MAC_STATS_IN_LEN);
int rc;
int change = action == EFX_STATS_PULL ? 0 : 1;
@@ -944,9 +946,14 @@ static int efx_mcdi_mac_stats(struct efx_nic *efx,
MAC_STATS_IN_PERIODIC_NOEVENT, 1,
MAC_STATS_IN_PERIOD_MS, period);
MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_LEN, dma_len);
-
- rc = efx_mcdi_rpc(efx, MC_CMD_MAC_STATS, inbuf, sizeof(inbuf),
- NULL, 0, NULL);
+ MCDI_SET_DWORD(inbuf, MAC_STATS_IN_PORT_ID, nic_data->vport_id);
+
+ rc = efx_mcdi_rpc_quiet(efx, MC_CMD_MAC_STATS, inbuf, sizeof(inbuf),
+ NULL, 0, NULL);
+ /* Expect ENOENT if DMA queues have not been set up */
+ if (rc && (rc != -ENOENT || atomic_read(&efx->active_queues)))
+ efx_mcdi_display_error(efx, MC_CMD_MAC_STATS, sizeof(inbuf),
+ NULL, 0, rc);
return rc;
}
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index 325dd94bca46..d72f522bf9c3 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -25,6 +25,7 @@
#include <linux/highmem.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
+#include <linux/rwsem.h>
#include <linux/vmalloc.h>
#include <linux/i2c.h>
#include <linux/mtd/mtd.h>
@@ -793,7 +794,6 @@ union efx_multicast_hash {
efx_oword_t oword[EFX_MCAST_HASH_ENTRIES / sizeof(efx_oword_t) / 8];
};
-struct efx_vf;
struct vfdi_status;
/**
@@ -897,7 +897,8 @@ struct vfdi_status;
* @loopback_mode: Loopback status
* @loopback_modes: Supported loopback mode bitmask
* @loopback_selftest: Offline self-test private state
- * @filter_lock: Filter table lock
+ * @filter_sem: Filter table rw_semaphore, for freeing the table
+ * @filter_lock: Filter table lock, for mere content changes
* @filter_state: Architecture-dependent filter table state
* @rps_flow_id: Flow IDs of filters allocated for accelerated RFS,
* indexed by filter ID
@@ -909,7 +910,6 @@ struct vfdi_status;
* completed (either success or failure). Not used when MCDI is used to
* flush receive queues.
* @flush_wq: wait queue used by efx_nic_flush_queues() to wait for flush completions.
- * @vf: Array of &struct efx_vf objects.
* @vf_count: Number of VFs intended to be enabled.
* @vf_init_count: Number of VFs that have been fully initialised.
* @vi_scale: log2 number of vnics per VF.
@@ -1040,6 +1040,7 @@ struct efx_nic {
void *loopback_selftest;
+ struct rw_semaphore filter_sem;
spinlock_t filter_lock;
void *filter_state;
#ifdef CONFIG_RFS_ACCEL
@@ -1053,7 +1054,6 @@ struct efx_nic {
wait_queue_head_t flush_wq;
#ifdef CONFIG_SFC_SRIOV
- struct efx_vf *vf;
unsigned vf_count;
unsigned vf_init_count;
unsigned vi_scale;
@@ -1092,6 +1092,7 @@ struct efx_mtd_partition {
/**
* struct efx_nic_type - Efx device type definition
+ * @mem_bar: Get the memory BAR
* @mem_map_size: Get memory BAR mapped size
* @probe: Probe the controller
* @remove: Free resources allocated by probe()
@@ -1204,6 +1205,7 @@ struct efx_mtd_partition {
* @ptp_set_ts_config: Set hardware timestamp configuration. The flags
* and tx_type will already have been validated but this operation
* must validate and update rx_filter.
+ * @set_mac_address: Set the MAC address of the device
* @revision: Hardware architecture revision
* @txd_ptr_tbl_base: TX descriptor ring base address
* @rxd_ptr_tbl_base: RX descriptor ring base address
@@ -1226,6 +1228,8 @@ struct efx_mtd_partition {
* @hwtstamp_filters: Mask of hardware timestamp filter types supported
*/
struct efx_nic_type {
+ bool is_vf;
+ unsigned int mem_bar;
unsigned int (*mem_map_size)(struct efx_nic *efx);
int (*probe)(struct efx_nic *efx);
void (*remove)(struct efx_nic *efx);
@@ -1277,7 +1281,8 @@ struct efx_nic_type {
void (*tx_init)(struct efx_tx_queue *tx_queue);
void (*tx_remove)(struct efx_tx_queue *tx_queue);
void (*tx_write)(struct efx_tx_queue *tx_queue);
- void (*rx_push_rss_config)(struct efx_nic *efx);
+ int (*rx_push_rss_config)(struct efx_nic *efx, bool user,
+ const u32 *rx_indir_table);
int (*rx_probe)(struct efx_rx_queue *rx_queue);
void (*rx_init)(struct efx_rx_queue *rx_queue);
void (*rx_remove)(struct efx_rx_queue *rx_queue);
@@ -1330,11 +1335,28 @@ struct efx_nic_type {
int (*ptp_set_ts_sync_events)(struct efx_nic *efx, bool en, bool temp);
int (*ptp_set_ts_config)(struct efx_nic *efx,
struct hwtstamp_config *init);
+ int (*sriov_configure)(struct efx_nic *efx, int num_vfs);
int (*sriov_init)(struct efx_nic *efx);
void (*sriov_fini)(struct efx_nic *efx);
- void (*sriov_mac_address_changed)(struct efx_nic *efx);
bool (*sriov_wanted)(struct efx_nic *efx);
void (*sriov_reset)(struct efx_nic *efx);
+ void (*sriov_flr)(struct efx_nic *efx, unsigned vf_i);
+ int (*sriov_set_vf_mac)(struct efx_nic *efx, int vf_i, u8 *mac);
+ int (*sriov_set_vf_vlan)(struct efx_nic *efx, int vf_i, u16 vlan,
+ u8 qos);
+ int (*sriov_set_vf_spoofchk)(struct efx_nic *efx, int vf_i,
+ bool spoofchk);
+ int (*sriov_get_vf_config)(struct efx_nic *efx, int vf_i,
+ struct ifla_vf_info *ivi);
+ int (*sriov_set_vf_link_state)(struct efx_nic *efx, int vf_i,
+ int link_state);
+ int (*sriov_get_phys_port_id)(struct efx_nic *efx,
+ struct netdev_phys_item_id *ppid);
+ int (*vswitching_probe)(struct efx_nic *efx);
+ int (*vswitching_restore)(struct efx_nic *efx);
+ void (*vswitching_remove)(struct efx_nic *efx);
+ int (*get_mac_address)(struct efx_nic *efx, unsigned char *perm_addr);
+ int (*set_mac_address)(struct efx_nic *efx);
int revision;
unsigned int txd_ptr_tbl_base;
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h
index 93d10cbbd1cf..31ff9084d9a4 100644
--- a/drivers/net/ethernet/sfc/nic.h
+++ b/drivers/net/ethernet/sfc/nic.h
@@ -381,6 +381,7 @@ enum {
* @efx: Pointer back to main interface structure
* @wol_filter_id: Wake-on-LAN packet filter id
* @stats: Hardware statistics
+ * @vf: Array of &struct siena_vf objects
* @vf_buftbl_base: The zeroth buffer table index used to back VF queues.
* @vfdi_status: Common VFDI status page to be dmad to VF address space.
* @local_addr_list: List of local addresses. Protected by %local_lock.
@@ -394,6 +395,7 @@ struct siena_nic_data {
int wol_filter_id;
u64 stats[SIENA_STAT_COUNT];
#ifdef CONFIG_SFC_SRIOV
+ struct siena_vf *vf;
struct efx_channel *vfdi_channel;
unsigned vf_buftbl_base;
struct efx_buffer vfdi_status;
@@ -405,59 +407,77 @@ struct siena_nic_data {
};
enum {
- EF10_STAT_tx_bytes = GENERIC_STAT_COUNT,
- EF10_STAT_tx_packets,
- EF10_STAT_tx_pause,
- EF10_STAT_tx_control,
- EF10_STAT_tx_unicast,
- EF10_STAT_tx_multicast,
- EF10_STAT_tx_broadcast,
- EF10_STAT_tx_lt64,
- EF10_STAT_tx_64,
- EF10_STAT_tx_65_to_127,
- EF10_STAT_tx_128_to_255,
- EF10_STAT_tx_256_to_511,
- EF10_STAT_tx_512_to_1023,
- EF10_STAT_tx_1024_to_15xx,
- EF10_STAT_tx_15xx_to_jumbo,
- EF10_STAT_rx_bytes,
- EF10_STAT_rx_bytes_minus_good_bytes,
- EF10_STAT_rx_good_bytes,
- EF10_STAT_rx_bad_bytes,
- EF10_STAT_rx_packets,
- EF10_STAT_rx_good,
- EF10_STAT_rx_bad,
- EF10_STAT_rx_pause,
- EF10_STAT_rx_control,
+ EF10_STAT_port_tx_bytes = GENERIC_STAT_COUNT,
+ EF10_STAT_port_tx_packets,
+ EF10_STAT_port_tx_pause,
+ EF10_STAT_port_tx_control,
+ EF10_STAT_port_tx_unicast,
+ EF10_STAT_port_tx_multicast,
+ EF10_STAT_port_tx_broadcast,
+ EF10_STAT_port_tx_lt64,
+ EF10_STAT_port_tx_64,
+ EF10_STAT_port_tx_65_to_127,
+ EF10_STAT_port_tx_128_to_255,
+ EF10_STAT_port_tx_256_to_511,
+ EF10_STAT_port_tx_512_to_1023,
+ EF10_STAT_port_tx_1024_to_15xx,
+ EF10_STAT_port_tx_15xx_to_jumbo,
+ EF10_STAT_port_rx_bytes,
+ EF10_STAT_port_rx_bytes_minus_good_bytes,
+ EF10_STAT_port_rx_good_bytes,
+ EF10_STAT_port_rx_bad_bytes,
+ EF10_STAT_port_rx_packets,
+ EF10_STAT_port_rx_good,
+ EF10_STAT_port_rx_bad,
+ EF10_STAT_port_rx_pause,
+ EF10_STAT_port_rx_control,
+ EF10_STAT_port_rx_unicast,
+ EF10_STAT_port_rx_multicast,
+ EF10_STAT_port_rx_broadcast,
+ EF10_STAT_port_rx_lt64,
+ EF10_STAT_port_rx_64,
+ EF10_STAT_port_rx_65_to_127,
+ EF10_STAT_port_rx_128_to_255,
+ EF10_STAT_port_rx_256_to_511,
+ EF10_STAT_port_rx_512_to_1023,
+ EF10_STAT_port_rx_1024_to_15xx,
+ EF10_STAT_port_rx_15xx_to_jumbo,
+ EF10_STAT_port_rx_gtjumbo,
+ EF10_STAT_port_rx_bad_gtjumbo,
+ EF10_STAT_port_rx_overflow,
+ EF10_STAT_port_rx_align_error,
+ EF10_STAT_port_rx_length_error,
+ EF10_STAT_port_rx_nodesc_drops,
+ EF10_STAT_port_rx_pm_trunc_bb_overflow,
+ EF10_STAT_port_rx_pm_discard_bb_overflow,
+ EF10_STAT_port_rx_pm_trunc_vfifo_full,
+ EF10_STAT_port_rx_pm_discard_vfifo_full,
+ EF10_STAT_port_rx_pm_trunc_qbb,
+ EF10_STAT_port_rx_pm_discard_qbb,
+ EF10_STAT_port_rx_pm_discard_mapping,
+ EF10_STAT_port_rx_dp_q_disabled_packets,
+ EF10_STAT_port_rx_dp_di_dropped_packets,
+ EF10_STAT_port_rx_dp_streaming_packets,
+ EF10_STAT_port_rx_dp_hlb_fetch,
+ EF10_STAT_port_rx_dp_hlb_wait,
EF10_STAT_rx_unicast,
+ EF10_STAT_rx_unicast_bytes,
EF10_STAT_rx_multicast,
+ EF10_STAT_rx_multicast_bytes,
EF10_STAT_rx_broadcast,
- EF10_STAT_rx_lt64,
- EF10_STAT_rx_64,
- EF10_STAT_rx_65_to_127,
- EF10_STAT_rx_128_to_255,
- EF10_STAT_rx_256_to_511,
- EF10_STAT_rx_512_to_1023,
- EF10_STAT_rx_1024_to_15xx,
- EF10_STAT_rx_15xx_to_jumbo,
- EF10_STAT_rx_gtjumbo,
- EF10_STAT_rx_bad_gtjumbo,
+ EF10_STAT_rx_broadcast_bytes,
+ EF10_STAT_rx_bad,
+ EF10_STAT_rx_bad_bytes,
EF10_STAT_rx_overflow,
- EF10_STAT_rx_align_error,
- EF10_STAT_rx_length_error,
- EF10_STAT_rx_nodesc_drops,
- EF10_STAT_rx_pm_trunc_bb_overflow,
- EF10_STAT_rx_pm_discard_bb_overflow,
- EF10_STAT_rx_pm_trunc_vfifo_full,
- EF10_STAT_rx_pm_discard_vfifo_full,
- EF10_STAT_rx_pm_trunc_qbb,
- EF10_STAT_rx_pm_discard_qbb,
- EF10_STAT_rx_pm_discard_mapping,
- EF10_STAT_rx_dp_q_disabled_packets,
- EF10_STAT_rx_dp_di_dropped_packets,
- EF10_STAT_rx_dp_streaming_packets,
- EF10_STAT_rx_dp_hlb_fetch,
- EF10_STAT_rx_dp_hlb_wait,
+ EF10_STAT_tx_unicast,
+ EF10_STAT_tx_unicast_bytes,
+ EF10_STAT_tx_multicast,
+ EF10_STAT_tx_multicast_bytes,
+ EF10_STAT_tx_broadcast,
+ EF10_STAT_tx_broadcast_bytes,
+ EF10_STAT_tx_bad,
+ EF10_STAT_tx_bad_bytes,
+ EF10_STAT_tx_overflow,
EF10_STAT_COUNT
};
@@ -483,12 +503,21 @@ enum {
* @must_restore_piobufs: Flag: PIO buffers have yet to be restored after MC
* reboot
* @rx_rss_context: Firmware handle for our RSS context
+ * @rx_rss_context_exclusive: Whether our RSS context is exclusive or shared
* @stats: Hardware statistics
* @workaround_35388: Flag: firmware supports workaround for bug 35388
* @must_check_datapath_caps: Flag: @datapath_caps needs to be revalidated
* after MC reboot
* @datapath_caps: Capabilities of datapath firmware (FLAGS1 field of
* %MC_CMD_GET_CAPABILITIES response)
+ * @rx_dpcpu_fw_id: Firmware ID of the RxDPCPU
+ * @tx_dpcpu_fw_id: Firmware ID of the TxDPCPU
+ * @vport_id: The function's vport ID, only relevant for PFs
+ * @must_probe_vswitching: Flag: vswitching has yet to be setup after MC reboot
+ * @pf_index: The number for this PF, or the parent PF if this is a VF
+#ifdef CONFIG_SFC_SRIOV
+ * @vf: Pointer to VF data structure
+#endif
*/
struct efx_ef10_nic_data {
struct efx_buffer mcdi_buf;
@@ -503,126 +532,27 @@ struct efx_ef10_nic_data {
unsigned int piobuf_handle[EF10_TX_PIOBUF_COUNT];
bool must_restore_piobufs;
u32 rx_rss_context;
+ bool rx_rss_context_exclusive;
u64 stats[EF10_STAT_COUNT];
bool workaround_35388;
bool must_check_datapath_caps;
u32 datapath_caps;
-};
-
-/*
- * On the SFC9000 family each port is associated with 1 PCI physical
- * function (PF) handled by sfc and a configurable number of virtual
- * functions (VFs) that may be handled by some other driver, often in
- * a VM guest. The queue pointer registers are mapped in both PF and
- * VF BARs such that an 8K region provides access to a single RX, TX
- * and event queue (collectively a Virtual Interface, VI or VNIC).
- *
- * The PF has access to all 1024 VIs while VFs are mapped to VIs
- * according to VI_BASE and VI_SCALE: VF i has access to VIs numbered
- * in range [VI_BASE + i << VI_SCALE, VI_BASE + i + 1 << VI_SCALE).
- * The number of VIs and the VI_SCALE value are configurable but must
- * be established at boot time by firmware.
- */
-
-/* Maximum VI_SCALE parameter supported by Siena */
-#define EFX_VI_SCALE_MAX 6
-/* Base VI to use for SR-IOV. Must be aligned to (1 << EFX_VI_SCALE_MAX),
- * so this is the smallest allowed value. */
-#define EFX_VI_BASE 128U
-/* Maximum number of VFs allowed */
-#define EFX_VF_COUNT_MAX 127
-/* Limit EVQs on VFs to be only 8k to reduce buffer table reservation */
-#define EFX_MAX_VF_EVQ_SIZE 8192UL
-/* The number of buffer table entries reserved for each VI on a VF */
-#define EFX_VF_BUFTBL_PER_VI \
- ((EFX_MAX_VF_EVQ_SIZE + 2 * EFX_MAX_DMAQ_SIZE) * \
- sizeof(efx_qword_t) / EFX_BUF_SIZE)
-
+ unsigned int rx_dpcpu_fw_id;
+ unsigned int tx_dpcpu_fw_id;
+ unsigned int vport_id;
+ bool must_probe_vswitching;
+ unsigned int pf_index;
+ u8 port_id[ETH_ALEN];
#ifdef CONFIG_SFC_SRIOV
-
-/* SIENA */
-static inline bool efx_siena_sriov_wanted(struct efx_nic *efx)
-{
- return efx->vf_count != 0;
-}
-
-static inline bool efx_siena_sriov_enabled(struct efx_nic *efx)
-{
- return efx->vf_init_count != 0;
-}
-
-static inline unsigned int efx_vf_size(struct efx_nic *efx)
-{
- return 1 << efx->vi_scale;
-}
+ unsigned int vf_index;
+ struct ef10_vf *vf;
+#endif
+ u8 vport_mac[ETH_ALEN];
+};
int efx_init_sriov(void);
-void efx_siena_sriov_probe(struct efx_nic *efx);
-int efx_siena_sriov_init(struct efx_nic *efx);
-void efx_siena_sriov_mac_address_changed(struct efx_nic *efx);
-void efx_siena_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event);
-void efx_siena_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event);
-void efx_siena_sriov_event(struct efx_channel *channel, efx_qword_t *event);
-void efx_siena_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq);
-void efx_siena_sriov_flr(struct efx_nic *efx, unsigned flr);
-void efx_siena_sriov_reset(struct efx_nic *efx);
-void efx_siena_sriov_fini(struct efx_nic *efx);
void efx_fini_sriov(void);
-/* EF10 */
-static inline bool efx_ef10_sriov_wanted(struct efx_nic *efx) { return false; }
-static inline int efx_ef10_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; }
-static inline void efx_ef10_sriov_mac_address_changed(struct efx_nic *efx) {}
-static inline void efx_ef10_sriov_reset(struct efx_nic *efx) {}
-static inline void efx_ef10_sriov_fini(struct efx_nic *efx) {}
-
-#else
-
-/* SIENA */
-static inline bool efx_siena_sriov_wanted(struct efx_nic *efx) { return false; }
-static inline bool efx_siena_sriov_enabled(struct efx_nic *efx) { return false; }
-static inline unsigned int efx_vf_size(struct efx_nic *efx) { return 0; }
-static inline int efx_init_sriov(void) { return 0; }
-static inline void efx_siena_sriov_probe(struct efx_nic *efx) {}
-static inline int efx_siena_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; }
-static inline void efx_siena_sriov_mac_address_changed(struct efx_nic *efx) {}
-static inline void efx_siena_sriov_tx_flush_done(struct efx_nic *efx,
- efx_qword_t *event) {}
-static inline void efx_siena_sriov_rx_flush_done(struct efx_nic *efx,
- efx_qword_t *event) {}
-static inline void efx_siena_sriov_event(struct efx_channel *channel,
- efx_qword_t *event) {}
-static inline void efx_siena_sriov_desc_fetch_err(struct efx_nic *efx,
- unsigned dmaq) {}
-static inline void efx_siena_sriov_flr(struct efx_nic *efx, unsigned flr) {}
-static inline void efx_siena_sriov_reset(struct efx_nic *efx) {}
-static inline void efx_siena_sriov_fini(struct efx_nic *efx) {}
-static inline void efx_fini_sriov(void) {}
-
-/* EF10 */
-static inline bool efx_ef10_sriov_wanted(struct efx_nic *efx) { return false; }
-static inline int efx_ef10_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; }
-static inline void efx_ef10_sriov_mac_address_changed(struct efx_nic *efx) {}
-static inline void efx_ef10_sriov_reset(struct efx_nic *efx) {}
-static inline void efx_ef10_sriov_fini(struct efx_nic *efx) {}
-
-#endif
-
-/* FALCON */
-static inline bool efx_falcon_sriov_wanted(struct efx_nic *efx) { return false; }
-static inline int efx_falcon_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; }
-static inline void efx_falcon_sriov_mac_address_changed(struct efx_nic *efx) {}
-static inline void efx_falcon_sriov_reset(struct efx_nic *efx) {}
-static inline void efx_falcon_sriov_fini(struct efx_nic *efx) {}
-
-int efx_siena_sriov_set_vf_mac(struct net_device *dev, int vf, u8 *mac);
-int efx_siena_sriov_set_vf_vlan(struct net_device *dev, int vf,
- u16 vlan, u8 qos);
-int efx_siena_sriov_get_vf_config(struct net_device *dev, int vf,
- struct ifla_vf_info *ivf);
-int efx_siena_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf,
- bool spoofchk);
-
struct ethtool_ts_info;
int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel);
void efx_ptp_defer_probe_with_channel(struct efx_nic *efx);
@@ -654,6 +584,7 @@ extern const struct efx_nic_type falcon_a1_nic_type;
extern const struct efx_nic_type falcon_b0_nic_type;
extern const struct efx_nic_type siena_a0_nic_type;
extern const struct efx_nic_type efx_hunt_a0_nic_type;
+extern const struct efx_nic_type efx_hunt_a0_vf_nic_type;
/**************************************************************************
*
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c
index a2e9aee05cdd..ad62615a93dc 100644
--- a/drivers/net/ethernet/sfc/ptp.c
+++ b/drivers/net/ethernet/sfc/ptp.c
@@ -306,7 +306,7 @@ struct efx_ptp_data {
struct work_struct pps_work;
struct workqueue_struct *pps_workwq;
bool nic_ts_enabled;
- MCDI_DECLARE_BUF(txbuf, MC_CMD_PTP_IN_TRANSMIT_LENMAX);
+ _MCDI_DECLARE_BUF(txbuf, MC_CMD_PTP_IN_TRANSMIT_LENMAX);
unsigned int good_syncs;
unsigned int fast_syncs;
@@ -389,11 +389,8 @@ size_t efx_ptp_update_stats(struct efx_nic *efx, u64 *stats)
MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0);
rc = efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), NULL);
- if (rc) {
- netif_err(efx, hw, efx->net_dev,
- "MC_CMD_PTP_OP_STATUS failed (%d)\n", rc);
+ if (rc)
memset(outbuf, 0, sizeof(outbuf));
- }
efx_nic_update_stats(efx_ptp_stat_desc, PTP_STAT_COUNT,
efx_ptp_stat_mask,
stats, _MCDI_PTR(outbuf, 0), false);
@@ -490,14 +487,20 @@ static int efx_ptp_get_attributes(struct efx_nic *efx)
*/
MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_GET_ATTRIBUTES);
MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0);
- rc = efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
- outbuf, sizeof(outbuf), &out_len);
- if (rc == 0)
+ rc = efx_mcdi_rpc_quiet(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
+ outbuf, sizeof(outbuf), &out_len);
+ if (rc == 0) {
fmt = MCDI_DWORD(outbuf, PTP_OUT_GET_ATTRIBUTES_TIME_FORMAT);
- else if (rc == -EINVAL)
+ } else if (rc == -EINVAL) {
fmt = MC_CMD_PTP_OUT_GET_ATTRIBUTES_SECONDS_NANOSECONDS;
- else
+ } else if (rc == -EPERM) {
+ netif_info(efx, probe, efx->net_dev, "no PTP support\n");
+ return rc;
+ } else {
+ efx_mcdi_display_error(efx, MC_CMD_PTP, sizeof(inbuf),
+ outbuf, sizeof(outbuf), rc);
return rc;
+ }
if (fmt == MC_CMD_PTP_OUT_GET_ATTRIBUTES_SECONDS_27FRACTION) {
ptp->ns_to_nic_time = efx_ptp_ns_to_s27;
@@ -541,8 +544,8 @@ static int efx_ptp_get_timestamp_corrections(struct efx_nic *efx)
MC_CMD_PTP_OP_GET_TIMESTAMP_CORRECTIONS);
MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0);
- rc = efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
- outbuf, sizeof(outbuf), NULL);
+ rc = efx_mcdi_rpc_quiet(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
+ outbuf, sizeof(outbuf), NULL);
if (rc == 0) {
efx->ptp_data->ts_corrections.tx = MCDI_DWORD(outbuf,
PTP_OUT_GET_TIMESTAMP_CORRECTIONS_TRANSMIT);
@@ -558,6 +561,8 @@ static int efx_ptp_get_timestamp_corrections(struct efx_nic *efx)
efx->ptp_data->ts_corrections.pps_out = 0;
efx->ptp_data->ts_corrections.pps_in = 0;
} else {
+ efx_mcdi_display_error(efx, MC_CMD_PTP, sizeof(inbuf), outbuf,
+ sizeof(outbuf), rc);
return rc;
}
@@ -568,7 +573,7 @@ static int efx_ptp_get_timestamp_corrections(struct efx_nic *efx)
static int efx_ptp_enable(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_ENABLE_LEN);
- MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, 0);
+ MCDI_DECLARE_BUF_ERR(outbuf);
int rc;
MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_ENABLE);
@@ -596,7 +601,7 @@ static int efx_ptp_enable(struct efx_nic *efx)
static int efx_ptp_disable(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_DISABLE_LEN);
- MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, 0);
+ MCDI_DECLARE_BUF_ERR(outbuf);
int rc;
MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_DISABLE);
@@ -604,7 +609,12 @@ static int efx_ptp_disable(struct efx_nic *efx)
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), NULL);
rc = (rc == -EALREADY) ? 0 : rc;
- if (rc)
+ /* If we get ENOSYS, the NIC doesn't support PTP, and thus this function
+ * should only have been called during probe.
+ */
+ if (rc == -ENOSYS || rc == -EPERM)
+ netif_info(efx, probe, efx->net_dev, "no PTP support\n");
+ else if (rc)
efx_mcdi_display_error(efx, MC_CMD_PTP,
MC_CMD_PTP_IN_DISABLE_LEN,
outbuf, sizeof(outbuf), rc);
diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c
index f12c811938d2..b323b9167526 100644
--- a/drivers/net/ethernet/sfc/siena.c
+++ b/drivers/net/ethernet/sfc/siena.c
@@ -25,6 +25,7 @@
#include "mcdi.h"
#include "mcdi_pcol.h"
#include "selftest.h"
+#include "siena_sriov.h"
/* Hardware control for SFC9000 family including SFL9021 (aka Siena). */
@@ -306,7 +307,9 @@ static int siena_probe_nic(struct efx_nic *efx)
if (rc)
goto fail5;
+#ifdef CONFIG_SFC_SRIOV
efx_siena_sriov_probe(efx);
+#endif
efx_ptp_defer_probe_with_channel(efx);
return 0;
@@ -321,7 +324,8 @@ fail1:
return rc;
}
-static void siena_rx_push_rss_config(struct efx_nic *efx)
+static int siena_rx_push_rss_config(struct efx_nic *efx, bool user,
+ const u32 *rx_indir_table)
{
efx_oword_t temp;
@@ -343,7 +347,11 @@ static void siena_rx_push_rss_config(struct efx_nic *efx)
FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8);
efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG3);
+ memcpy(efx->rx_indir_table, rx_indir_table,
+ sizeof(efx->rx_indir_table));
efx_farch_rx_push_indir_table(efx);
+
+ return 0;
}
/* This call performs hardware-specific global initialisation, such as
@@ -386,7 +394,7 @@ static int siena_init_nic(struct efx_nic *efx)
EFX_RX_USR_BUF_SIZE >> 5);
efx_writeo(efx, &temp, FR_AZ_RX_CFG);
- siena_rx_push_rss_config(efx);
+ siena_rx_push_rss_config(efx, false, efx->rx_indir_table);
/* Enable event logging */
rc = efx_mcdi_log_ctrl(efx, true, false, 0);
@@ -909,6 +917,8 @@ fail:
*/
const struct efx_nic_type siena_a0_nic_type = {
+ .is_vf = false,
+ .mem_bar = EFX_MEM_BAR,
.mem_map_size = siena_mem_map_size,
.probe = siena_probe_nic,
.remove = siena_remove_nic,
@@ -996,11 +1006,22 @@ const struct efx_nic_type siena_a0_nic_type = {
#endif
.ptp_write_host_time = siena_ptp_write_host_time,
.ptp_set_ts_config = siena_ptp_set_ts_config,
+#ifdef CONFIG_SFC_SRIOV
+ .sriov_configure = efx_siena_sriov_configure,
.sriov_init = efx_siena_sriov_init,
.sriov_fini = efx_siena_sriov_fini,
- .sriov_mac_address_changed = efx_siena_sriov_mac_address_changed,
.sriov_wanted = efx_siena_sriov_wanted,
.sriov_reset = efx_siena_sriov_reset,
+ .sriov_flr = efx_siena_sriov_flr,
+ .sriov_set_vf_mac = efx_siena_sriov_set_vf_mac,
+ .sriov_set_vf_vlan = efx_siena_sriov_set_vf_vlan,
+ .sriov_set_vf_spoofchk = efx_siena_sriov_set_vf_spoofchk,
+ .sriov_get_vf_config = efx_siena_sriov_get_vf_config,
+ .vswitching_probe = efx_port_dummy_op_int,
+ .vswitching_restore = efx_port_dummy_op_int,
+ .vswitching_remove = efx_port_dummy_op_void,
+ .set_mac_address = efx_siena_sriov_mac_address_changed,
+#endif
.revision = EFX_REV_SIENA_A0,
.txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL,
diff --git a/drivers/net/ethernet/sfc/siena_sriov.c b/drivers/net/ethernet/sfc/siena_sriov.c
index fe83430796fd..da7b94f34604 100644
--- a/drivers/net/ethernet/sfc/siena_sriov.c
+++ b/drivers/net/ethernet/sfc/siena_sriov.c
@@ -16,6 +16,7 @@
#include "filter.h"
#include "mcdi_pcol.h"
#include "farch_regs.h"
+#include "siena_sriov.h"
#include "vfdi.h"
/* Number of longs required to track all the VIs in a VF */
@@ -38,7 +39,7 @@ enum efx_vf_tx_filter_mode {
};
/**
- * struct efx_vf - Back-end resource and protocol state for a PCI VF
+ * struct siena_vf - Back-end resource and protocol state for a PCI VF
* @efx: The Efx NIC owning this VF
* @pci_rid: The PCI requester ID for this VF
* @pci_name: The PCI name (formatted address) of this VF
@@ -83,7 +84,7 @@ enum efx_vf_tx_filter_mode {
* @rxq_retry_count: Number of receive queues in @rxq_retry_mask.
* @reset_work: Work item to schedule a VF reset.
*/
-struct efx_vf {
+struct siena_vf {
struct efx_nic *efx;
unsigned int pci_rid;
char pci_name[13]; /* dddd:bb:dd.f */
@@ -189,7 +190,7 @@ MODULE_PARM_DESC(max_vfs,
*/
static struct workqueue_struct *vfdi_workqueue;
-static unsigned abs_index(struct efx_vf *vf, unsigned index)
+static unsigned abs_index(struct siena_vf *vf, unsigned index)
{
return EFX_VI_BASE + vf->index * efx_vf_size(vf->efx) + index;
}
@@ -207,8 +208,8 @@ static int efx_siena_sriov_cmd(struct efx_nic *efx, bool enable,
MCDI_SET_DWORD(inbuf, SRIOV_IN_VI_BASE, EFX_VI_BASE);
MCDI_SET_DWORD(inbuf, SRIOV_IN_VF_COUNT, efx->vf_count);
- rc = efx_mcdi_rpc(efx, MC_CMD_SRIOV, inbuf, MC_CMD_SRIOV_IN_LEN,
- outbuf, MC_CMD_SRIOV_OUT_LEN, &outlen);
+ rc = efx_mcdi_rpc_quiet(efx, MC_CMD_SRIOV, inbuf, MC_CMD_SRIOV_IN_LEN,
+ outbuf, MC_CMD_SRIOV_OUT_LEN, &outlen);
if (rc)
return rc;
if (outlen < MC_CMD_SRIOV_OUT_LEN)
@@ -299,7 +300,7 @@ out:
/* The TX filter is entirely controlled by this driver, and is modified
* underneath the feet of the VF
*/
-static void efx_siena_sriov_reset_tx_filter(struct efx_vf *vf)
+static void efx_siena_sriov_reset_tx_filter(struct siena_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct efx_filter_spec filter;
@@ -343,7 +344,7 @@ static void efx_siena_sriov_reset_tx_filter(struct efx_vf *vf)
}
/* The RX filter is managed here on behalf of the VF driver */
-static void efx_siena_sriov_reset_rx_filter(struct efx_vf *vf)
+static void efx_siena_sriov_reset_rx_filter(struct siena_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct efx_filter_spec filter;
@@ -382,7 +383,7 @@ static void efx_siena_sriov_reset_rx_filter(struct efx_vf *vf)
}
}
-static void __efx_siena_sriov_update_vf_addr(struct efx_vf *vf)
+static void __efx_siena_sriov_update_vf_addr(struct siena_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct siena_nic_data *nic_data = efx->nic_data;
@@ -397,7 +398,7 @@ static void __efx_siena_sriov_update_vf_addr(struct efx_vf *vf)
* local_page_list, either by acquiring local_lock or by running from
* efx_siena_sriov_peer_work()
*/
-static void __efx_siena_sriov_push_vf_status(struct efx_vf *vf)
+static void __efx_siena_sriov_push_vf_status(struct siena_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct siena_nic_data *nic_data = efx->nic_data;
@@ -509,8 +510,9 @@ static bool bad_buf_count(unsigned buf_count, unsigned max_entry_count)
* Optionally set VF index and VI index within the VF.
*/
static bool map_vi_index(struct efx_nic *efx, unsigned abs_index,
- struct efx_vf **vf_out, unsigned *rel_index_out)
+ struct siena_vf **vf_out, unsigned *rel_index_out)
{
+ struct siena_nic_data *nic_data = efx->nic_data;
unsigned vf_i;
if (abs_index < EFX_VI_BASE)
@@ -520,13 +522,13 @@ static bool map_vi_index(struct efx_nic *efx, unsigned abs_index,
return true;
if (vf_out)
- *vf_out = efx->vf + vf_i;
+ *vf_out = nic_data->vf + vf_i;
if (rel_index_out)
*rel_index_out = abs_index % efx_vf_size(efx);
return false;
}
-static int efx_vfdi_init_evq(struct efx_vf *vf)
+static int efx_vfdi_init_evq(struct siena_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct vfdi_req *req = vf->buf.addr;
@@ -567,7 +569,7 @@ static int efx_vfdi_init_evq(struct efx_vf *vf)
return VFDI_RC_SUCCESS;
}
-static int efx_vfdi_init_rxq(struct efx_vf *vf)
+static int efx_vfdi_init_rxq(struct siena_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct vfdi_req *req = vf->buf.addr;
@@ -608,7 +610,7 @@ static int efx_vfdi_init_rxq(struct efx_vf *vf)
return VFDI_RC_SUCCESS;
}
-static int efx_vfdi_init_txq(struct efx_vf *vf)
+static int efx_vfdi_init_txq(struct siena_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct vfdi_req *req = vf->buf.addr;
@@ -655,7 +657,7 @@ static int efx_vfdi_init_txq(struct efx_vf *vf)
}
/* Returns true when efx_vfdi_fini_all_queues should wake */
-static bool efx_vfdi_flush_wake(struct efx_vf *vf)
+static bool efx_vfdi_flush_wake(struct siena_vf *vf)
{
/* Ensure that all updates are visible to efx_vfdi_fini_all_queues() */
smp_mb();
@@ -664,7 +666,7 @@ static bool efx_vfdi_flush_wake(struct efx_vf *vf)
atomic_read(&vf->rxq_retry_count);
}
-static void efx_vfdi_flush_clear(struct efx_vf *vf)
+static void efx_vfdi_flush_clear(struct siena_vf *vf)
{
memset(vf->txq_mask, 0, sizeof(vf->txq_mask));
vf->txq_count = 0;
@@ -674,7 +676,7 @@ static void efx_vfdi_flush_clear(struct efx_vf *vf)
atomic_set(&vf->rxq_retry_count, 0);
}
-static int efx_vfdi_fini_all_queues(struct efx_vf *vf)
+static int efx_vfdi_fini_all_queues(struct siena_vf *vf)
{
struct efx_nic *efx = vf->efx;
efx_oword_t reg;
@@ -757,7 +759,7 @@ static int efx_vfdi_fini_all_queues(struct efx_vf *vf)
return timeout ? 0 : VFDI_RC_ETIMEDOUT;
}
-static int efx_vfdi_insert_filter(struct efx_vf *vf)
+static int efx_vfdi_insert_filter(struct siena_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct siena_nic_data *nic_data = efx->nic_data;
@@ -789,7 +791,7 @@ static int efx_vfdi_insert_filter(struct efx_vf *vf)
return VFDI_RC_SUCCESS;
}
-static int efx_vfdi_remove_all_filters(struct efx_vf *vf)
+static int efx_vfdi_remove_all_filters(struct siena_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct siena_nic_data *nic_data = efx->nic_data;
@@ -801,7 +803,7 @@ static int efx_vfdi_remove_all_filters(struct efx_vf *vf)
return VFDI_RC_SUCCESS;
}
-static int efx_vfdi_set_status_page(struct efx_vf *vf)
+static int efx_vfdi_set_status_page(struct siena_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct siena_nic_data *nic_data = efx->nic_data;
@@ -846,7 +848,7 @@ static int efx_vfdi_set_status_page(struct efx_vf *vf)
return VFDI_RC_SUCCESS;
}
-static int efx_vfdi_clear_status_page(struct efx_vf *vf)
+static int efx_vfdi_clear_status_page(struct siena_vf *vf)
{
mutex_lock(&vf->status_lock);
vf->status_addr = 0;
@@ -855,7 +857,7 @@ static int efx_vfdi_clear_status_page(struct efx_vf *vf)
return VFDI_RC_SUCCESS;
}
-typedef int (*efx_vfdi_op_t)(struct efx_vf *vf);
+typedef int (*efx_vfdi_op_t)(struct siena_vf *vf);
static const efx_vfdi_op_t vfdi_ops[VFDI_OP_LIMIT] = {
[VFDI_OP_INIT_EVQ] = efx_vfdi_init_evq,
@@ -870,7 +872,7 @@ static const efx_vfdi_op_t vfdi_ops[VFDI_OP_LIMIT] = {
static void efx_siena_sriov_vfdi(struct work_struct *work)
{
- struct efx_vf *vf = container_of(work, struct efx_vf, req);
+ struct siena_vf *vf = container_of(work, struct siena_vf, req);
struct efx_nic *efx = vf->efx;
struct vfdi_req *req = vf->buf.addr;
struct efx_memcpy_req copy[2];
@@ -936,7 +938,8 @@ static void efx_siena_sriov_vfdi(struct work_struct *work)
* event ring in guest memory with VFDI reset events, then (re-initialise) the
* event queue to raise an interrupt. The guest driver will then recover.
*/
-static void efx_siena_sriov_reset_vf(struct efx_vf *vf,
+
+static void efx_siena_sriov_reset_vf(struct siena_vf *vf,
struct efx_buffer *buffer)
{
struct efx_nic *efx = vf->efx;
@@ -1006,7 +1009,7 @@ static void efx_siena_sriov_reset_vf(struct efx_vf *vf,
static void efx_siena_sriov_reset_vf_work(struct work_struct *work)
{
- struct efx_vf *vf = container_of(work, struct efx_vf, req);
+ struct siena_vf *vf = container_of(work, struct siena_vf, req);
struct efx_nic *efx = vf->efx;
struct efx_buffer buf;
@@ -1055,8 +1058,10 @@ void efx_siena_sriov_probe(struct efx_nic *efx)
if (!max_vfs)
return;
- if (efx_siena_sriov_cmd(efx, false, &efx->vi_scale, &count))
+ if (efx_siena_sriov_cmd(efx, false, &efx->vi_scale, &count)) {
+ netif_info(efx, probe, efx->net_dev, "no SR-IOV VFs probed\n");
return;
+ }
if (count > 0 && count > max_vfs)
count = max_vfs;
@@ -1077,7 +1082,7 @@ static void efx_siena_sriov_peer_work(struct work_struct *data)
peer_work);
struct efx_nic *efx = nic_data->efx;
struct vfdi_status *vfdi_status = nic_data->vfdi_status.addr;
- struct efx_vf *vf;
+ struct siena_vf *vf;
struct efx_local_addr *local_addr;
struct vfdi_endpoint *peer;
struct efx_endpoint_page *epp;
@@ -1099,7 +1104,7 @@ static void efx_siena_sriov_peer_work(struct work_struct *data)
peer_space = ARRAY_SIZE(vfdi_status->peers) - 1;
peer_count = 1;
for (pos = 0; pos < efx->vf_count; ++pos) {
- vf = efx->vf + pos;
+ vf = nic_data->vf + pos;
mutex_lock(&vf->status_lock);
if (vf->rx_filtering && !is_zero_ether_addr(vf->addr.mac_addr)) {
@@ -1155,7 +1160,7 @@ static void efx_siena_sriov_peer_work(struct work_struct *data)
/* Finally, push the pages */
for (pos = 0; pos < efx->vf_count; ++pos) {
- vf = efx->vf + pos;
+ vf = nic_data->vf + pos;
mutex_lock(&vf->status_lock);
if (vf->status_addr)
@@ -1190,14 +1195,16 @@ static void efx_siena_sriov_free_local(struct efx_nic *efx)
static int efx_siena_sriov_vf_alloc(struct efx_nic *efx)
{
unsigned index;
- struct efx_vf *vf;
+ struct siena_vf *vf;
+ struct siena_nic_data *nic_data = efx->nic_data;
- efx->vf = kzalloc(sizeof(struct efx_vf) * efx->vf_count, GFP_KERNEL);
- if (!efx->vf)
+ nic_data->vf = kcalloc(efx->vf_count, sizeof(*nic_data->vf),
+ GFP_KERNEL);
+ if (!nic_data->vf)
return -ENOMEM;
for (index = 0; index < efx->vf_count; ++index) {
- vf = efx->vf + index;
+ vf = nic_data->vf + index;
vf->efx = efx;
vf->index = index;
@@ -1216,11 +1223,12 @@ static int efx_siena_sriov_vf_alloc(struct efx_nic *efx)
static void efx_siena_sriov_vfs_fini(struct efx_nic *efx)
{
- struct efx_vf *vf;
+ struct siena_nic_data *nic_data = efx->nic_data;
+ struct siena_vf *vf;
unsigned int pos;
for (pos = 0; pos < efx->vf_count; ++pos) {
- vf = efx->vf + pos;
+ vf = nic_data->vf + pos;
efx_nic_free_buffer(efx, &vf->buf);
kfree(vf->peer_page_addrs);
@@ -1237,7 +1245,7 @@ static int efx_siena_sriov_vfs_init(struct efx_nic *efx)
struct siena_nic_data *nic_data = efx->nic_data;
unsigned index, devfn, sriov, buftbl_base;
u16 offset, stride;
- struct efx_vf *vf;
+ struct siena_vf *vf;
int rc;
sriov = pci_find_ext_capability(pci_dev, PCI_EXT_CAP_ID_SRIOV);
@@ -1250,7 +1258,7 @@ static int efx_siena_sriov_vfs_init(struct efx_nic *efx)
buftbl_base = nic_data->vf_buftbl_base;
devfn = pci_dev->devfn + offset;
for (index = 0; index < efx->vf_count; ++index) {
- vf = efx->vf + index;
+ vf = nic_data->vf + index;
/* Reserve buffer entries */
vf->buftbl_base = buftbl_base;
@@ -1350,7 +1358,7 @@ fail_pci:
fail_vfs:
cancel_work_sync(&nic_data->peer_work);
efx_siena_sriov_free_local(efx);
- kfree(efx->vf);
+ kfree(nic_data->vf);
fail_alloc:
efx_nic_free_buffer(efx, &nic_data->vfdi_status);
fail_status:
@@ -1361,7 +1369,7 @@ fail_cmd:
void efx_siena_sriov_fini(struct efx_nic *efx)
{
- struct efx_vf *vf;
+ struct siena_vf *vf;
unsigned int pos;
struct siena_nic_data *nic_data = efx->nic_data;
@@ -1377,7 +1385,7 @@ void efx_siena_sriov_fini(struct efx_nic *efx)
/* Flush all reconfiguration work */
for (pos = 0; pos < efx->vf_count; ++pos) {
- vf = efx->vf + pos;
+ vf = nic_data->vf + pos;
cancel_work_sync(&vf->req);
cancel_work_sync(&vf->reset_work);
}
@@ -1388,7 +1396,7 @@ void efx_siena_sriov_fini(struct efx_nic *efx)
/* Tear down back-end state */
efx_siena_sriov_vfs_fini(efx);
efx_siena_sriov_free_local(efx);
- kfree(efx->vf);
+ kfree(nic_data->vf);
efx_nic_free_buffer(efx, &nic_data->vfdi_status);
efx_siena_sriov_cmd(efx, false, NULL, NULL);
}
@@ -1396,7 +1404,7 @@ void efx_siena_sriov_fini(struct efx_nic *efx)
void efx_siena_sriov_event(struct efx_channel *channel, efx_qword_t *event)
{
struct efx_nic *efx = channel->efx;
- struct efx_vf *vf;
+ struct siena_vf *vf;
unsigned qid, seq, type, data;
qid = EFX_QWORD_FIELD(*event, FSF_CZ_USER_QID);
@@ -1452,11 +1460,12 @@ error:
void efx_siena_sriov_flr(struct efx_nic *efx, unsigned vf_i)
{
- struct efx_vf *vf;
+ struct siena_nic_data *nic_data = efx->nic_data;
+ struct siena_vf *vf;
if (vf_i > efx->vf_init_count)
return;
- vf = efx->vf + vf_i;
+ vf = nic_data->vf + vf_i;
netif_info(efx, hw, efx->net_dev,
"FLR on VF %s\n", vf->pci_name);
@@ -1467,21 +1476,23 @@ void efx_siena_sriov_flr(struct efx_nic *efx, unsigned vf_i)
vf->evq0_count = 0;
}
-void efx_siena_sriov_mac_address_changed(struct efx_nic *efx)
+int efx_siena_sriov_mac_address_changed(struct efx_nic *efx)
{
struct siena_nic_data *nic_data = efx->nic_data;
struct vfdi_status *vfdi_status = nic_data->vfdi_status.addr;
if (!efx->vf_init_count)
- return;
+ return 0;
ether_addr_copy(vfdi_status->peers[0].mac_addr,
efx->net_dev->dev_addr);
queue_work(vfdi_workqueue, &nic_data->peer_work);
+
+ return 0;
}
void efx_siena_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event)
{
- struct efx_vf *vf;
+ struct siena_vf *vf;
unsigned queue, qid;
queue = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA);
@@ -1500,7 +1511,7 @@ void efx_siena_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event)
void efx_siena_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event)
{
- struct efx_vf *vf;
+ struct siena_vf *vf;
unsigned ev_failed, queue, qid;
queue = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_RX_DESCQ_ID);
@@ -1525,7 +1536,7 @@ void efx_siena_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event)
/* Called from napi. Schedule the reset work item */
void efx_siena_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq)
{
- struct efx_vf *vf;
+ struct siena_vf *vf;
unsigned int rel;
if (map_vi_index(efx, dmaq, &vf, &rel))
@@ -1541,9 +1552,10 @@ void efx_siena_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq)
/* Reset all VFs */
void efx_siena_sriov_reset(struct efx_nic *efx)
{
+ struct siena_nic_data *nic_data = efx->nic_data;
unsigned int vf_i;
struct efx_buffer buf;
- struct efx_vf *vf;
+ struct siena_vf *vf;
ASSERT_RTNL();
@@ -1557,7 +1569,7 @@ void efx_siena_sriov_reset(struct efx_nic *efx)
return;
for (vf_i = 0; vf_i < efx->vf_init_count; ++vf_i) {
- vf = efx->vf + vf_i;
+ vf = nic_data->vf + vf_i;
efx_siena_sriov_reset_vf(vf, &buf);
}
@@ -1573,7 +1585,6 @@ int efx_init_sriov(void)
vfdi_workqueue = create_singlethread_workqueue("sfc_vfdi");
if (!vfdi_workqueue)
return -ENOMEM;
-
return 0;
}
@@ -1582,14 +1593,14 @@ void efx_fini_sriov(void)
destroy_workqueue(vfdi_workqueue);
}
-int efx_siena_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac)
+int efx_siena_sriov_set_vf_mac(struct efx_nic *efx, int vf_i, u8 *mac)
{
- struct efx_nic *efx = netdev_priv(net_dev);
- struct efx_vf *vf;
+ struct siena_nic_data *nic_data = efx->nic_data;
+ struct siena_vf *vf;
if (vf_i >= efx->vf_init_count)
return -EINVAL;
- vf = efx->vf + vf_i;
+ vf = nic_data->vf + vf_i;
mutex_lock(&vf->status_lock);
ether_addr_copy(vf->addr.mac_addr, mac);
@@ -1599,16 +1610,16 @@ int efx_siena_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac)
return 0;
}
-int efx_siena_sriov_set_vf_vlan(struct net_device *net_dev, int vf_i,
+int efx_siena_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i,
u16 vlan, u8 qos)
{
- struct efx_nic *efx = netdev_priv(net_dev);
- struct efx_vf *vf;
+ struct siena_nic_data *nic_data = efx->nic_data;
+ struct siena_vf *vf;
u16 tci;
if (vf_i >= efx->vf_init_count)
return -EINVAL;
- vf = efx->vf + vf_i;
+ vf = nic_data->vf + vf_i;
mutex_lock(&vf->status_lock);
tci = (vlan & VLAN_VID_MASK) | ((qos & 0x7) << VLAN_PRIO_SHIFT);
@@ -1619,16 +1630,16 @@ int efx_siena_sriov_set_vf_vlan(struct net_device *net_dev, int vf_i,
return 0;
}
-int efx_siena_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf_i,
+int efx_siena_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf_i,
bool spoofchk)
{
- struct efx_nic *efx = netdev_priv(net_dev);
- struct efx_vf *vf;
+ struct siena_nic_data *nic_data = efx->nic_data;
+ struct siena_vf *vf;
int rc;
if (vf_i >= efx->vf_init_count)
return -EINVAL;
- vf = efx->vf + vf_i;
+ vf = nic_data->vf + vf_i;
mutex_lock(&vf->txq_lock);
if (vf->txq_count == 0) {
@@ -1643,16 +1654,16 @@ int efx_siena_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf_i,
return rc;
}
-int efx_siena_sriov_get_vf_config(struct net_device *net_dev, int vf_i,
+int efx_siena_sriov_get_vf_config(struct efx_nic *efx, int vf_i,
struct ifla_vf_info *ivi)
{
- struct efx_nic *efx = netdev_priv(net_dev);
- struct efx_vf *vf;
+ struct siena_nic_data *nic_data = efx->nic_data;
+ struct siena_vf *vf;
u16 tci;
if (vf_i >= efx->vf_init_count)
return -EINVAL;
- vf = efx->vf + vf_i;
+ vf = nic_data->vf + vf_i;
ivi->vf = vf_i;
ether_addr_copy(ivi->mac, vf->addr.mac_addr);
@@ -1666,3 +1677,12 @@ int efx_siena_sriov_get_vf_config(struct net_device *net_dev, int vf_i,
return 0;
}
+bool efx_siena_sriov_wanted(struct efx_nic *efx)
+{
+ return efx->vf_count != 0;
+}
+
+int efx_siena_sriov_configure(struct efx_nic *efx, int num_vfs)
+{
+ return 0;
+}
diff --git a/drivers/net/ethernet/sfc/siena_sriov.h b/drivers/net/ethernet/sfc/siena_sriov.h
new file mode 100644
index 000000000000..d88d4dab170a
--- /dev/null
+++ b/drivers/net/ethernet/sfc/siena_sriov.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers and boards
+ * Copyright 2015 Solarflare Communications 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, incorporated herein by reference.
+ */
+
+#ifndef SIENA_SRIOV_H
+#define SIENA_SRIOV_H
+
+#include "net_driver.h"
+
+/* On the SFC9000 family each port is associated with 1 PCI physical
+ * function (PF) handled by sfc and a configurable number of virtual
+ * functions (VFs) that may be handled by some other driver, often in
+ * a VM guest. The queue pointer registers are mapped in both PF and
+ * VF BARs such that an 8K region provides access to a single RX, TX
+ * and event queue (collectively a Virtual Interface, VI or VNIC).
+ *
+ * The PF has access to all 1024 VIs while VFs are mapped to VIs
+ * according to VI_BASE and VI_SCALE: VF i has access to VIs numbered
+ * in range [VI_BASE + i << VI_SCALE, VI_BASE + i + 1 << VI_SCALE).
+ * The number of VIs and the VI_SCALE value are configurable but must
+ * be established at boot time by firmware.
+ */
+
+/* Maximum VI_SCALE parameter supported by Siena */
+#define EFX_VI_SCALE_MAX 6
+/* Base VI to use for SR-IOV. Must be aligned to (1 << EFX_VI_SCALE_MAX),
+ * so this is the smallest allowed value.
+ */
+#define EFX_VI_BASE 128U
+/* Maximum number of VFs allowed */
+#define EFX_VF_COUNT_MAX 127
+/* Limit EVQs on VFs to be only 8k to reduce buffer table reservation */
+#define EFX_MAX_VF_EVQ_SIZE 8192UL
+/* The number of buffer table entries reserved for each VI on a VF */
+#define EFX_VF_BUFTBL_PER_VI \
+ ((EFX_MAX_VF_EVQ_SIZE + 2 * EFX_MAX_DMAQ_SIZE) * \
+ sizeof(efx_qword_t) / EFX_BUF_SIZE)
+
+int efx_siena_sriov_configure(struct efx_nic *efx, int num_vfs);
+int efx_siena_sriov_init(struct efx_nic *efx);
+void efx_siena_sriov_fini(struct efx_nic *efx);
+int efx_siena_sriov_mac_address_changed(struct efx_nic *efx);
+bool efx_siena_sriov_wanted(struct efx_nic *efx);
+void efx_siena_sriov_reset(struct efx_nic *efx);
+void efx_siena_sriov_flr(struct efx_nic *efx, unsigned flr);
+
+int efx_siena_sriov_set_vf_mac(struct efx_nic *efx, int vf, u8 *mac);
+int efx_siena_sriov_set_vf_vlan(struct efx_nic *efx, int vf,
+ u16 vlan, u8 qos);
+int efx_siena_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf,
+ bool spoofchk);
+int efx_siena_sriov_get_vf_config(struct efx_nic *efx, int vf,
+ struct ifla_vf_info *ivf);
+
+#ifdef CONFIG_SFC_SRIOV
+
+static inline bool efx_siena_sriov_enabled(struct efx_nic *efx)
+{
+ return efx->vf_init_count != 0;
+}
+#else /* !CONFIG_SFC_SRIOV */
+static inline bool efx_siena_sriov_enabled(struct efx_nic *efx)
+{
+ return false;
+}
+#endif /* CONFIG_SFC_SRIOV */
+
+void efx_siena_sriov_probe(struct efx_nic *efx);
+void efx_siena_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event);
+void efx_siena_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event);
+void efx_siena_sriov_event(struct efx_channel *channel, efx_qword_t *event);
+void efx_siena_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq);
+
+#endif /* SIENA_SRIOV_H */
diff --git a/drivers/net/ethernet/sfc/sriov.c b/drivers/net/ethernet/sfc/sriov.c
new file mode 100644
index 000000000000..816c44689e67
--- /dev/null
+++ b/drivers/net/ethernet/sfc/sriov.c
@@ -0,0 +1,83 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers and boards
+ * Copyright 2014-2015 Solarflare Communications 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, incorporated herein by reference.
+ */
+#include <linux/module.h>
+#include "net_driver.h"
+#include "nic.h"
+#include "sriov.h"
+
+int efx_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+
+ if (efx->type->sriov_set_vf_mac)
+ return efx->type->sriov_set_vf_mac(efx, vf_i, mac);
+ else
+ return -EOPNOTSUPP;
+}
+
+int efx_sriov_set_vf_vlan(struct net_device *net_dev, int vf_i, u16 vlan,
+ u8 qos)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+
+ if (efx->type->sriov_set_vf_vlan) {
+ if ((vlan & ~VLAN_VID_MASK) ||
+ (qos & ~(VLAN_PRIO_MASK >> VLAN_PRIO_SHIFT)))
+ return -EINVAL;
+
+ return efx->type->sriov_set_vf_vlan(efx, vf_i, vlan, qos);
+ } else {
+ return -EOPNOTSUPP;
+ }
+}
+
+int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf_i,
+ bool spoofchk)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+
+ if (efx->type->sriov_set_vf_spoofchk)
+ return efx->type->sriov_set_vf_spoofchk(efx, vf_i, spoofchk);
+ else
+ return -EOPNOTSUPP;
+}
+
+int efx_sriov_get_vf_config(struct net_device *net_dev, int vf_i,
+ struct ifla_vf_info *ivi)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+
+ if (efx->type->sriov_get_vf_config)
+ return efx->type->sriov_get_vf_config(efx, vf_i, ivi);
+ else
+ return -EOPNOTSUPP;
+}
+
+int efx_sriov_set_vf_link_state(struct net_device *net_dev, int vf_i,
+ int link_state)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+
+ if (efx->type->sriov_set_vf_link_state)
+ return efx->type->sriov_set_vf_link_state(efx, vf_i,
+ link_state);
+ else
+ return -EOPNOTSUPP;
+}
+
+int efx_sriov_get_phys_port_id(struct net_device *net_dev,
+ struct netdev_phys_item_id *ppid)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+
+ if (efx->type->sriov_get_phys_port_id)
+ return efx->type->sriov_get_phys_port_id(efx, ppid);
+ else
+ return -EOPNOTSUPP;
+}
diff --git a/drivers/net/ethernet/sfc/sriov.h b/drivers/net/ethernet/sfc/sriov.h
new file mode 100644
index 000000000000..400df526586d
--- /dev/null
+++ b/drivers/net/ethernet/sfc/sriov.h
@@ -0,0 +1,31 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers and boards
+ * Copyright 2014-2015 Solarflare Communications 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, incorporated herein by reference.
+ */
+
+#ifndef EFX_SRIOV_H
+#define EFX_SRIOV_H
+
+#include "net_driver.h"
+
+#ifdef CONFIG_SFC_SRIOV
+
+int efx_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac);
+int efx_sriov_set_vf_vlan(struct net_device *net_dev, int vf_i, u16 vlan,
+ u8 qos);
+int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf_i,
+ bool spoofchk);
+int efx_sriov_get_vf_config(struct net_device *net_dev, int vf_i,
+ struct ifla_vf_info *ivi);
+int efx_sriov_set_vf_link_state(struct net_device *net_dev, int vf_i,
+ int link_state);
+int efx_sriov_get_phys_port_id(struct net_device *net_dev,
+ struct netdev_phys_item_id *ppid);
+
+#endif /* CONFIG_SFC_SRIOV */
+
+#endif /* EFX_SRIOV_H */
diff --git a/drivers/net/ethernet/sgi/Kconfig b/drivers/net/ethernet/sgi/Kconfig
index e832f46660c9..fbbb21c13e95 100644
--- a/drivers/net/ethernet/sgi/Kconfig
+++ b/drivers/net/ethernet/sgi/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_SGI
default y
depends on (PCI && SGI_IP27) || SGI_IP32
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
@@ -24,9 +22,7 @@ config SGI_IOC3_ETH
select CRC32
select MII
---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card of this type, say Y here.
config SGI_O2MACE_ETH
tristate "SGI O2 MACE Fast Ethernet support"
diff --git a/drivers/net/ethernet/silan/Kconfig b/drivers/net/ethernet/silan/Kconfig
index 3409b3f97a1b..ac982be38510 100644
--- a/drivers/net/ethernet/silan/Kconfig
+++ b/drivers/net/ethernet/silan/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_SILAN
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/sis/Kconfig b/drivers/net/ethernet/sis/Kconfig
index 68d052b09af1..22ec98ec9d3e 100644
--- a/drivers/net/ethernet/sis/Kconfig
+++ b/drivers/net/ethernet/sis/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_SIS
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig
index 3e97a8b43147..eb9230e2092f 100644
--- a/drivers/net/ethernet/smsc/Kconfig
+++ b/drivers/net/ethernet/smsc/Kconfig
@@ -9,9 +9,7 @@ config NET_VENDOR_SMSC
ISA || M32R || MAC || MIPS || MN10300 || NIOS2 || PCI || \
PCMCIA || SUPERH || XTENSA
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
@@ -29,8 +27,7 @@ config SMC9194
option if you have a DELL laptop with the docking station, or
another SMC9192/9194 based chipset. Say Y if you want it compiled
into the kernel, and read the file
- <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
+ <file:Documentation/networking/smc9.txt>.
To compile this driver as a module, choose M here. The module
will be called smc9194.
@@ -46,8 +43,7 @@ config SMC91X
This is a driver for SMC's 91x series of Ethernet chipsets,
including the SMC91C94 and the SMC91C111. Say Y if you want it
compiled into the kernel, and read the file
- <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
+ <file:Documentation/networking/smc9.txt>.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
@@ -85,9 +81,7 @@ config SMC911X
---help---
This is a driver for SMSC's LAN911x series of Ethernet chipsets
including the new LAN9115, LAN9116, LAN9117, and LAN9118.
- Say Y if you want it compiled into the kernel,
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ Say Y here if you want it compiled into the kernel.
This driver is also available as a module. The module will be
called smc911x. If you want to compile it as a module, say M
@@ -122,9 +116,7 @@ config SMSC9420
select SMSC_PHY
---help---
This is a driver for SMSC's LAN9420 PCI ethernet adapter.
- Say Y if you want it compiled into the kernel,
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ Say Y here if you want it compiled into the kernel.
This driver is also available as a module. The module will be
called smsc9420. If you want to compile it as a module, say M
diff --git a/drivers/net/ethernet/stmicro/Kconfig b/drivers/net/ethernet/stmicro/Kconfig
index f4a80da00650..1c1157d2bd40 100644
--- a/drivers/net/ethernet/stmicro/Kconfig
+++ b/drivers/net/ethernet/stmicro/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_STMICRO
default y
depends on HAS_IOMEM
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 7d3af190be55..cec147d1d34f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -16,6 +16,7 @@ if STMMAC_ETH
config STMMAC_PLATFORM
tristate "STMMAC Platform bus support"
depends on STMMAC_ETH
+ select MFD_SYSCON
default y
---help---
This selects the platform specific bus support for the stmmac driver.
@@ -26,6 +27,95 @@ config STMMAC_PLATFORM
If unsure, say N.
+if STMMAC_PLATFORM
+
+config DWMAC_GENERIC
+ tristate "Generic driver for DWMAC"
+ default STMMAC_PLATFORM
+ ---help---
+ Generic DWMAC driver for platforms that don't require any
+ platform specific code to function or is using platform
+ data for setup.
+
+config DWMAC_IPQ806X
+ tristate "QCA IPQ806x DWMAC support"
+ default ARCH_QCOM
+ depends on OF
+ select MFD_SYSCON
+ help
+ Support for QCA IPQ806X DWMAC Ethernet.
+
+ This selects the IPQ806x SoC glue layer support for the stmmac
+ device driver. This driver does not use any of the hardware
+ acceleration features available on this SoC. Network devices
+ will behave like standard non-accelerated ethernet interfaces.
+
+config DWMAC_LPC18XX
+ tristate "NXP LPC18xx/43xx DWMAC support"
+ default ARCH_LPC18XX
+ depends on OF
+ select MFD_SYSCON
+ ---help---
+ Support for NXP LPC18xx/43xx DWMAC Ethernet.
+
+config DWMAC_MESON
+ tristate "Amlogic Meson dwmac support"
+ default ARCH_MESON
+ depends on OF
+ help
+ Support for Ethernet controller on Amlogic Meson SoCs.
+
+ This selects the Amlogic Meson SoC glue layer support for
+ the stmmac device driver. This driver is used for Meson6 and
+ Meson8 SoCs.
+
+config DWMAC_ROCKCHIP
+ tristate "Rockchip dwmac support"
+ default ARCH_ROCKCHIP
+ depends on OF
+ select MFD_SYSCON
+ help
+ Support for Ethernet controller on Rockchip RK3288 SoC.
+
+ This selects the Rockchip RK3288 SoC glue layer support for
+ the stmmac device driver.
+
+config DWMAC_SOCFPGA
+ tristate "SOCFPGA dwmac support"
+ default ARCH_SOCFPGA
+ depends on OF
+ select MFD_SYSCON
+ help
+ Support for ethernet controller on Altera SOCFPGA
+
+ This selects the Altera SOCFPGA SoC glue layer support
+ for the stmmac device driver. This driver is used for
+ arria5 and cyclone5 FPGA SoCs.
+
+config DWMAC_STI
+ tristate "STi GMAC support"
+ default ARCH_STI
+ depends on OF
+ select MFD_SYSCON
+ ---help---
+ Support for ethernet controller on STi SOCs.
+
+ This selects STi SoC glue layer support for the stmmac
+ device driver. This driver is used on for the STi series
+ SOCs GMAC ethernet controller.
+
+config DWMAC_SUNXI
+ tristate "Allwinner GMAC support"
+ default ARCH_SUNXI
+ depends on OF
+ ---help---
+ Support for Allwinner A20/A31 GMAC ethernet controllers.
+
+ This selects Allwinner SoC glue layer support for the
+ stmmac device driver. This driver is used for A20/A31
+ GMAC ethernet controller.
+endif
+
config STMMAC_PCI
tristate "STMMAC PCI bus support"
depends on STMMAC_ETH && PCI
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 73c2715a27f3..b3901616f4f6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -4,9 +4,17 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o $(stmmac-y)
-obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
-stmmac-platform-objs:= stmmac_platform.o dwmac-meson.o dwmac-sunxi.o \
- dwmac-sti.o dwmac-socfpga.o dwmac-rk.o
+# Ordering matters. Generic driver must be last.
+obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
+obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o
+obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o
+obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o
+obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o
+obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o
+obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o
+obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
+obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o
+stmmac-platform-objs:= stmmac_platform.o
obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
stmmac-pci-objs:= stmmac_pci.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs.h b/drivers/net/ethernet/stmicro/stmmac/descs.h
index ad3996038018..799c2929c536 100644
--- a/drivers/net/ethernet/stmicro/stmmac/descs.h
+++ b/drivers/net/ethernet/stmicro/stmmac/descs.h
@@ -158,6 +158,8 @@ struct dma_desc {
u32 buffer2_size:13;
u32 reserved4:3;
} etx; /* -- enhanced -- */
+
+ u64 all_flags;
} des01;
unsigned int des2;
unsigned int des3;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
new file mode 100644
index 000000000000..e817a1a44379
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
@@ -0,0 +1,41 @@
+/*
+ * Generic DWMAC platform driver
+ *
+ * Copyright (C) 2007-2011 STMicroelectronics Ltd
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "stmmac.h"
+#include "stmmac_platform.h"
+
+static const struct of_device_id dwmac_generic_match[] = {
+ { .compatible = "st,spear600-gmac"},
+ { .compatible = "snps,dwmac-3.610"},
+ { .compatible = "snps,dwmac-3.70a"},
+ { .compatible = "snps,dwmac-3.710"},
+ { .compatible = "snps,dwmac"},
+ { }
+};
+MODULE_DEVICE_TABLE(of, dwmac_generic_match);
+
+static struct platform_driver dwmac_generic_driver = {
+ .probe = stmmac_pltfr_probe,
+ .remove = stmmac_pltfr_remove,
+ .driver = {
+ .name = STMMAC_RESOURCE_NAME,
+ .pm = &stmmac_pltfr_pm_ops,
+ .of_match_table = of_match_ptr(dwmac_generic_match),
+ },
+};
+module_platform_driver(dwmac_generic_driver);
+
+MODULE_DESCRIPTION("Generic dwmac driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
new file mode 100644
index 000000000000..7e3129e7f143
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
@@ -0,0 +1,365 @@
+/*
+ * Qualcomm Atheros IPQ806x GMAC glue layer
+ *
+ * Copyright (C) 2015 The Linux Foundation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/phy.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/of_net.h>
+#include <linux/mfd/syscon.h>
+#include <linux/stmmac.h>
+#include <linux/of_mdio.h>
+#include <linux/module.h>
+
+#include "stmmac_platform.h"
+
+#define NSS_COMMON_CLK_GATE 0x8
+#define NSS_COMMON_CLK_GATE_PTP_EN(x) BIT(0x10 + x)
+#define NSS_COMMON_CLK_GATE_RGMII_RX_EN(x) BIT(0x9 + (x * 2))
+#define NSS_COMMON_CLK_GATE_RGMII_TX_EN(x) BIT(0x8 + (x * 2))
+#define NSS_COMMON_CLK_GATE_GMII_RX_EN(x) BIT(0x4 + x)
+#define NSS_COMMON_CLK_GATE_GMII_TX_EN(x) BIT(0x0 + x)
+
+#define NSS_COMMON_CLK_DIV0 0xC
+#define NSS_COMMON_CLK_DIV_OFFSET(x) (x * 8)
+#define NSS_COMMON_CLK_DIV_MASK 0x7f
+
+#define NSS_COMMON_CLK_SRC_CTRL 0x14
+#define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x) (1 << x)
+/* Mode is coded on 1 bit but is different depending on the MAC ID:
+ * MAC0: QSGMII=0 RGMII=1
+ * MAC1: QSGMII=0 SGMII=0 RGMII=1
+ * MAC2 & MAC3: QSGMII=0 SGMII=1
+ */
+#define NSS_COMMON_CLK_SRC_CTRL_RGMII(x) 1
+#define NSS_COMMON_CLK_SRC_CTRL_SGMII(x) ((x >= 2) ? 1 : 0)
+
+#define NSS_COMMON_MACSEC_CTL 0x28
+#define NSS_COMMON_MACSEC_CTL_EXT_BYPASS_EN(x) (1 << x)
+
+#define NSS_COMMON_GMAC_CTL(x) (0x30 + (x * 4))
+#define NSS_COMMON_GMAC_CTL_CSYS_REQ BIT(19)
+#define NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL BIT(16)
+#define NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET 8
+#define NSS_COMMON_GMAC_CTL_IFG_OFFSET 0
+#define NSS_COMMON_GMAC_CTL_IFG_MASK 0x3f
+
+#define NSS_COMMON_CLK_DIV_RGMII_1000 1
+#define NSS_COMMON_CLK_DIV_RGMII_100 9
+#define NSS_COMMON_CLK_DIV_RGMII_10 99
+#define NSS_COMMON_CLK_DIV_SGMII_1000 0
+#define NSS_COMMON_CLK_DIV_SGMII_100 4
+#define NSS_COMMON_CLK_DIV_SGMII_10 49
+
+#define QSGMII_PCS_MODE_CTL 0x68
+#define QSGMII_PCS_MODE_CTL_AUTONEG_EN(x) BIT((x * 8) + 7)
+
+#define QSGMII_PCS_CAL_LCKDT_CTL 0x120
+#define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19)
+
+/* Only GMAC1/2/3 support SGMII and their CTL register are not contiguous */
+#define QSGMII_PHY_SGMII_CTL(x) ((x == 1) ? 0x134 : \
+ (0x13c + (4 * (x - 2))))
+#define QSGMII_PHY_CDR_EN BIT(0)
+#define QSGMII_PHY_RX_FRONT_EN BIT(1)
+#define QSGMII_PHY_RX_SIGNAL_DETECT_EN BIT(2)
+#define QSGMII_PHY_TX_DRIVER_EN BIT(3)
+#define QSGMII_PHY_QSGMII_EN BIT(7)
+#define QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET 12
+#define QSGMII_PHY_PHASE_LOOP_GAIN_MASK 0x7
+#define QSGMII_PHY_RX_DC_BIAS_OFFSET 18
+#define QSGMII_PHY_RX_DC_BIAS_MASK 0x3
+#define QSGMII_PHY_RX_INPUT_EQU_OFFSET 20
+#define QSGMII_PHY_RX_INPUT_EQU_MASK 0x3
+#define QSGMII_PHY_CDR_PI_SLEW_OFFSET 22
+#define QSGMII_PHY_CDR_PI_SLEW_MASK 0x3
+#define QSGMII_PHY_TX_DRV_AMP_OFFSET 28
+#define QSGMII_PHY_TX_DRV_AMP_MASK 0xf
+
+struct ipq806x_gmac {
+ struct platform_device *pdev;
+ struct regmap *nss_common;
+ struct regmap *qsgmii_csr;
+ uint32_t id;
+ struct clk *core_clk;
+ phy_interface_t phy_mode;
+};
+
+static int get_clk_div_sgmii(struct ipq806x_gmac *gmac, unsigned int speed)
+{
+ struct device *dev = &gmac->pdev->dev;
+ int div;
+
+ switch (speed) {
+ case SPEED_1000:
+ div = NSS_COMMON_CLK_DIV_SGMII_1000;
+ break;
+
+ case SPEED_100:
+ div = NSS_COMMON_CLK_DIV_SGMII_100;
+ break;
+
+ case SPEED_10:
+ div = NSS_COMMON_CLK_DIV_SGMII_10;
+ break;
+
+ default:
+ dev_err(dev, "Speed %dMbps not supported in SGMII\n", speed);
+ return -EINVAL;
+ }
+
+ return div;
+}
+
+static int get_clk_div_rgmii(struct ipq806x_gmac *gmac, unsigned int speed)
+{
+ struct device *dev = &gmac->pdev->dev;
+ int div;
+
+ switch (speed) {
+ case SPEED_1000:
+ div = NSS_COMMON_CLK_DIV_RGMII_1000;
+ break;
+
+ case SPEED_100:
+ div = NSS_COMMON_CLK_DIV_RGMII_100;
+ break;
+
+ case SPEED_10:
+ div = NSS_COMMON_CLK_DIV_RGMII_10;
+ break;
+
+ default:
+ dev_err(dev, "Speed %dMbps not supported in RGMII\n", speed);
+ return -EINVAL;
+ }
+
+ return div;
+}
+
+static int ipq806x_gmac_set_speed(struct ipq806x_gmac *gmac, unsigned int speed)
+{
+ uint32_t clk_bits, val;
+ int div;
+
+ switch (gmac->phy_mode) {
+ case PHY_INTERFACE_MODE_RGMII:
+ div = get_clk_div_rgmii(gmac, speed);
+ clk_bits = NSS_COMMON_CLK_GATE_RGMII_RX_EN(gmac->id) |
+ NSS_COMMON_CLK_GATE_RGMII_TX_EN(gmac->id);
+ break;
+
+ case PHY_INTERFACE_MODE_SGMII:
+ div = get_clk_div_sgmii(gmac, speed);
+ clk_bits = NSS_COMMON_CLK_GATE_GMII_RX_EN(gmac->id) |
+ NSS_COMMON_CLK_GATE_GMII_TX_EN(gmac->id);
+ break;
+
+ default:
+ dev_err(&gmac->pdev->dev, "Unsupported PHY mode: \"%s\"\n",
+ phy_modes(gmac->phy_mode));
+ return -EINVAL;
+ }
+
+ /* Disable the clocks */
+ regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
+ val &= ~clk_bits;
+ regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
+
+ /* Set the divider */
+ regmap_read(gmac->nss_common, NSS_COMMON_CLK_DIV0, &val);
+ val &= ~(NSS_COMMON_CLK_DIV_MASK
+ << NSS_COMMON_CLK_DIV_OFFSET(gmac->id));
+ val |= div << NSS_COMMON_CLK_DIV_OFFSET(gmac->id);
+ regmap_write(gmac->nss_common, NSS_COMMON_CLK_DIV0, val);
+
+ /* Enable the clock back */
+ regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
+ val |= clk_bits;
+ regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
+
+ return 0;
+}
+
+static void *ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac)
+{
+ struct device *dev = &gmac->pdev->dev;
+
+ gmac->phy_mode = of_get_phy_mode(dev->of_node);
+ if (gmac->phy_mode < 0) {
+ dev_err(dev, "missing phy mode property\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (of_property_read_u32(dev->of_node, "qcom,id", &gmac->id) < 0) {
+ dev_err(dev, "missing qcom id property\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* The GMACs are called 1 to 4 in the documentation, but to simplify the
+ * code and keep it consistent with the Linux convention, we'll number
+ * them from 0 to 3 here.
+ */
+ if (gmac->id < 0 || gmac->id > 3) {
+ dev_err(dev, "invalid gmac id\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ gmac->core_clk = devm_clk_get(dev, "stmmaceth");
+ if (IS_ERR(gmac->core_clk)) {
+ dev_err(dev, "missing stmmaceth clk property\n");
+ return gmac->core_clk;
+ }
+ clk_set_rate(gmac->core_clk, 266000000);
+
+ /* Setup the register map for the nss common registers */
+ gmac->nss_common = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "qcom,nss-common");
+ if (IS_ERR(gmac->nss_common)) {
+ dev_err(dev, "missing nss-common node\n");
+ return gmac->nss_common;
+ }
+
+ /* Setup the register map for the qsgmii csr registers */
+ gmac->qsgmii_csr = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "qcom,qsgmii-csr");
+ if (IS_ERR(gmac->qsgmii_csr)) {
+ dev_err(dev, "missing qsgmii-csr node\n");
+ return gmac->qsgmii_csr;
+ }
+
+ return NULL;
+}
+
+static void *ipq806x_gmac_setup(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ipq806x_gmac *gmac;
+ int val;
+ void *err;
+
+ gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
+ if (!gmac)
+ return ERR_PTR(-ENOMEM);
+
+ gmac->pdev = pdev;
+
+ err = ipq806x_gmac_of_parse(gmac);
+ if (err) {
+ dev_err(dev, "device tree parsing error\n");
+ return err;
+ }
+
+ regmap_write(gmac->qsgmii_csr, QSGMII_PCS_CAL_LCKDT_CTL,
+ QSGMII_PCS_CAL_LCKDT_CTL_RST);
+
+ /* Inter frame gap is set to 12 */
+ val = 12 << NSS_COMMON_GMAC_CTL_IFG_OFFSET |
+ 12 << NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET;
+ /* We also initiate an AXI low power exit request */
+ val |= NSS_COMMON_GMAC_CTL_CSYS_REQ;
+ switch (gmac->phy_mode) {
+ case PHY_INTERFACE_MODE_RGMII:
+ val |= NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL;
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ val &= ~NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL;
+ break;
+ default:
+ dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
+ phy_modes(gmac->phy_mode));
+ return NULL;
+ }
+ regmap_write(gmac->nss_common, NSS_COMMON_GMAC_CTL(gmac->id), val);
+
+ /* Configure the clock src according to the mode */
+ regmap_read(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, &val);
+ val &= ~NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
+ switch (gmac->phy_mode) {
+ case PHY_INTERFACE_MODE_RGMII:
+ val |= NSS_COMMON_CLK_SRC_CTRL_RGMII(gmac->id) <<
+ NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ val |= NSS_COMMON_CLK_SRC_CTRL_SGMII(gmac->id) <<
+ NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
+ break;
+ default:
+ dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
+ phy_modes(gmac->phy_mode));
+ return NULL;
+ }
+ regmap_write(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, val);
+
+ /* Enable PTP clock */
+ regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
+ val |= NSS_COMMON_CLK_GATE_PTP_EN(gmac->id);
+ regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
+
+ if (gmac->phy_mode == PHY_INTERFACE_MODE_SGMII) {
+ regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id),
+ QSGMII_PHY_CDR_EN |
+ QSGMII_PHY_RX_FRONT_EN |
+ QSGMII_PHY_RX_SIGNAL_DETECT_EN |
+ QSGMII_PHY_TX_DRIVER_EN |
+ QSGMII_PHY_QSGMII_EN |
+ 0x4 << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET |
+ 0x3 << QSGMII_PHY_RX_DC_BIAS_OFFSET |
+ 0x1 << QSGMII_PHY_RX_INPUT_EQU_OFFSET |
+ 0x2 << QSGMII_PHY_CDR_PI_SLEW_OFFSET |
+ 0xC << QSGMII_PHY_TX_DRV_AMP_OFFSET);
+ }
+
+ return gmac;
+}
+
+static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed)
+{
+ struct ipq806x_gmac *gmac = priv;
+
+ ipq806x_gmac_set_speed(gmac, speed);
+}
+
+static const struct stmmac_of_data ipq806x_gmac_data = {
+ .has_gmac = 1,
+ .setup = ipq806x_gmac_setup,
+ .fix_mac_speed = ipq806x_gmac_fix_mac_speed,
+};
+
+static const struct of_device_id ipq806x_gmac_dwmac_match[] = {
+ { .compatible = "qcom,ipq806x-gmac", .data = &ipq806x_gmac_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ipq806x_gmac_dwmac_match);
+
+static struct platform_driver ipq806x_gmac_dwmac_driver = {
+ .probe = stmmac_pltfr_probe,
+ .remove = stmmac_pltfr_remove,
+ .driver = {
+ .name = "ipq806x-gmac-dwmac",
+ .pm = &stmmac_pltfr_pm_ops,
+ .of_match_table = ipq806x_gmac_dwmac_match,
+ },
+};
+module_platform_driver(ipq806x_gmac_dwmac_driver);
+
+MODULE_AUTHOR("Mathieu Olivari <mathieu@codeaurora.org>");
+MODULE_DESCRIPTION("Qualcomm Atheros IPQ806x DWMAC specific glue layer");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c
new file mode 100644
index 000000000000..cb888d3ebbdc
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c
@@ -0,0 +1,99 @@
+/*
+ * DWMAC glue for NXP LPC18xx/LPC43xx Ethernet
+ *
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/stmmac.h>
+
+#include "stmmac_platform.h"
+
+/* Register defines for CREG syscon */
+#define LPC18XX_CREG_CREG6 0x12c
+# define LPC18XX_CREG_CREG6_ETHMODE_MASK 0x7
+# define LPC18XX_CREG_CREG6_ETHMODE_MII 0x0
+# define LPC18XX_CREG_CREG6_ETHMODE_RMII 0x4
+
+struct lpc18xx_dwmac_priv_data {
+ struct regmap *reg;
+ int interface;
+};
+
+static void *lpc18xx_dwmac_setup(struct platform_device *pdev)
+{
+ struct lpc18xx_dwmac_priv_data *dwmac;
+
+ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
+ if (!dwmac)
+ return ERR_PTR(-ENOMEM);
+
+ dwmac->interface = of_get_phy_mode(pdev->dev.of_node);
+ if (dwmac->interface < 0)
+ return ERR_PTR(dwmac->interface);
+
+ dwmac->reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg");
+ if (IS_ERR(dwmac->reg)) {
+ dev_err(&pdev->dev, "Syscon lookup failed\n");
+ return dwmac->reg;
+ }
+
+ return dwmac;
+}
+
+static int lpc18xx_dwmac_init(struct platform_device *pdev, void *priv)
+{
+ struct lpc18xx_dwmac_priv_data *dwmac = priv;
+ u8 ethmode;
+
+ if (dwmac->interface == PHY_INTERFACE_MODE_MII) {
+ ethmode = LPC18XX_CREG_CREG6_ETHMODE_MII;
+ } else if (dwmac->interface == PHY_INTERFACE_MODE_RMII) {
+ ethmode = LPC18XX_CREG_CREG6_ETHMODE_RMII;
+ } else {
+ dev_err(&pdev->dev, "Only MII and RMII mode supported\n");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(dwmac->reg, LPC18XX_CREG_CREG6,
+ LPC18XX_CREG_CREG6_ETHMODE_MASK, ethmode);
+
+ return 0;
+}
+
+static const struct stmmac_of_data lpc18xx_dwmac_data = {
+ .has_gmac = 1,
+ .setup = lpc18xx_dwmac_setup,
+ .init = lpc18xx_dwmac_init,
+};
+
+static const struct of_device_id lpc18xx_dwmac_match[] = {
+ { .compatible = "nxp,lpc1850-dwmac", .data = &lpc18xx_dwmac_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lpc18xx_dwmac_match);
+
+static struct platform_driver lpc18xx_dwmac_driver = {
+ .probe = stmmac_pltfr_probe,
+ .remove = stmmac_pltfr_remove,
+ .driver = {
+ .name = "lpc18xx-dwmac",
+ .pm = &stmmac_pltfr_pm_ops,
+ .of_match_table = lpc18xx_dwmac_match,
+ },
+};
+module_platform_driver(lpc18xx_dwmac_driver);
+
+MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
+MODULE_DESCRIPTION("DWMAC glue for LPC18xx/43xx Ethernet");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
index cca028d632f6..61a324a87d09 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
@@ -15,6 +15,7 @@
#include <linux/ethtool.h>
#include <linux/io.h>
#include <linux/ioport.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/stmmac.h>
@@ -63,7 +64,28 @@ static void *meson6_dwmac_setup(struct platform_device *pdev)
return dwmac;
}
-const struct stmmac_of_data meson6_dwmac_data = {
+static const struct stmmac_of_data meson6_dwmac_data = {
.setup = meson6_dwmac_setup,
.fix_mac_speed = meson6_dwmac_fix_mac_speed,
};
+
+static const struct of_device_id meson6_dwmac_match[] = {
+ { .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data},
+ { }
+};
+MODULE_DEVICE_TABLE(of, meson6_dwmac_match);
+
+static struct platform_driver meson6_dwmac_driver = {
+ .probe = stmmac_pltfr_probe,
+ .remove = stmmac_pltfr_remove,
+ .driver = {
+ .name = "meson6-dwmac",
+ .pm = &stmmac_pltfr_pm_ops,
+ .of_match_table = meson6_dwmac_match,
+ },
+};
+module_platform_driver(meson6_dwmac_driver);
+
+MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
+MODULE_DESCRIPTION("Amlogic Meson DWMAC glue layer");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 6249a4ec08f0..00a1e1e09d4f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -22,23 +22,36 @@
#include <linux/phy.h>
#include <linux/of_net.h>
#include <linux/gpio.h>
+#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/delay.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
+#include "stmmac_platform.h"
+
+struct rk_priv_data;
+struct rk_gmac_ops {
+ void (*set_to_rgmii)(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay);
+ void (*set_to_rmii)(struct rk_priv_data *bsp_priv);
+ void (*set_rgmii_speed)(struct rk_priv_data *bsp_priv, int speed);
+ void (*set_rmii_speed)(struct rk_priv_data *bsp_priv, int speed);
+};
+
struct rk_priv_data {
struct platform_device *pdev;
int phy_iface;
struct regulator *regulator;
+ struct rk_gmac_ops *ops;
bool clk_enabled;
bool clock_input;
struct clk *clk_mac;
- struct clk *clk_mac_pll;
struct clk *gmac_clkin;
struct clk *mac_clk_rx;
struct clk *mac_clk_tx;
@@ -61,103 +74,228 @@ struct rk_priv_data {
#define RK3288_GRF_SOC_CON1 0x0248
#define RK3288_GRF_SOC_CON3 0x0250
-#define RK3288_GRF_GPIO3D_E 0x01ec
-#define RK3288_GRF_GPIO4A_E 0x01f0
-#define RK3288_GRF_GPIO4B_E 0x01f4
/*RK3288_GRF_SOC_CON1*/
-#define GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(6) | GRF_CLR_BIT(7) | GRF_CLR_BIT(8))
-#define GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | GRF_BIT(8))
-#define GMAC_FLOW_CTRL GRF_BIT(9)
-#define GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9)
-#define GMAC_SPEED_10M GRF_CLR_BIT(10)
-#define GMAC_SPEED_100M GRF_BIT(10)
-#define GMAC_RMII_CLK_25M GRF_BIT(11)
-#define GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11)
-#define GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13))
-#define GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13))
-#define GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13))
-#define GMAC_RMII_MODE GRF_BIT(14)
-#define GMAC_RMII_MODE_CLR GRF_CLR_BIT(14)
+#define RK3288_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(6) | GRF_CLR_BIT(7) | \
+ GRF_CLR_BIT(8))
+#define RK3288_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | \
+ GRF_BIT(8))
+#define RK3288_GMAC_FLOW_CTRL GRF_BIT(9)
+#define RK3288_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9)
+#define RK3288_GMAC_SPEED_10M GRF_CLR_BIT(10)
+#define RK3288_GMAC_SPEED_100M GRF_BIT(10)
+#define RK3288_GMAC_RMII_CLK_25M GRF_BIT(11)
+#define RK3288_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11)
+#define RK3288_GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13))
+#define RK3288_GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13))
+#define RK3288_GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13))
+#define RK3288_GMAC_RMII_MODE GRF_BIT(14)
+#define RK3288_GMAC_RMII_MODE_CLR GRF_CLR_BIT(14)
/*RK3288_GRF_SOC_CON3*/
-#define GMAC_TXCLK_DLY_ENABLE GRF_BIT(14)
-#define GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14)
-#define GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
-#define GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
-#define GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7)
-#define GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
-
-static void set_to_rgmii(struct rk_priv_data *bsp_priv,
- int tx_delay, int rx_delay)
+#define RK3288_GMAC_TXCLK_DLY_ENABLE GRF_BIT(14)
+#define RK3288_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14)
+#define RK3288_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
+#define RK3288_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
+#define RK3288_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7)
+#define RK3288_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+static void rk3288_set_to_rgmii(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay)
{
struct device *dev = &bsp_priv->pdev->dev;
if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ dev_err(dev, "Missing rockchip,grf property\n");
return;
}
regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
- GMAC_PHY_INTF_SEL_RGMII | GMAC_RMII_MODE_CLR);
+ RK3288_GMAC_PHY_INTF_SEL_RGMII |
+ RK3288_GMAC_RMII_MODE_CLR);
regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
- GMAC_RXCLK_DLY_ENABLE | GMAC_TXCLK_DLY_ENABLE |
- GMAC_CLK_RX_DL_CFG(rx_delay) |
- GMAC_CLK_TX_DL_CFG(tx_delay));
+ RK3288_GMAC_RXCLK_DLY_ENABLE |
+ RK3288_GMAC_TXCLK_DLY_ENABLE |
+ RK3288_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3288_GMAC_CLK_TX_DL_CFG(tx_delay));
}
-static void set_to_rmii(struct rk_priv_data *bsp_priv)
+static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv)
{
struct device *dev = &bsp_priv->pdev->dev;
if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ dev_err(dev, "Missing rockchip,grf property\n");
return;
}
regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
- GMAC_PHY_INTF_SEL_RMII | GMAC_RMII_MODE);
+ RK3288_GMAC_PHY_INTF_SEL_RMII | RK3288_GMAC_RMII_MODE);
}
-static void set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
+static void rk3288_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
{
struct device *dev = &bsp_priv->pdev->dev;
if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ dev_err(dev, "Missing rockchip,grf property\n");
return;
}
if (speed == 10)
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_2_5M);
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+ RK3288_GMAC_CLK_2_5M);
else if (speed == 100)
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_25M);
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+ RK3288_GMAC_CLK_25M);
else if (speed == 1000)
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_125M);
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+ RK3288_GMAC_CLK_125M);
else
dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
}
-static void set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+static void rk3288_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
{
struct device *dev = &bsp_priv->pdev->dev;
if (IS_ERR(bsp_priv->grf)) {
- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ dev_err(dev, "Missing rockchip,grf property\n");
return;
}
if (speed == 10) {
regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
- GMAC_RMII_CLK_2_5M | GMAC_SPEED_10M);
+ RK3288_GMAC_RMII_CLK_2_5M |
+ RK3288_GMAC_SPEED_10M);
} else if (speed == 100) {
regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
- GMAC_RMII_CLK_25M | GMAC_SPEED_100M);
+ RK3288_GMAC_RMII_CLK_25M |
+ RK3288_GMAC_SPEED_100M);
} else {
dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
}
}
+struct rk_gmac_ops rk3288_ops = {
+ .set_to_rgmii = rk3288_set_to_rgmii,
+ .set_to_rmii = rk3288_set_to_rmii,
+ .set_rgmii_speed = rk3288_set_rgmii_speed,
+ .set_rmii_speed = rk3288_set_rmii_speed,
+};
+
+#define RK3368_GRF_SOC_CON15 0x043c
+#define RK3368_GRF_SOC_CON16 0x0440
+
+/* RK3368_GRF_SOC_CON15 */
+#define RK3368_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(9) | GRF_CLR_BIT(10) | \
+ GRF_CLR_BIT(11))
+#define RK3368_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(9) | GRF_CLR_BIT(10) | \
+ GRF_BIT(11))
+#define RK3368_GMAC_FLOW_CTRL GRF_BIT(8)
+#define RK3368_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(8)
+#define RK3368_GMAC_SPEED_10M GRF_CLR_BIT(7)
+#define RK3368_GMAC_SPEED_100M GRF_BIT(7)
+#define RK3368_GMAC_RMII_CLK_25M GRF_BIT(3)
+#define RK3368_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(3)
+#define RK3368_GMAC_CLK_125M (GRF_CLR_BIT(4) | GRF_CLR_BIT(5))
+#define RK3368_GMAC_CLK_25M (GRF_BIT(4) | GRF_BIT(5))
+#define RK3368_GMAC_CLK_2_5M (GRF_CLR_BIT(4) | GRF_BIT(5))
+#define RK3368_GMAC_RMII_MODE GRF_BIT(6)
+#define RK3368_GMAC_RMII_MODE_CLR GRF_CLR_BIT(6)
+
+/* RK3368_GRF_SOC_CON16 */
+#define RK3368_GMAC_TXCLK_DLY_ENABLE GRF_BIT(7)
+#define RK3368_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7)
+#define RK3368_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
+#define RK3368_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
+#define RK3368_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
+#define RK3368_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+static void rk3368_set_to_rgmii(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
+ RK3368_GMAC_PHY_INTF_SEL_RGMII |
+ RK3368_GMAC_RMII_MODE_CLR);
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON16,
+ RK3368_GMAC_RXCLK_DLY_ENABLE |
+ RK3368_GMAC_TXCLK_DLY_ENABLE |
+ RK3368_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3368_GMAC_CLK_TX_DL_CFG(tx_delay));
+}
+
+static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
+ RK3368_GMAC_PHY_INTF_SEL_RMII | RK3368_GMAC_RMII_MODE);
+}
+
+static void rk3368_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ if (speed == 10)
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
+ RK3368_GMAC_CLK_2_5M);
+ else if (speed == 100)
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
+ RK3368_GMAC_CLK_25M);
+ else if (speed == 1000)
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
+ RK3368_GMAC_CLK_125M);
+ else
+ dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
+}
+
+static void rk3368_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ if (speed == 10) {
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
+ RK3368_GMAC_RMII_CLK_2_5M |
+ RK3368_GMAC_SPEED_10M);
+ } else if (speed == 100) {
+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
+ RK3368_GMAC_RMII_CLK_25M |
+ RK3368_GMAC_SPEED_100M);
+ } else {
+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+ }
+}
+
+struct rk_gmac_ops rk3368_ops = {
+ .set_to_rgmii = rk3368_set_to_rgmii,
+ .set_to_rmii = rk3368_set_to_rmii,
+ .set_rgmii_speed = rk3368_set_rgmii_speed,
+ .set_rmii_speed = rk3368_set_rmii_speed,
+};
+
static int gmac_clk_init(struct rk_priv_data *bsp_priv)
{
struct device *dev = &bsp_priv->pdev->dev;
@@ -166,49 +304,49 @@ static int gmac_clk_init(struct rk_priv_data *bsp_priv)
bsp_priv->mac_clk_rx = devm_clk_get(dev, "mac_clk_rx");
if (IS_ERR(bsp_priv->mac_clk_rx))
- dev_err(dev, "%s: cannot get clock %s\n",
- __func__, "mac_clk_rx");
+ dev_err(dev, "cannot get clock %s\n",
+ "mac_clk_rx");
bsp_priv->mac_clk_tx = devm_clk_get(dev, "mac_clk_tx");
if (IS_ERR(bsp_priv->mac_clk_tx))
- dev_err(dev, "%s: cannot get clock %s\n",
- __func__, "mac_clk_tx");
+ dev_err(dev, "cannot get clock %s\n",
+ "mac_clk_tx");
bsp_priv->aclk_mac = devm_clk_get(dev, "aclk_mac");
if (IS_ERR(bsp_priv->aclk_mac))
- dev_err(dev, "%s: cannot get clock %s\n",
- __func__, "aclk_mac");
+ dev_err(dev, "cannot get clock %s\n",
+ "aclk_mac");
bsp_priv->pclk_mac = devm_clk_get(dev, "pclk_mac");
if (IS_ERR(bsp_priv->pclk_mac))
- dev_err(dev, "%s: cannot get clock %s\n",
- __func__, "pclk_mac");
+ dev_err(dev, "cannot get clock %s\n",
+ "pclk_mac");
bsp_priv->clk_mac = devm_clk_get(dev, "stmmaceth");
if (IS_ERR(bsp_priv->clk_mac))
- dev_err(dev, "%s: cannot get clock %s\n",
- __func__, "stmmaceth");
+ dev_err(dev, "cannot get clock %s\n",
+ "stmmaceth");
if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) {
bsp_priv->clk_mac_ref = devm_clk_get(dev, "clk_mac_ref");
if (IS_ERR(bsp_priv->clk_mac_ref))
- dev_err(dev, "%s: cannot get clock %s\n",
- __func__, "clk_mac_ref");
+ dev_err(dev, "cannot get clock %s\n",
+ "clk_mac_ref");
if (!bsp_priv->clock_input) {
bsp_priv->clk_mac_refout =
devm_clk_get(dev, "clk_mac_refout");
if (IS_ERR(bsp_priv->clk_mac_refout))
- dev_err(dev, "%s: cannot get clock %s\n",
- __func__, "clk_mac_refout");
+ dev_err(dev, "cannot get clock %s\n",
+ "clk_mac_refout");
}
}
if (bsp_priv->clock_input) {
- dev_info(dev, "%s: clock input from PHY\n", __func__);
+ dev_info(dev, "clock input from PHY\n");
} else {
if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
- clk_set_rate(bsp_priv->clk_mac_pll, 50000000);
+ clk_set_rate(bsp_priv->clk_mac, 50000000);
}
return 0;
@@ -292,26 +430,25 @@ static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable)
struct device *dev = &bsp_priv->pdev->dev;
if (!ldo) {
- dev_err(dev, "%s: no regulator found\n", __func__);
+ dev_err(dev, "no regulator found\n");
return -1;
}
if (enable) {
ret = regulator_enable(ldo);
if (ret)
- dev_err(dev, "%s: fail to enable phy-supply\n",
- __func__);
+ dev_err(dev, "fail to enable phy-supply\n");
} else {
ret = regulator_disable(ldo);
if (ret)
- dev_err(dev, "%s: fail to disable phy-supply\n",
- __func__);
+ dev_err(dev, "fail to disable phy-supply\n");
}
return 0;
}
-static void *rk_gmac_setup(struct platform_device *pdev)
+static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
+ struct rk_gmac_ops *ops)
{
struct rk_priv_data *bsp_priv;
struct device *dev = &pdev->dev;
@@ -324,6 +461,7 @@ static void *rk_gmac_setup(struct platform_device *pdev)
return ERR_PTR(-ENOMEM);
bsp_priv->phy_iface = of_get_phy_mode(dev->of_node);
+ bsp_priv->ops = ops;
bsp_priv->regulator = devm_regulator_get_optional(dev, "phy");
if (IS_ERR(bsp_priv->regulator)) {
@@ -337,12 +475,11 @@ static void *rk_gmac_setup(struct platform_device *pdev)
ret = of_property_read_string(dev->of_node, "clock_in_out", &strings);
if (ret) {
- dev_err(dev, "%s: Can not read property: clock_in_out.\n",
- __func__);
+ dev_err(dev, "Can not read property: clock_in_out.\n");
bsp_priv->clock_input = true;
} else {
- dev_info(dev, "%s: clock input or output? (%s).\n",
- __func__, strings);
+ dev_info(dev, "clock input or output? (%s).\n",
+ strings);
if (!strcmp(strings, "input"))
bsp_priv->clock_input = true;
else
@@ -352,22 +489,22 @@ static void *rk_gmac_setup(struct platform_device *pdev)
ret = of_property_read_u32(dev->of_node, "tx_delay", &value);
if (ret) {
bsp_priv->tx_delay = 0x30;
- dev_err(dev, "%s: Can not read property: tx_delay.", __func__);
- dev_err(dev, "%s: set tx_delay to 0x%x\n",
- __func__, bsp_priv->tx_delay);
+ dev_err(dev, "Can not read property: tx_delay.");
+ dev_err(dev, "set tx_delay to 0x%x\n",
+ bsp_priv->tx_delay);
} else {
- dev_info(dev, "%s: TX delay(0x%x).\n", __func__, value);
+ dev_info(dev, "TX delay(0x%x).\n", value);
bsp_priv->tx_delay = value;
}
ret = of_property_read_u32(dev->of_node, "rx_delay", &value);
if (ret) {
bsp_priv->rx_delay = 0x10;
- dev_err(dev, "%s: Can not read property: rx_delay.", __func__);
- dev_err(dev, "%s: set rx_delay to 0x%x\n",
- __func__, bsp_priv->rx_delay);
+ dev_err(dev, "Can not read property: rx_delay.");
+ dev_err(dev, "set rx_delay to 0x%x\n",
+ bsp_priv->rx_delay);
} else {
- dev_info(dev, "%s: RX delay(0x%x).\n", __func__, value);
+ dev_info(dev, "RX delay(0x%x).\n", value);
bsp_priv->rx_delay = value;
}
@@ -377,13 +514,14 @@ static void *rk_gmac_setup(struct platform_device *pdev)
/*rmii or rgmii*/
if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) {
- dev_info(dev, "%s: init for RGMII\n", __func__);
- set_to_rgmii(bsp_priv, bsp_priv->tx_delay, bsp_priv->rx_delay);
+ dev_info(dev, "init for RGMII\n");
+ bsp_priv->ops->set_to_rgmii(bsp_priv, bsp_priv->tx_delay,
+ bsp_priv->rx_delay);
} else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) {
- dev_info(dev, "%s: init for RMII\n", __func__);
- set_to_rmii(bsp_priv);
+ dev_info(dev, "init for RMII\n");
+ bsp_priv->ops->set_to_rmii(bsp_priv);
} else {
- dev_err(dev, "%s: NO interface defined!\n", __func__);
+ dev_err(dev, "NO interface defined!\n");
}
gmac_clk_init(bsp_priv);
@@ -391,6 +529,16 @@ static void *rk_gmac_setup(struct platform_device *pdev)
return bsp_priv;
}
+static void *rk3288_gmac_setup(struct platform_device *pdev)
+{
+ return rk_gmac_setup(pdev, &rk3288_ops);
+}
+
+static void *rk3368_gmac_setup(struct platform_device *pdev)
+{
+ return rk_gmac_setup(pdev, &rk3368_ops);
+}
+
static int rk_gmac_init(struct platform_device *pdev, void *priv)
{
struct rk_priv_data *bsp_priv = priv;
@@ -421,17 +569,47 @@ static void rk_fix_speed(void *priv, unsigned int speed)
struct device *dev = &bsp_priv->pdev->dev;
if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII)
- set_rgmii_speed(bsp_priv, speed);
+ bsp_priv->ops->set_rgmii_speed(bsp_priv, speed);
else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
- set_rmii_speed(bsp_priv, speed);
+ bsp_priv->ops->set_rmii_speed(bsp_priv, speed);
else
dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface);
}
-const struct stmmac_of_data rk3288_gmac_data = {
+static const struct stmmac_of_data rk3288_gmac_data = {
.has_gmac = 1,
.fix_mac_speed = rk_fix_speed,
- .setup = rk_gmac_setup,
+ .setup = rk3288_gmac_setup,
.init = rk_gmac_init,
.exit = rk_gmac_exit,
};
+
+static const struct stmmac_of_data rk3368_gmac_data = {
+ .has_gmac = 1,
+ .fix_mac_speed = rk_fix_speed,
+ .setup = rk3368_gmac_setup,
+ .init = rk_gmac_init,
+ .exit = rk_gmac_exit,
+};
+
+static const struct of_device_id rk_gmac_dwmac_match[] = {
+ { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_gmac_data},
+ { .compatible = "rockchip,rk3368-gmac", .data = &rk3368_gmac_data},
+ { }
+};
+MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match);
+
+static struct platform_driver rk_gmac_dwmac_driver = {
+ .probe = stmmac_pltfr_probe,
+ .remove = stmmac_pltfr_remove,
+ .driver = {
+ .name = "rk_gmac-dwmac",
+ .pm = &stmmac_pltfr_pm_ops,
+ .of_match_table = rk_gmac_dwmac_match,
+ },
+};
+module_platform_driver(rk_gmac_dwmac_driver);
+
+MODULE_AUTHOR("Chen-Zhi (Roger Chen) <roger.chen@rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip RK3288 DWMAC specific glue layer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index 5a36bd2c7837..8141c5b844ae 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -257,9 +257,28 @@ static int socfpga_dwmac_init(struct platform_device *pdev, void *priv)
return ret;
}
-const struct stmmac_of_data socfpga_gmac_data = {
+static const struct stmmac_of_data socfpga_gmac_data = {
.setup = socfpga_dwmac_probe,
.init = socfpga_dwmac_init,
.exit = socfpga_dwmac_exit,
.fix_mac_speed = socfpga_dwmac_fix_mac_speed,
};
+
+static const struct of_device_id socfpga_dwmac_match[] = {
+ { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, socfpga_dwmac_match);
+
+static struct platform_driver socfpga_dwmac_driver = {
+ .probe = stmmac_pltfr_probe,
+ .remove = stmmac_pltfr_remove,
+ .driver = {
+ .name = "socfpga-dwmac",
+ .pm = &stmmac_pltfr_pm_ops,
+ .of_match_table = socfpga_dwmac_match,
+ },
+};
+module_platform_driver(socfpga_dwmac_driver);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
index bb6e2dc61bec..a2e8111c5d14 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
@@ -17,6 +17,7 @@
#include <linux/stmmac.h>
#include <linux/phy.h>
#include <linux/mfd/syscon.h>
+#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/clk.h>
#include <linux/of.h>
@@ -351,16 +352,40 @@ static void *sti_dwmac_setup(struct platform_device *pdev)
return dwmac;
}
-const struct stmmac_of_data stih4xx_dwmac_data = {
+static const struct stmmac_of_data stih4xx_dwmac_data = {
.fix_mac_speed = stih4xx_fix_retime_src,
.setup = sti_dwmac_setup,
.init = stix4xx_init,
.exit = sti_dwmac_exit,
};
-const struct stmmac_of_data stid127_dwmac_data = {
+static const struct stmmac_of_data stid127_dwmac_data = {
.fix_mac_speed = stid127_fix_retime_src,
.setup = sti_dwmac_setup,
.init = stid127_init,
.exit = sti_dwmac_exit,
};
+
+static const struct of_device_id sti_dwmac_match[] = {
+ { .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data},
+ { .compatible = "st,stih416-dwmac", .data = &stih4xx_dwmac_data},
+ { .compatible = "st,stid127-dwmac", .data = &stid127_dwmac_data},
+ { .compatible = "st,stih407-dwmac", .data = &stih4xx_dwmac_data},
+ { }
+};
+MODULE_DEVICE_TABLE(of, sti_dwmac_match);
+
+static struct platform_driver sti_dwmac_driver = {
+ .probe = stmmac_pltfr_probe,
+ .remove = stmmac_pltfr_remove,
+ .driver = {
+ .name = "sti-dwmac",
+ .pm = &stmmac_pltfr_pm_ops,
+ .of_match_table = sti_dwmac_match,
+ },
+};
+module_platform_driver(sti_dwmac_driver);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics DWMAC Specific Glue layer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
index c5ea9ab75b03..15048ca39759 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
@@ -18,7 +18,9 @@
#include <linux/stmmac.h>
#include <linux/clk.h>
+#include <linux/module.h>
#include <linux/phy.h>
+#include <linux/platform_device.h>
#include <linux/of_net.h>
#include <linux/regulator/consumer.h>
@@ -132,7 +134,7 @@ static void sun7i_fix_speed(void *priv, unsigned int speed)
/* of_data specifying hardware features and callbacks.
* hardware features were copied from Allwinner drivers. */
-const struct stmmac_of_data sun7i_gmac_data = {
+static const struct stmmac_of_data sun7i_gmac_data = {
.has_gmac = 1,
.tx_coe = 1,
.fix_mac_speed = sun7i_fix_speed,
@@ -140,3 +142,24 @@ const struct stmmac_of_data sun7i_gmac_data = {
.init = sun7i_gmac_init,
.exit = sun7i_gmac_exit,
};
+
+static const struct of_device_id sun7i_dwmac_match[] = {
+ { .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
+ { }
+};
+MODULE_DEVICE_TABLE(of, sun7i_dwmac_match);
+
+static struct platform_driver sun7i_dwmac_driver = {
+ .probe = stmmac_pltfr_probe,
+ .remove = stmmac_pltfr_remove,
+ .driver = {
+ .name = "sun7i-dwmac",
+ .pm = &stmmac_pltfr_pm_ops,
+ .of_match_table = sun7i_dwmac_match,
+ },
+};
+module_platform_driver(sun7i_dwmac_driver);
+
+MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
+MODULE_DESCRIPTION("Allwinner sunxi DWMAC specific glue layer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index 1e2bcf5f89e1..7d944449f5ef 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -240,6 +240,7 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
int mode, int end)
{
+ p->des01.all_flags = 0;
p->des01.erx.own = 1;
p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
@@ -254,7 +255,7 @@ static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
static void enh_desc_init_tx_desc(struct dma_desc *p, int mode, int end)
{
- p->des01.etx.own = 0;
+ p->des01.all_flags = 0;
if (mode == STMMAC_CHAIN_MODE)
ehn_desc_tx_set_on_chain(p, end);
else
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index 35ad4f427ae2..48c3456445b2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -123,6 +123,7 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
int end)
{
+ p->des01.all_flags = 0;
p->des01.rx.own = 1;
p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
@@ -137,7 +138,7 @@ static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end)
{
- p->des01.tx.own = 0;
+ p->des01.all_flags = 0;
if (mode == STMMAC_CHAIN_MODE)
ndesc_tx_set_on_chain(p, end);
else
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 73bab983edd9..1f3b33a6c6a8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -34,6 +34,14 @@
#include <linux/ptp_clock_kernel.h>
#include <linux/reset.h>
+struct stmmac_resources {
+ void __iomem *addr;
+ const char *mac;
+ int wol_irq;
+ int lpi_irq;
+ int irq;
+};
+
struct stmmac_tx_info {
dma_addr_t buf;
bool map_as_page;
@@ -135,9 +143,9 @@ void stmmac_ptp_unregister(struct stmmac_priv *priv);
int stmmac_resume(struct net_device *ndev);
int stmmac_suspend(struct net_device *ndev);
int stmmac_dvr_remove(struct net_device *ndev);
-struct stmmac_priv *stmmac_dvr_probe(struct device *device,
- struct plat_stmmacenet_data *plat_dat,
- void __iomem *addr);
+int stmmac_dvr_probe(struct device *device,
+ struct plat_stmmacenet_data *plat_dat,
+ struct stmmac_resources *res);
void stmmac_disable_eee_mode(struct stmmac_priv *priv);
bool stmmac_eee_init(struct stmmac_priv *priv);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 2c5ce2baca87..50f7a7a26821 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -52,6 +52,7 @@
#include "stmmac_ptp.h"
#include "stmmac.h"
#include <linux/reset.h>
+#include <linux/of_mdio.h>
#define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x)
@@ -816,18 +817,25 @@ static int stmmac_init_phy(struct net_device *dev)
priv->speed = 0;
priv->oldduplex = -1;
- if (priv->plat->phy_bus_name)
- snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x",
- priv->plat->phy_bus_name, priv->plat->bus_id);
- else
- snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x",
- priv->plat->bus_id);
+ if (priv->plat->phy_node) {
+ phydev = of_phy_connect(dev, priv->plat->phy_node,
+ &stmmac_adjust_link, 0, interface);
+ } else {
+ if (priv->plat->phy_bus_name)
+ snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x",
+ priv->plat->phy_bus_name, priv->plat->bus_id);
+ else
+ snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x",
+ priv->plat->bus_id);
- snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
- priv->plat->phy_addr);
- pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id_fmt);
+ snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
+ priv->plat->phy_addr);
+ pr_debug("stmmac_init_phy: trying to attach to %s\n",
+ phy_id_fmt);
- phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, interface);
+ phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link,
+ interface);
+ }
if (IS_ERR(phydev)) {
pr_err("%s: Could not attach to PHY\n", dev->name);
@@ -848,7 +856,7 @@ static int stmmac_init_phy(struct net_device *dev)
* device as well.
* Note: phydev->phy_id is the result of reading the UID PHY registers.
*/
- if (phydev->phy_id == 0) {
+ if (!priv->plat->phy_node && phydev->phy_id == 0) {
phy_disconnect(phydev);
return -ENODEV;
}
@@ -975,13 +983,11 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
{
struct sk_buff *skb;
- skb = __netdev_alloc_skb(priv->dev, priv->dma_buf_sz + NET_IP_ALIGN,
- flags);
+ skb = __netdev_alloc_skb_ip_align(priv->dev, priv->dma_buf_sz, flags);
if (!skb) {
pr_err("%s: Rx init fails; skb is NULL\n", __func__);
return -ENOMEM;
}
- skb_reserve(skb, NET_IP_ALIGN);
priv->rx_skbuff[i] = skb;
priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
priv->dma_buf_sz,
@@ -1189,41 +1195,41 @@ static int alloc_dma_desc_resources(struct stmmac_priv *priv)
goto err_tx_skbuff;
if (priv->extend_desc) {
- priv->dma_erx = dma_alloc_coherent(priv->device, rxsize *
- sizeof(struct
- dma_extended_desc),
- &priv->dma_rx_phy,
- GFP_KERNEL);
+ priv->dma_erx = dma_zalloc_coherent(priv->device, rxsize *
+ sizeof(struct
+ dma_extended_desc),
+ &priv->dma_rx_phy,
+ GFP_KERNEL);
if (!priv->dma_erx)
goto err_dma;
- priv->dma_etx = dma_alloc_coherent(priv->device, txsize *
- sizeof(struct
- dma_extended_desc),
- &priv->dma_tx_phy,
- GFP_KERNEL);
+ priv->dma_etx = dma_zalloc_coherent(priv->device, txsize *
+ sizeof(struct
+ dma_extended_desc),
+ &priv->dma_tx_phy,
+ GFP_KERNEL);
if (!priv->dma_etx) {
dma_free_coherent(priv->device, priv->dma_rx_size *
- sizeof(struct dma_extended_desc),
- priv->dma_erx, priv->dma_rx_phy);
+ sizeof(struct dma_extended_desc),
+ priv->dma_erx, priv->dma_rx_phy);
goto err_dma;
}
} else {
- priv->dma_rx = dma_alloc_coherent(priv->device, rxsize *
- sizeof(struct dma_desc),
- &priv->dma_rx_phy,
- GFP_KERNEL);
+ priv->dma_rx = dma_zalloc_coherent(priv->device, rxsize *
+ sizeof(struct dma_desc),
+ &priv->dma_rx_phy,
+ GFP_KERNEL);
if (!priv->dma_rx)
goto err_dma;
- priv->dma_tx = dma_alloc_coherent(priv->device, txsize *
- sizeof(struct dma_desc),
- &priv->dma_tx_phy,
- GFP_KERNEL);
+ priv->dma_tx = dma_zalloc_coherent(priv->device, txsize *
+ sizeof(struct dma_desc),
+ &priv->dma_tx_phy,
+ GFP_KERNEL);
if (!priv->dma_tx) {
dma_free_coherent(priv->device, priv->dma_rx_size *
- sizeof(struct dma_desc),
- priv->dma_rx, priv->dma_rx_phy);
+ sizeof(struct dma_desc),
+ priv->dma_rx, priv->dma_rx_phy);
goto err_dma;
}
}
@@ -2800,16 +2806,15 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
* stmmac_dvr_probe
* @device: device pointer
* @plat_dat: platform data pointer
- * @addr: iobase memory address
+ * @res: stmmac resource pointer
* Description: this is the main probe function used to
* call the alloc_etherdev, allocate the priv structure.
* Return:
- * on success the new private structure is returned, otherwise the error
- * pointer.
+ * returns 0 on success, otherwise errno.
*/
-struct stmmac_priv *stmmac_dvr_probe(struct device *device,
- struct plat_stmmacenet_data *plat_dat,
- void __iomem *addr)
+int stmmac_dvr_probe(struct device *device,
+ struct plat_stmmacenet_data *plat_dat,
+ struct stmmac_resources *res)
{
int ret = 0;
struct net_device *ndev = NULL;
@@ -2817,7 +2822,7 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
ndev = alloc_etherdev(sizeof(struct stmmac_priv));
if (!ndev)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
SET_NETDEV_DEV(ndev, device);
@@ -2828,8 +2833,17 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
stmmac_set_ethtool_ops(ndev);
priv->pause = pause;
priv->plat = plat_dat;
- priv->ioaddr = addr;
- priv->dev->base_addr = (unsigned long)addr;
+ priv->ioaddr = res->addr;
+ priv->dev->base_addr = (unsigned long)res->addr;
+
+ priv->dev->irq = res->irq;
+ priv->wol_irq = res->wol_irq;
+ priv->lpi_irq = res->lpi_irq;
+
+ if (res->mac)
+ memcpy(priv->dev->dev_addr, res->mac, ETH_ALEN);
+
+ dev_set_drvdata(device, priv);
/* Verify driver arguments */
stmmac_verify_args();
@@ -2944,7 +2958,7 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
}
}
- return priv;
+ return 0;
error_mdio_register:
unregister_netdev(ndev);
@@ -2957,7 +2971,7 @@ error_pclk_get:
error_clk_get:
free_netdev(ndev);
- return ERR_PTR(ret);
+ return ret;
}
EXPORT_SYMBOL_GPL(stmmac_dvr_probe);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index 3bca908716e2..d71a721ea61c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -163,7 +163,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
{
struct stmmac_pci_info *info = (struct stmmac_pci_info *)id->driver_data;
struct plat_stmmacenet_data *plat;
- struct stmmac_priv *priv;
+ struct stmmac_resources res;
int i;
int ret;
@@ -214,19 +214,12 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
pci_enable_msi(pdev);
- priv = stmmac_dvr_probe(&pdev->dev, plat, pcim_iomap_table(pdev)[i]);
- if (IS_ERR(priv)) {
- dev_err(&pdev->dev, "%s: main driver probe failed\n", __func__);
- return PTR_ERR(priv);
- }
- priv->dev->irq = pdev->irq;
- priv->wol_irq = pdev->irq;
-
- pci_set_drvdata(pdev, priv->dev);
+ memset(&res, 0, sizeof(res));
+ res.addr = pcim_iomap_table(pdev)[i];
+ res.wol_irq = pdev->irq;
+ res.irq = pdev->irq;
- dev_dbg(&pdev->dev, "STMMAC PCI driver registration completed\n");
-
- return 0;
+ return stmmac_dvr_probe(&pdev->dev, plat, &res);
}
/**
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 68aec5c460db..f3918c7e7eeb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -28,29 +28,11 @@
#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/of_device.h>
+#include <linux/of_mdio.h>
#include "stmmac.h"
#include "stmmac_platform.h"
-static const struct of_device_id stmmac_dt_ids[] = {
- /* SoC specific glue layers should come before generic bindings */
- { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_gmac_data},
- { .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data},
- { .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
- { .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data},
- { .compatible = "st,stih416-dwmac", .data = &stih4xx_dwmac_data},
- { .compatible = "st,stid127-dwmac", .data = &stid127_dwmac_data},
- { .compatible = "st,stih407-dwmac", .data = &stih4xx_dwmac_data},
- { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data },
- { .compatible = "st,spear600-gmac"},
- { .compatible = "snps,dwmac-3.610"},
- { .compatible = "snps,dwmac-3.70a"},
- { .compatible = "snps,dwmac-3.710"},
- { .compatible = "snps,dwmac"},
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, stmmac_dt_ids);
-
#ifdef CONFIG_OF
/**
@@ -129,14 +111,9 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
struct device_node *np = pdev->dev.of_node;
struct stmmac_dma_cfg *dma_cfg;
const struct of_device_id *device;
+ struct device *dev = &pdev->dev;
- if (!np)
- return -ENODEV;
-
- device = of_match_device(stmmac_dt_ids, &pdev->dev);
- if (!device)
- return -ENODEV;
-
+ device = of_match_device(dev->driver->of_match_table, dev);
if (device->data) {
const struct stmmac_of_data *data = device->data;
plat->has_gmac = data->has_gmac;
@@ -168,13 +145,24 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
/* Default to phy auto-detection */
plat->phy_addr = -1;
+ /* If we find a phy-handle property, use it as the PHY */
+ plat->phy_node = of_parse_phandle(np, "phy-handle", 0);
+
+ /* If phy-handle is not specified, check if we have a fixed-phy */
+ if (!plat->phy_node && of_phy_is_fixed_link(np)) {
+ if ((of_phy_register_fixed_link(np) < 0))
+ return -ENODEV;
+
+ plat->phy_node = of_node_get(np);
+ }
+
/* "snps,phy-addr" is not a standard property. Mark it as deprecated
* and warn of its use. Remove this when phy node support is added.
*/
if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
- if (plat->phy_bus_name)
+ if (plat->phy_node || plat->phy_bus_name)
plat->mdio_bus_data = NULL;
else
plat->mdio_bus_data =
@@ -232,8 +220,10 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
if (of_find_property(np, "snps,pbl", NULL)) {
dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
GFP_KERNEL);
- if (!dma_cfg)
+ if (!dma_cfg) {
+ of_node_put(np);
return -ENOMEM;
+ }
plat->dma_cfg = dma_cfg;
of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
dma_cfg->fixed_burst =
@@ -268,27 +258,26 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
* the necessary platform resources, invoke custom helper (if required) and
* invoke the main probe function.
*/
-static int stmmac_pltfr_probe(struct platform_device *pdev)
+int stmmac_pltfr_probe(struct platform_device *pdev)
{
+ struct stmmac_resources stmmac_res;
int ret = 0;
struct resource *res;
struct device *dev = &pdev->dev;
- void __iomem *addr = NULL;
- struct stmmac_priv *priv = NULL;
struct plat_stmmacenet_data *plat_dat = NULL;
- const char *mac = NULL;
- int irq, wol_irq, lpi_irq;
+
+ memset(&stmmac_res, 0, sizeof(stmmac_res));
/* Get IRQ information early to have an ability to ask for deferred
* probe if needed before we went too far with resource allocation.
*/
- irq = platform_get_irq_byname(pdev, "macirq");
- if (irq < 0) {
- if (irq != -EPROBE_DEFER) {
+ stmmac_res.irq = platform_get_irq_byname(pdev, "macirq");
+ if (stmmac_res.irq < 0) {
+ if (stmmac_res.irq != -EPROBE_DEFER) {
dev_err(dev,
"MAC IRQ configuration information not found\n");
}
- return irq;
+ return stmmac_res.irq;
}
/* On some platforms e.g. SPEAr the wake up irq differs from the mac irq
@@ -298,21 +287,21 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
* In case the wake up interrupt is not passed from the platform
* so the driver will continue to use the mac irq (ndev->irq)
*/
- wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
- if (wol_irq < 0) {
- if (wol_irq == -EPROBE_DEFER)
+ stmmac_res.wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
+ if (stmmac_res.wol_irq < 0) {
+ if (stmmac_res.wol_irq == -EPROBE_DEFER)
return -EPROBE_DEFER;
- wol_irq = irq;
+ stmmac_res.wol_irq = stmmac_res.irq;
}
- lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
- if (lpi_irq == -EPROBE_DEFER)
+ stmmac_res.lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
+ if (stmmac_res.lpi_irq == -EPROBE_DEFER)
return -EPROBE_DEFER;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- addr = devm_ioremap_resource(dev, res);
- if (IS_ERR(addr))
- return PTR_ERR(addr);
+ stmmac_res.addr = devm_ioremap_resource(dev, res);
+ if (IS_ERR(stmmac_res.addr))
+ return PTR_ERR(stmmac_res.addr);
plat_dat = dev_get_platdata(&pdev->dev);
@@ -332,7 +321,7 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
plat_dat->unicast_filter_entries = 1;
if (pdev->dev.of_node) {
- ret = stmmac_probe_config_dt(pdev, plat_dat, &mac);
+ ret = stmmac_probe_config_dt(pdev, plat_dat, &stmmac_res.mac);
if (ret) {
pr_err("%s: main dt probe failed", __func__);
return ret;
@@ -353,27 +342,9 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
return ret;
}
- priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr);
- if (IS_ERR(priv)) {
- pr_err("%s: main driver probe failed", __func__);
- return PTR_ERR(priv);
- }
-
- /* Copy IRQ values to priv structure which is now avaialble */
- priv->dev->irq = irq;
- priv->wol_irq = wol_irq;
- priv->lpi_irq = lpi_irq;
-
- /* Get MAC address if available (DT) */
- if (mac)
- memcpy(priv->dev->dev_addr, mac, ETH_ALEN);
-
- platform_set_drvdata(pdev, priv->dev);
-
- pr_debug("STMMAC platform driver registration completed");
-
- return 0;
+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
}
+EXPORT_SYMBOL_GPL(stmmac_pltfr_probe);
/**
* stmmac_pltfr_remove
@@ -381,7 +352,7 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
* Description: this function calls the main to free the net resources
* and calls the platforms hook and release the resources (e.g. mem).
*/
-static int stmmac_pltfr_remove(struct platform_device *pdev)
+int stmmac_pltfr_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct stmmac_priv *priv = netdev_priv(ndev);
@@ -395,6 +366,7 @@ static int stmmac_pltfr_remove(struct platform_device *pdev)
return ret;
}
+EXPORT_SYMBOL_GPL(stmmac_pltfr_remove);
#ifdef CONFIG_PM_SLEEP
/**
@@ -438,21 +410,6 @@ static int stmmac_pltfr_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
-static SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops,
- stmmac_pltfr_suspend, stmmac_pltfr_resume);
-
-static struct platform_driver stmmac_pltfr_driver = {
- .probe = stmmac_pltfr_probe,
- .remove = stmmac_pltfr_remove,
- .driver = {
- .name = STMMAC_RESOURCE_NAME,
- .pm = &stmmac_pltfr_pm_ops,
- .of_match_table = of_match_ptr(stmmac_dt_ids),
- },
-};
-
-module_platform_driver(stmmac_pltfr_driver);
-
-MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PLATFORM driver");
-MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
-MODULE_LICENSE("GPL");
+SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, stmmac_pltfr_suspend,
+ stmmac_pltfr_resume);
+EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
index 093eb99e5ffd..71da86d7bd00 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
@@ -19,11 +19,8 @@
#ifndef __STMMAC_PLATFORM_H__
#define __STMMAC_PLATFORM_H__
-extern const struct stmmac_of_data meson6_dwmac_data;
-extern const struct stmmac_of_data sun7i_gmac_data;
-extern const struct stmmac_of_data stih4xx_dwmac_data;
-extern const struct stmmac_of_data stid127_dwmac_data;
-extern const struct stmmac_of_data socfpga_gmac_data;
-extern const struct stmmac_of_data rk3288_gmac_data;
+int stmmac_pltfr_probe(struct platform_device *pdev);
+int stmmac_pltfr_remove(struct platform_device *pdev);
+extern const struct dev_pm_ops stmmac_pltfr_pm_ops;
#endif /* __STMMAC_PLATFORM_H__ */
diff --git a/drivers/net/ethernet/sun/Kconfig b/drivers/net/ethernet/sun/Kconfig
index 3074aa374c6b..dee94b67638c 100644
--- a/drivers/net/ethernet/sun/Kconfig
+++ b/drivers/net/ethernet/sun/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_SUN
default y
depends on SUN3 || SBUS || PCI || SUN_LDOMS
---help---
- If you have a network (Ethernet) card belonging to this class, say
- Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/tehuti/Kconfig b/drivers/net/ethernet/tehuti/Kconfig
index 1fc027eda33e..b17f0ca3f395 100644
--- a/drivers/net/ethernet/tehuti/Kconfig
+++ b/drivers/net/ethernet/tehuti/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_TEHUTI
default y
depends on PCI
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
index 631e0afd07d2..e7f0b7d95b65 100644
--- a/drivers/net/ethernet/ti/Kconfig
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_TI
default y
depends on PCI || EISA || AR7 || ARCH_DAVINCI || ARCH_OMAP2PLUS || ARCH_KEYSTONE
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
@@ -110,9 +108,7 @@ config TLAN
depends on (PCI || EISA)
---help---
If you have a PCI Ethernet network card based on the ThunderLAN chip
- which is supported by this driver, say Y and read the
- Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ which is supported by this driver, say Y here.
Devices currently supported by this driver are Compaq Netelligent,
Compaq NetFlex and Olicom cards. Please read the file
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index b536b4c82752..462820514fae 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1361,7 +1361,6 @@ static int cpsw_ndo_stop(struct net_device *ndev)
if (cpsw_common_res_usage_state(priv) <= 1) {
cpts_unregister(priv->cpts);
cpsw_intr_disable(priv);
- cpdma_ctlr_int_ctrl(priv->dma, false);
cpdma_ctlr_stop(priv->dma);
cpsw_ale_stop(priv->ale);
}
@@ -1456,7 +1455,7 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
if (priv->cpts->rx_enable)
ctrl |= CTRL_V2_RX_TS_BITS;
- break;
+ break;
case CPSW_VERSION_3:
default:
ctrl &= ~CTRL_V3_ALL_TS_MASK;
@@ -1466,7 +1465,7 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
if (priv->cpts->rx_enable)
ctrl |= CTRL_V3_RX_TS_BITS;
- break;
+ break;
}
mtype = (30 << TS_SEQ_ID_OFFSET_SHIFT) | EVENT_MSG_BITS;
@@ -1589,10 +1588,8 @@ static void cpsw_ndo_tx_timeout(struct net_device *ndev)
cpsw_err(priv, tx_err, "transmit timeout, restarting dma\n");
ndev->stats.tx_errors++;
cpsw_intr_disable(priv);
- cpdma_ctlr_int_ctrl(priv->dma, false);
cpdma_chan_stop(priv->txch);
cpdma_chan_start(priv->txch);
- cpdma_ctlr_int_ctrl(priv->dma, true);
cpsw_intr_enable(priv);
}
@@ -1629,10 +1626,8 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev)
struct cpsw_priv *priv = netdev_priv(ndev);
cpsw_intr_disable(priv);
- cpdma_ctlr_int_ctrl(priv->dma, false);
cpsw_rx_interrupt(priv->irqs_table[0], priv);
cpsw_tx_interrupt(priv->irqs_table[1], priv);
- cpdma_ctlr_int_ctrl(priv->dma, true);
cpsw_intr_enable(priv);
}
#endif
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index 6e927b4583aa..43b061bd8e07 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -268,39 +268,6 @@ int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid)
}
EXPORT_SYMBOL_GPL(cpsw_ale_flush_multicast);
-static void cpsw_ale_flush_ucast(struct cpsw_ale *ale, u32 *ale_entry,
- int port_mask)
-{
- int port;
-
- port = cpsw_ale_get_port_num(ale_entry);
- if ((BIT(port) & port_mask) == 0)
- return; /* ports dont intersect, not interested */
- cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
-}
-
-int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask)
-{
- u32 ale_entry[ALE_ENTRY_WORDS];
- int ret, idx;
-
- for (idx = 0; idx < ale->params.ale_entries; idx++) {
- cpsw_ale_read(ale, idx, ale_entry);
- ret = cpsw_ale_get_entry_type(ale_entry);
- if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR)
- continue;
-
- if (cpsw_ale_get_mcast(ale_entry))
- cpsw_ale_flush_mcast(ale, ale_entry, port_mask);
- else
- cpsw_ale_flush_ucast(ale, ale_entry, port_mask);
-
- cpsw_ale_write(ale, idx, ale_entry);
- }
- return 0;
-}
-EXPORT_SYMBOL_GPL(cpsw_ale_flush);
-
static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry,
int flags, u16 vid)
{
@@ -752,18 +719,6 @@ static void cpsw_ale_timer(unsigned long arg)
}
}
-int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout)
-{
- del_timer_sync(&ale->timer);
- ale->ageout = ageout * HZ;
- if (ale->ageout) {
- ale->timer.expires = jiffies + ale->ageout;
- add_timer(&ale->timer);
- }
- return 0;
-}
-EXPORT_SYMBOL_GPL(cpsw_ale_set_ageout);
-
void cpsw_ale_start(struct cpsw_ale *ale)
{
u32 rev;
diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h
index af1e7ecd87c6..a7001894f3da 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.h
+++ b/drivers/net/ethernet/ti/cpsw_ale.h
@@ -90,8 +90,6 @@ int cpsw_ale_destroy(struct cpsw_ale *ale);
void cpsw_ale_start(struct cpsw_ale *ale);
void cpsw_ale_stop(struct cpsw_ale *ale);
-int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout);
-int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask);
int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid);
int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
int flags, u16 vid);
diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c
index 43efc3a0cda5..5ec4ed3f6c8d 100644
--- a/drivers/net/ethernet/ti/netcp_core.c
+++ b/drivers/net/ethernet/ti/netcp_core.c
@@ -537,7 +537,7 @@ int netcp_unregister_rxhook(struct netcp_intf *netcp_priv, int order,
static void netcp_frag_free(bool is_frag, void *ptr)
{
if (is_frag)
- put_page(virt_to_head_page(ptr));
+ skb_free_frag(ptr);
else
kfree(ptr);
}
@@ -698,7 +698,6 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
}
}
- netcp->ndev->last_rx = jiffies;
netcp->ndev->stats.rx_packets++;
netcp->ndev->stats.rx_bytes += skb->len;
diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c
index 3d8f60d9643e..6f0a4495c7f3 100644
--- a/drivers/net/ethernet/tile/tilepro.c
+++ b/drivers/net/ethernet/tile/tilepro.c
@@ -721,9 +721,6 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
if (!hash_default)
__inv_buffer(buf, len);
- /* ISSUE: Is this needed? */
- dev->last_rx = jiffies;
-
#ifdef TILE_NET_DUMP_PACKETS
dump_packet(buf, len, "rx");
#endif /* TILE_NET_DUMP_PACKETS */
diff --git a/drivers/net/ethernet/toshiba/Kconfig b/drivers/net/ethernet/toshiba/Kconfig
index 5d244b6b5e3a..6f1d5b623768 100644
--- a/drivers/net/ethernet/toshiba/Kconfig
+++ b/drivers/net/ethernet/toshiba/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_TOSHIBA
default y
depends on PCI && (PPC_IBM_CELL_BLADE || MIPS) || PPC_PS3
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
index ac62a5e248b0..79f0ec4e51ac 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_net.c
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
@@ -102,6 +102,18 @@ static void gelic_card_get_ether_port_status(struct gelic_card *card,
}
}
+/**
+ * gelic_descr_get_status -- returns the status of a descriptor
+ * @descr: descriptor to look at
+ *
+ * returns the status as in the dmac_cmd_status field of the descriptor
+ */
+static enum gelic_descr_dma_status
+gelic_descr_get_status(struct gelic_descr *descr)
+{
+ return be32_to_cpu(descr->dmac_cmd_status) & GELIC_DESCR_DMA_STAT_MASK;
+}
+
static int gelic_card_set_link_mode(struct gelic_card *card, int mode)
{
int status;
@@ -278,18 +290,6 @@ void gelic_card_down(struct gelic_card *card)
}
/**
- * gelic_descr_get_status -- returns the status of a descriptor
- * @descr: descriptor to look at
- *
- * returns the status as in the dmac_cmd_status field of the descriptor
- */
-static enum gelic_descr_dma_status
-gelic_descr_get_status(struct gelic_descr *descr)
-{
- return be32_to_cpu(descr->dmac_cmd_status) & GELIC_DESCR_DMA_STAT_MASK;
-}
-
-/**
* gelic_card_free_chain - free descriptor chain
* @card: card structure
* @descr_in: address of desc
diff --git a/drivers/net/ethernet/toshiba/spider_net.c b/drivers/net/ethernet/toshiba/spider_net.c
index 8e9371a3388a..3c54a2cae5df 100644
--- a/drivers/net/ethernet/toshiba/spider_net.c
+++ b/drivers/net/ethernet/toshiba/spider_net.c
@@ -604,8 +604,7 @@ spider_net_set_multi(struct net_device *netdev)
int i;
u32 reg;
struct spider_net_card *card = netdev_priv(netdev);
- unsigned long bitmask[SPIDER_NET_MULTICAST_HASHES / BITS_PER_LONG] =
- {0, };
+ DECLARE_BITMAP(bitmask, SPIDER_NET_MULTICAST_HASHES) = {};
spider_net_set_promisc(card);
diff --git a/drivers/net/ethernet/tundra/Kconfig b/drivers/net/ethernet/tundra/Kconfig
index cf7d69b62c42..81d845e4e23b 100644
--- a/drivers/net/ethernet/tundra/Kconfig
+++ b/drivers/net/ethernet/tundra/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_TUNDRA
default y
depends on TSI108_BRIDGE
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/via/Kconfig b/drivers/net/ethernet/via/Kconfig
index f66ddaee0c87..8b0b1d6aca72 100644
--- a/drivers/net/ethernet/via/Kconfig
+++ b/drivers/net/ethernet/via/Kconfig
@@ -6,9 +6,7 @@ config NET_VENDOR_VIA
bool "VIA devices"
default y
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
@@ -19,7 +17,7 @@ if NET_VENDOR_VIA
config VIA_RHINE
tristate "VIA Rhine support"
- depends on (PCI || USE_OF)
+ depends on (PCI || OF_IRQ)
select CRC32
select MII
---help---
@@ -43,7 +41,7 @@ config VIA_RHINE_MMIO
config VIA_VELOCITY
tristate "VIA Velocity support"
- depends on (PCI || USE_OF)
+ depends on (PCI || (OF_ADDRESS && OF_IRQ))
select CRC32
select CRC_CCITT
select MII
diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c
index de2850497c09..a83263743665 100644
--- a/drivers/net/ethernet/via/via-rhine.c
+++ b/drivers/net/ethernet/via/via-rhine.c
@@ -96,7 +96,6 @@ static const int multicast_filter_limit = 32;
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
-#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
@@ -472,8 +471,7 @@ struct rhine_private {
/* Frequently used values: keep some adjacent for cache effect. */
u32 quirks;
- struct rx_desc *rx_head_desc;
- unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
+ unsigned int cur_rx;
unsigned int cur_tx, dirty_tx;
unsigned int rx_buf_sz; /* Based on MTU+slack. */
struct rhine_stats rx_stats;
@@ -1213,17 +1211,61 @@ static void free_ring(struct net_device* dev)
}
-static void alloc_rbufs(struct net_device *dev)
+struct rhine_skb_dma {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+};
+
+static inline int rhine_skb_dma_init(struct net_device *dev,
+ struct rhine_skb_dma *sd)
{
struct rhine_private *rp = netdev_priv(dev);
struct device *hwdev = dev->dev.parent;
- dma_addr_t next;
+ const int size = rp->rx_buf_sz;
+
+ sd->skb = netdev_alloc_skb(dev, size);
+ if (!sd->skb)
+ return -ENOMEM;
+
+ sd->dma = dma_map_single(hwdev, sd->skb->data, size, DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(hwdev, sd->dma))) {
+ netif_err(rp, drv, dev, "Rx DMA mapping failure\n");
+ dev_kfree_skb_any(sd->skb);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void rhine_reset_rbufs(struct rhine_private *rp)
+{
int i;
- rp->dirty_rx = rp->cur_rx = 0;
+ rp->cur_rx = 0;
+
+ for (i = 0; i < RX_RING_SIZE; i++)
+ rp->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
+}
+
+static inline void rhine_skb_dma_nic_store(struct rhine_private *rp,
+ struct rhine_skb_dma *sd, int entry)
+{
+ rp->rx_skbuff_dma[entry] = sd->dma;
+ rp->rx_skbuff[entry] = sd->skb;
+
+ rp->rx_ring[entry].addr = cpu_to_le32(sd->dma);
+ dma_wmb();
+}
+
+static void free_rbufs(struct net_device* dev);
+
+static int alloc_rbufs(struct net_device *dev)
+{
+ struct rhine_private *rp = netdev_priv(dev);
+ dma_addr_t next;
+ int rc, i;
rp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
- rp->rx_head_desc = &rp->rx_ring[0];
next = rp->rx_ring_dma;
/* Init the ring entries */
@@ -1239,23 +1281,20 @@ static void alloc_rbufs(struct net_device *dev)
/* Fill in the Rx buffers. Handle allocation failure gracefully. */
for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = netdev_alloc_skb(dev, rp->rx_buf_sz);
- rp->rx_skbuff[i] = skb;
- if (skb == NULL)
- break;
+ struct rhine_skb_dma sd;
- rp->rx_skbuff_dma[i] =
- dma_map_single(hwdev, skb->data, rp->rx_buf_sz,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(hwdev, rp->rx_skbuff_dma[i])) {
- rp->rx_skbuff_dma[i] = 0;
- dev_kfree_skb(skb);
- break;
+ rc = rhine_skb_dma_init(dev, &sd);
+ if (rc < 0) {
+ free_rbufs(dev);
+ goto out;
}
- rp->rx_ring[i].addr = cpu_to_le32(rp->rx_skbuff_dma[i]);
- rp->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
+
+ rhine_skb_dma_nic_store(rp, &sd, i);
}
- rp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+
+ rhine_reset_rbufs(rp);
+out:
+ return rc;
}
static void free_rbufs(struct net_device* dev)
@@ -1659,16 +1698,18 @@ static int rhine_open(struct net_device *dev)
rc = request_irq(rp->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev);
if (rc)
- return rc;
+ goto out;
netif_dbg(rp, ifup, dev, "%s() irq %d\n", __func__, rp->irq);
rc = alloc_ring(dev);
- if (rc) {
- free_irq(rp->irq, dev);
- return rc;
- }
- alloc_rbufs(dev);
+ if (rc < 0)
+ goto out_free_irq;
+
+ rc = alloc_rbufs(dev);
+ if (rc < 0)
+ goto out_free_ring;
+
alloc_tbufs(dev);
rhine_chip_reset(dev);
rhine_task_enable(rp);
@@ -1680,7 +1721,14 @@ static int rhine_open(struct net_device *dev)
netif_start_queue(dev);
- return 0;
+out:
+ return rc;
+
+out_free_ring:
+ free_ring(dev);
+out_free_irq:
+ free_irq(rp->irq, dev);
+ goto out;
}
static void rhine_reset_task(struct work_struct *work)
@@ -1700,9 +1748,9 @@ static void rhine_reset_task(struct work_struct *work)
/* clear all descriptors */
free_tbufs(dev);
- free_rbufs(dev);
alloc_tbufs(dev);
- alloc_rbufs(dev);
+
+ rhine_reset_rbufs(rp);
/* Reinitialize the hardware. */
rhine_chip_reset(dev);
@@ -1730,6 +1778,11 @@ static void rhine_tx_timeout(struct net_device *dev)
schedule_work(&rp->reset_task);
}
+static inline bool rhine_tx_queue_full(struct rhine_private *rp)
+{
+ return (rp->cur_tx - rp->dirty_tx) >= TX_QUEUE_LEN;
+}
+
static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
struct net_device *dev)
{
@@ -1800,11 +1853,17 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
netdev_sent_queue(dev, skb->len);
/* lock eth irq */
- wmb();
+ dma_wmb();
rp->tx_ring[entry].tx_status |= cpu_to_le32(DescOwn);
wmb();
rp->cur_tx++;
+ /*
+ * Nobody wants cur_tx write to rot for ages after the NIC will have
+ * seen the transmit request, especially as the transmit completion
+ * handler could miss it.
+ */
+ smp_wmb();
/* Non-x86 Todo: explicitly flush cache lines here. */
@@ -1817,8 +1876,14 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
ioaddr + ChipCmd1);
IOSYNC;
- if (rp->cur_tx == rp->dirty_tx + TX_QUEUE_LEN)
+ /* dirty_tx may be pessimistically out-of-sync. See rhine_tx. */
+ if (rhine_tx_queue_full(rp)) {
netif_stop_queue(dev);
+ smp_rmb();
+ /* Rejuvenate. */
+ if (!rhine_tx_queue_full(rp))
+ netif_wake_queue(dev);
+ }
netif_dbg(rp, tx_queued, dev, "Transmit frame #%d queued in slot %d\n",
rp->cur_tx - 1, entry);
@@ -1866,13 +1931,24 @@ static void rhine_tx(struct net_device *dev)
{
struct rhine_private *rp = netdev_priv(dev);
struct device *hwdev = dev->dev.parent;
- int txstatus = 0, entry = rp->dirty_tx % TX_RING_SIZE;
unsigned int pkts_compl = 0, bytes_compl = 0;
+ unsigned int dirty_tx = rp->dirty_tx;
+ unsigned int cur_tx;
struct sk_buff *skb;
+ /*
+ * The race with rhine_start_tx does not matter here as long as the
+ * driver enforces a value of cur_tx that was relevant when the
+ * packet was scheduled to the network chipset.
+ * Executive summary: smp_rmb() balances smp_wmb() in rhine_start_tx.
+ */
+ smp_rmb();
+ cur_tx = rp->cur_tx;
/* find and cleanup dirty tx descriptors */
- while (rp->dirty_tx != rp->cur_tx) {
- txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status);
+ while (dirty_tx != cur_tx) {
+ unsigned int entry = dirty_tx % TX_RING_SIZE;
+ u32 txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status);
+
netif_dbg(rp, tx_done, dev, "Tx scavenge %d status %08x\n",
entry, txstatus);
if (txstatus & DescOwn)
@@ -1921,12 +1997,23 @@ static void rhine_tx(struct net_device *dev)
pkts_compl++;
dev_consume_skb_any(skb);
rp->tx_skbuff[entry] = NULL;
- entry = (++rp->dirty_tx) % TX_RING_SIZE;
+ dirty_tx++;
}
+ rp->dirty_tx = dirty_tx;
+ /* Pity we can't rely on the nearby BQL completion implicit barrier. */
+ smp_wmb();
+
netdev_completed_queue(dev, pkts_compl, bytes_compl);
- if ((rp->cur_tx - rp->dirty_tx) < TX_QUEUE_LEN - 4)
+
+ /* cur_tx may be optimistically out-of-sync. See rhine_start_tx. */
+ if (!rhine_tx_queue_full(rp) && netif_queue_stopped(dev)) {
netif_wake_queue(dev);
+ smp_rmb();
+ /* Rejuvenate. */
+ if (rhine_tx_queue_full(rp))
+ netif_stop_queue(dev);
+ }
}
/**
@@ -1944,22 +2031,33 @@ static inline u16 rhine_get_vlan_tci(struct sk_buff *skb, int data_size)
return be16_to_cpup((__be16 *)trailer);
}
+static inline void rhine_rx_vlan_tag(struct sk_buff *skb, struct rx_desc *desc,
+ int data_size)
+{
+ dma_rmb();
+ if (unlikely(desc->desc_length & cpu_to_le32(DescTag))) {
+ u16 vlan_tci;
+
+ vlan_tci = rhine_get_vlan_tci(skb, data_size);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci);
+ }
+}
+
/* Process up to limit frames from receive ring */
static int rhine_rx(struct net_device *dev, int limit)
{
struct rhine_private *rp = netdev_priv(dev);
struct device *hwdev = dev->dev.parent;
- int count;
int entry = rp->cur_rx % RX_RING_SIZE;
+ int count;
netif_dbg(rp, rx_status, dev, "%s(), entry %d status %08x\n", __func__,
- entry, le32_to_cpu(rp->rx_head_desc->rx_status));
+ entry, le32_to_cpu(rp->rx_ring[entry].rx_status));
/* If EOP is set on the next entry, it's a new packet. Send it up. */
for (count = 0; count < limit; ++count) {
- struct rx_desc *desc = rp->rx_head_desc;
+ struct rx_desc *desc = rp->rx_ring + entry;
u32 desc_status = le32_to_cpu(desc->rx_status);
- u32 desc_length = le32_to_cpu(desc->desc_length);
int data_size = desc_status >> 16;
if (desc_status & DescOwn)
@@ -1975,10 +2073,6 @@ static int rhine_rx(struct net_device *dev, int limit)
"entry %#x length %d status %08x!\n",
entry, data_size,
desc_status);
- netdev_warn(dev,
- "Oversized Ethernet frame %p vs %p\n",
- rp->rx_head_desc,
- &rp->rx_ring[entry]);
dev->stats.rx_length_errors++;
} else if (desc_status & RxErr) {
/* There was a error. */
@@ -2000,16 +2094,17 @@ static int rhine_rx(struct net_device *dev, int limit)
}
}
} else {
- struct sk_buff *skb = NULL;
/* Length should omit the CRC */
int pkt_len = data_size - 4;
- u16 vlan_tci = 0;
+ struct sk_buff *skb;
/* Check if the packet is long enough to accept without
copying to a minimally-sized skbuff. */
- if (pkt_len < rx_copybreak)
+ if (pkt_len < rx_copybreak) {
skb = netdev_alloc_skb_ip_align(dev, pkt_len);
- if (skb) {
+ if (unlikely(!skb))
+ goto drop;
+
dma_sync_single_for_cpu(hwdev,
rp->rx_skbuff_dma[entry],
rp->rx_buf_sz,
@@ -2018,32 +2113,31 @@ static int rhine_rx(struct net_device *dev, int limit)
skb_copy_to_linear_data(skb,
rp->rx_skbuff[entry]->data,
pkt_len);
- skb_put(skb, pkt_len);
+
dma_sync_single_for_device(hwdev,
rp->rx_skbuff_dma[entry],
rp->rx_buf_sz,
DMA_FROM_DEVICE);
} else {
+ struct rhine_skb_dma sd;
+
+ if (unlikely(rhine_skb_dma_init(dev, &sd) < 0))
+ goto drop;
+
skb = rp->rx_skbuff[entry];
- if (skb == NULL) {
- netdev_err(dev, "Inconsistent Rx descriptor chain\n");
- break;
- }
- rp->rx_skbuff[entry] = NULL;
- skb_put(skb, pkt_len);
+
dma_unmap_single(hwdev,
rp->rx_skbuff_dma[entry],
rp->rx_buf_sz,
DMA_FROM_DEVICE);
+ rhine_skb_dma_nic_store(rp, &sd, entry);
}
- if (unlikely(desc_length & DescTag))
- vlan_tci = rhine_get_vlan_tci(skb, data_size);
-
+ skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, dev);
- if (unlikely(desc_length & DescTag))
- __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci);
+ rhine_rx_vlan_tag(skb, desc, data_size);
+
netif_receive_skb(skb);
u64_stats_update_begin(&rp->rx_stats.syncp);
@@ -2051,35 +2145,16 @@ static int rhine_rx(struct net_device *dev, int limit)
rp->rx_stats.packets++;
u64_stats_update_end(&rp->rx_stats.syncp);
}
+give_descriptor_to_nic:
+ desc->rx_status = cpu_to_le32(DescOwn);
entry = (++rp->cur_rx) % RX_RING_SIZE;
- rp->rx_head_desc = &rp->rx_ring[entry];
- }
-
- /* Refill the Rx ring buffers. */
- for (; rp->cur_rx - rp->dirty_rx > 0; rp->dirty_rx++) {
- struct sk_buff *skb;
- entry = rp->dirty_rx % RX_RING_SIZE;
- if (rp->rx_skbuff[entry] == NULL) {
- skb = netdev_alloc_skb(dev, rp->rx_buf_sz);
- rp->rx_skbuff[entry] = skb;
- if (skb == NULL)
- break; /* Better luck next round. */
- rp->rx_skbuff_dma[entry] =
- dma_map_single(hwdev, skb->data,
- rp->rx_buf_sz,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(hwdev,
- rp->rx_skbuff_dma[entry])) {
- dev_kfree_skb(skb);
- rp->rx_skbuff_dma[entry] = 0;
- break;
- }
- rp->rx_ring[entry].addr = cpu_to_le32(rp->rx_skbuff_dma[entry]);
- }
- rp->rx_ring[entry].rx_status = cpu_to_le32(DescOwn);
}
return count;
+
+drop:
+ dev->stats.rx_dropped++;
+ goto give_descriptor_to_nic;
}
static void rhine_restart_tx(struct net_device *dev) {
@@ -2484,9 +2559,8 @@ static int rhine_resume(struct device *device)
enable_mmio(rp->pioaddr, rp->quirks);
rhine_power_init(dev);
free_tbufs(dev);
- free_rbufs(dev);
alloc_tbufs(dev);
- alloc_rbufs(dev);
+ rhine_reset_rbufs(rp);
rhine_task_enable(rp);
spin_lock_bh(&rp->lock);
init_registers(dev);
diff --git a/drivers/net/ethernet/wiznet/Kconfig b/drivers/net/ethernet/wiznet/Kconfig
index b4d281626fb4..f98b91d21f33 100644
--- a/drivers/net/ethernet/wiznet/Kconfig
+++ b/drivers/net/ethernet/wiznet/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_WIZNET
depends on HAS_IOMEM
default y
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index 7b90a5eba099..4f5c024c6192 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_XILINX
default y
depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index af2694dc6f90..5a1068df7038 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -62,12 +62,12 @@
u32 temac_ior(struct temac_local *lp, int offset)
{
- return in_be32((u32 *)(lp->regs + offset));
+ return in_be32(lp->regs + offset);
}
void temac_iow(struct temac_local *lp, int offset, u32 value)
{
- out_be32((u32 *) (lp->regs + offset), value);
+ out_be32(lp->regs + offset, value);
}
int temac_indirect_busywait(struct temac_local *lp)
@@ -124,7 +124,7 @@ void temac_indirect_out32(struct temac_local *lp, int reg, u32 value)
*/
static u32 temac_dma_in32(struct temac_local *lp, int reg)
{
- return in_be32((u32 *)(lp->sdma_regs + (reg << 2)));
+ return in_be32(lp->sdma_regs + (reg << 2));
}
/**
@@ -134,7 +134,7 @@ static u32 temac_dma_in32(struct temac_local *lp, int reg)
*/
static void temac_dma_out32(struct temac_local *lp, int reg, u32 value)
{
- out_be32((u32 *)(lp->sdma_regs + (reg << 2)), value);
+ out_be32(lp->sdma_regs + (reg << 2), value);
}
/* DMA register access functions can be DCR based or memory mapped.
@@ -400,7 +400,7 @@ static void temac_set_multicast_list(struct net_device *ndev)
mutex_unlock(&lp->indirect_mutex);
}
-struct temac_option {
+static struct temac_option {
int flg;
u32 opt;
u32 reg;
@@ -587,7 +587,7 @@ static void temac_device_reset(struct net_device *ndev)
ndev->trans_start = jiffies; /* prevent tx timeout */
}
-void temac_adjust_link(struct net_device *ndev)
+static void temac_adjust_link(struct net_device *ndev)
{
struct temac_local *lp = netdev_priv(ndev);
struct phy_device *phy = lp->phy_dev;
@@ -688,10 +688,8 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
if (temac_check_tx_bd_space(lp, num_frag)) {
- if (!netif_queue_stopped(ndev)) {
+ if (!netif_queue_stopped(ndev))
netif_stop_queue(ndev);
- return NETDEV_TX_BUSY;
- }
return NETDEV_TX_BUSY;
}
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 4c9b4fa1d3c1..7cb9abac95c8 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -11,16 +11,16 @@
#include <linux/netdevice.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
+#include <linux/if_vlan.h>
/* Packet size info */
#define XAE_HDR_SIZE 14 /* Size of Ethernet header */
-#define XAE_HDR_VLAN_SIZE 18 /* Size of an Ethernet hdr + VLAN */
#define XAE_TRL_SIZE 4 /* Size of Ethernet trailer (FCS) */
#define XAE_MTU 1500 /* Max MTU of an Ethernet frame */
#define XAE_JUMBO_MTU 9000 /* Max MTU of a jumbo Eth. frame */
#define XAE_MAX_FRAME_SIZE (XAE_MTU + XAE_HDR_SIZE + XAE_TRL_SIZE)
-#define XAE_MAX_VLAN_FRAME_SIZE (XAE_MTU + XAE_HDR_VLAN_SIZE + XAE_TRL_SIZE)
+#define XAE_MAX_VLAN_FRAME_SIZE (XAE_MTU + VLAN_ETH_HLEN + XAE_TRL_SIZE)
#define XAE_MAX_JUMBO_FRAME_SIZE (XAE_JUMBO_MTU + XAE_HDR_SIZE + XAE_TRL_SIZE)
/* Configuration options */
@@ -38,18 +38,21 @@
#define XAE_OPTION_FLOW_CONTROL (1 << 4)
/* Strip FCS and PAD from incoming frames. Note: PAD from VLAN frames is not
- * stripped. Default: disabled (set) */
+ * stripped. Default: disabled (set)
+ */
#define XAE_OPTION_FCS_STRIP (1 << 5)
/* Generate FCS field and add PAD automatically for outgoing frames.
- * Default: enabled (set) */
+ * Default: enabled (set)
+ */
#define XAE_OPTION_FCS_INSERT (1 << 6)
/* Enable Length/Type error checking for incoming frames. When this option is
* set, the MAC will filter frames that have a mismatched type/length field
* and if XAE_OPTION_REPORT_RXERR is set, the user is notified when these
* types of frames are encountered. When this option is cleared, the MAC will
- * allow these types of frames to be received. Default: enabled (set) */
+ * allow these types of frames to be received. Default: enabled (set)
+ */
#define XAE_OPTION_LENTYPE_ERR (1 << 7)
/* Enable the transmitter. Default: enabled (set) */
@@ -159,12 +162,12 @@
#define XAE_MDIO_MWD_OFFSET 0x00000508 /* MII Management Write Data */
#define XAE_MDIO_MRD_OFFSET 0x0000050C /* MII Management Read Data */
#define XAE_MDIO_MIS_OFFSET 0x00000600 /* MII Management Interrupt Status */
-#define XAE_MDIO_MIP_OFFSET 0x00000620 /* MII Mgmt Interrupt Pending
- * register offset */
-#define XAE_MDIO_MIE_OFFSET 0x00000640 /* MII Management Interrupt Enable
- * register offset */
-#define XAE_MDIO_MIC_OFFSET 0x00000660 /* MII Management Interrupt Clear
- * register offset. */
+/* MII Mgmt Interrupt Pending register offset */
+#define XAE_MDIO_MIP_OFFSET 0x00000620
+/* MII Management Interrupt Enable register offset */
+#define XAE_MDIO_MIE_OFFSET 0x00000640
+/* MII Management Interrupt Clear register offset. */
+#define XAE_MDIO_MIC_OFFSET 0x00000660
#define XAE_UAW0_OFFSET 0x00000700 /* Unicast address word 0 */
#define XAE_UAW1_OFFSET 0x00000704 /* Unicast address word 1 */
#define XAE_FMI_OFFSET 0x00000708 /* Filter Mask Index */
@@ -176,18 +179,17 @@
#define XAE_MCAST_TABLE_OFFSET 0x00020000 /* Multicast table address */
/* Bit Masks for Axi Ethernet RAF register */
-#define XAE_RAF_MCSTREJ_MASK 0x00000002 /* Reject receive multicast
- * destination address */
-#define XAE_RAF_BCSTREJ_MASK 0x00000004 /* Reject receive broadcast
- * destination address */
+/* Reject receive multicast destination address */
+#define XAE_RAF_MCSTREJ_MASK 0x00000002
+/* Reject receive broadcast destination address */
+#define XAE_RAF_BCSTREJ_MASK 0x00000004
#define XAE_RAF_TXVTAGMODE_MASK 0x00000018 /* Tx VLAN TAG mode */
#define XAE_RAF_RXVTAGMODE_MASK 0x00000060 /* Rx VLAN TAG mode */
#define XAE_RAF_TXVSTRPMODE_MASK 0x00000180 /* Tx VLAN STRIP mode */
#define XAE_RAF_RXVSTRPMODE_MASK 0x00000600 /* Rx VLAN STRIP mode */
#define XAE_RAF_NEWFNCENBL_MASK 0x00000800 /* New function mode */
-#define XAE_RAF_EMULTIFLTRENBL_MASK 0x00001000 /* Exteneded Multicast
- * Filtering mode
- */
+/* Exteneded Multicast Filtering mode */
+#define XAE_RAF_EMULTIFLTRENBL_MASK 0x00001000
#define XAE_RAF_STATSRST_MASK 0x00002000 /* Stats. Counter Reset */
#define XAE_RAF_RXBADFRMEN_MASK 0x00004000 /* Recv Bad Frame Enable */
#define XAE_RAF_TXVTAGMODE_SHIFT 3 /* Tx Tag mode shift bits */
@@ -197,15 +199,16 @@
/* Bit Masks for Axi Ethernet TPF and IFGP registers */
#define XAE_TPF_TPFV_MASK 0x0000FFFF /* Tx pause frame value */
-#define XAE_IFGP0_IFGP_MASK 0x0000007F /* Transmit inter-frame
- * gap adjustment value */
+/* Transmit inter-frame gap adjustment value */
+#define XAE_IFGP0_IFGP_MASK 0x0000007F
/* Bit Masks for Axi Ethernet IS, IE and IP registers, Same masks apply
- * for all 3 registers. */
-#define XAE_INT_HARDACSCMPLT_MASK 0x00000001 /* Hard register access
- * complete */
-#define XAE_INT_AUTONEG_MASK 0x00000002 /* Auto negotiation
- * complete */
+ * for all 3 registers.
+ */
+/* Hard register access complete */
+#define XAE_INT_HARDACSCMPLT_MASK 0x00000001
+/* Auto negotiation complete */
+#define XAE_INT_AUTONEG_MASK 0x00000002
#define XAE_INT_RXCMPIT_MASK 0x00000004 /* Rx complete */
#define XAE_INT_RXRJECT_MASK 0x00000008 /* Rx frame rejected */
#define XAE_INT_RXFIFOOVR_MASK 0x00000010 /* Rx fifo overrun */
@@ -215,10 +218,9 @@
#define XAE_INT_PHYRSTCMPLT_MASK 0x00000100 /* Phy Reset complete */
#define XAE_INT_ALL_MASK 0x0000003F /* All the ints */
+/* INT bits that indicate receive errors */
#define XAE_INT_RECV_ERROR_MASK \
- (XAE_INT_RXRJECT_MASK | XAE_INT_RXFIFOOVR_MASK) /* INT bits that
- * indicate receive
- * errors */
+ (XAE_INT_RXRJECT_MASK | XAE_INT_RXFIFOOVR_MASK)
/* Bit masks for Axi Ethernet VLAN TPID Word 0 register */
#define XAE_TPID_0_MASK 0x0000FFFF /* TPID 0 */
@@ -231,27 +233,28 @@
/* Bit masks for Axi Ethernet RCW1 register */
#define XAE_RCW1_RST_MASK 0x80000000 /* Reset */
#define XAE_RCW1_JUM_MASK 0x40000000 /* Jumbo frame enable */
-#define XAE_RCW1_FCS_MASK 0x20000000 /* In-Band FCS enable
- * (FCS not stripped) */
+/* In-Band FCS enable (FCS not stripped) */
+#define XAE_RCW1_FCS_MASK 0x20000000
#define XAE_RCW1_RX_MASK 0x10000000 /* Receiver enable */
#define XAE_RCW1_VLAN_MASK 0x08000000 /* VLAN frame enable */
-#define XAE_RCW1_LT_DIS_MASK 0x02000000 /* Length/type field valid check
- * disable */
-#define XAE_RCW1_CL_DIS_MASK 0x01000000 /* Control frame Length check
- * disable */
-#define XAE_RCW1_PAUSEADDR_MASK 0x0000FFFF /* Pause frame source address
- * bits [47:32]. Bits [31:0] are
- * stored in register RCW0 */
+/* Length/type field valid check disable */
+#define XAE_RCW1_LT_DIS_MASK 0x02000000
+/* Control frame Length check disable */
+#define XAE_RCW1_CL_DIS_MASK 0x01000000
+/* Pause frame source address bits [47:32]. Bits [31:0] are
+ * stored in register RCW0
+ */
+#define XAE_RCW1_PAUSEADDR_MASK 0x0000FFFF
/* Bit masks for Axi Ethernet TC register */
#define XAE_TC_RST_MASK 0x80000000 /* Reset */
#define XAE_TC_JUM_MASK 0x40000000 /* Jumbo frame enable */
-#define XAE_TC_FCS_MASK 0x20000000 /* In-Band FCS enable
- * (FCS not generated) */
+/* In-Band FCS enable (FCS not generated) */
+#define XAE_TC_FCS_MASK 0x20000000
#define XAE_TC_TX_MASK 0x10000000 /* Transmitter enable */
#define XAE_TC_VLAN_MASK 0x08000000 /* VLAN frame enable */
-#define XAE_TC_IFG_MASK 0x02000000 /* Inter-frame gap adjustment
- * enable */
+/* Inter-frame gap adjustment enable */
+#define XAE_TC_IFG_MASK 0x02000000
/* Bit masks for Axi Ethernet FCC register */
#define XAE_FCC_FCRX_MASK 0x20000000 /* Rx flow control enable */
@@ -301,10 +304,10 @@
#define XAE_MDIO_INT_MIIM_RDY_MASK 0x00000001 /* MIIM Interrupt */
/* Bit masks for Axi Ethernet UAW1 register */
-#define XAE_UAW1_UNICASTADDR_MASK 0x0000FFFF /* Station address bits
- * [47:32]; Station address
- * bits [31:0] are stored in
- * register UAW0 */
+/* Station address bits [47:32]; Station address
+ * bits [31:0] are stored in register UAW0
+ */
+#define XAE_UAW1_UNICASTADDR_MASK 0x0000FFFF
/* Bit masks for Axi Ethernet FMI register */
#define XAE_FMI_PM_MASK 0x80000000 /* Promis. mode enable */
@@ -320,8 +323,8 @@
#define XAE_PHY_TYPE_SGMII 4
#define XAE_PHY_TYPE_1000BASE_X 5
-#define XAE_MULTICAST_CAM_TABLE_NUM 4 /* Total number of entries in the
- * hardware multicast table. */
+ /* Total number of entries in the hardware multicast table. */
+#define XAE_MULTICAST_CAM_TABLE_NUM 4
/* Axi Ethernet Synthesis features */
#define XAE_FEATURE_PARTIAL_RX_CSUM (1 << 0)
@@ -407,8 +410,11 @@ struct axidma_bd {
* Txed/Rxed in the existing hardware. If jumbo option is
* supported, the maximum frame size would be 9k. Else it is
* 1522 bytes (assuming support for basic VLAN)
- * @jumbo_support: Stores hardware configuration for jumbo support. If hardware
- * can handle jumbo packets, this entry will be 1, else 0.
+ * @rxmem: Stores rx memory size for jumbo frame handling.
+ * @csum_offload_on_tx_path: Stores the checksum selection on TX side.
+ * @csum_offload_on_rx_path: Stores the checksum selection on RX side.
+ * @coalesce_count_rx: Store the irq coalesce on RX side.
+ * @coalesce_count_tx: Store the irq coalesce on TX side.
*/
struct axienet_local {
struct net_device *ndev;
@@ -446,7 +452,7 @@ struct axienet_local {
u32 rx_bd_ci;
u32 max_frm_size;
- u32 jumbo_support;
+ u32 rxmem;
int csum_offload_on_tx_path;
int csum_offload_on_rx_path;
@@ -472,7 +478,7 @@ struct axienet_option {
* @lp: Pointer to axienet local structure
* @offset: Address offset from the base address of Axi Ethernet core
*
- * returns: The contents of the Axi Ethernet register
+ * Return: The contents of the Axi Ethernet register
*
* This function returns the contents of the corresponding register.
*/
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 28b7e7d9c272..4208dd7ef101 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -117,7 +117,7 @@ static struct axienet_option axienet_options[] = {
* @lp: Pointer to axienet local structure
* @reg: Address offset from the base address of the Axi DMA core
*
- * returns: The contents of the Axi DMA register
+ * Return: The contents of the Axi DMA register
*
* This function returns the contents of the corresponding Axi DMA register.
*/
@@ -179,8 +179,7 @@ static void axienet_dma_bd_release(struct net_device *ndev)
* axienet_dma_bd_init - Setup buffer descriptor rings for Axi DMA
* @ndev: Pointer to the net_device structure
*
- * returns: 0, on success
- * -ENOMEM, on failure
+ * Return: 0, on success -ENOMEM, on failure
*
* This function is called to initialize the Rx and Tx DMA descriptor
* rings. This initializes the descriptors with required default values
@@ -198,9 +197,7 @@ static int axienet_dma_bd_init(struct net_device *ndev)
lp->tx_bd_tail = 0;
lp->rx_bd_ci = 0;
- /*
- * Allocate the Tx and Rx buffer descriptors.
- */
+ /* Allocate the Tx and Rx buffer descriptors. */
lp->tx_bd_v = dma_zalloc_coherent(ndev->dev.parent,
sizeof(*lp->tx_bd_v) * TX_BD_NUM,
&lp->tx_bd_p, GFP_KERNEL);
@@ -263,7 +260,8 @@ static int axienet_dma_bd_init(struct net_device *ndev)
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr);
/* Populate the tail pointer and bring the Rx Axi DMA engine out of
- * halted state. This will make the Rx side ready for reception.*/
+ * halted state. This will make the Rx side ready for reception.
+ */
axienet_dma_out32(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p);
cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET,
@@ -273,7 +271,8 @@ static int axienet_dma_bd_init(struct net_device *ndev)
/* Write to the RS (Run-stop) bit in the Tx channel control register.
* Tx channel is now ready to run. But only after we write to the
- * tail pointer register that the Tx channel will start transmitting */
+ * tail pointer register that the Tx channel will start transmitting.
+ */
axienet_dma_out32(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p);
cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET,
@@ -320,7 +319,7 @@ static void axienet_set_mac_address(struct net_device *ndev, void *address)
* @ndev: Pointer to the net_device structure
* @p: 6 byte Address to be written as MAC address
*
- * returns: 0 for all conditions. Presently, there is no failure case.
+ * Return: 0 for all conditions. Presently, there is no failure case.
*
* This function is called to initialize the MAC address of the Axi Ethernet
* core. It calls the core specific axienet_set_mac_address. This is the
@@ -354,7 +353,8 @@ static void axienet_set_multicast_list(struct net_device *ndev)
netdev_mc_count(ndev) > XAE_MULTICAST_CAM_TABLE_NUM) {
/* We must make the kernel realize we had to move into
* promiscuous mode. If it was a promiscuous mode request
- * the flag is already set. If not we set it. */
+ * the flag is already set. If not we set it.
+ */
ndev->flags |= IFF_PROMISC;
reg = axienet_ior(lp, XAE_FMI_OFFSET);
reg |= XAE_FMI_PM_MASK;
@@ -438,14 +438,15 @@ static void __axienet_device_reset(struct axienet_local *lp,
/* Reset Axi DMA. This would reset Axi Ethernet core as well. The reset
* process of Axi DMA takes a while to complete as all pending
* commands/transfers will be flushed or completed during this
- * reset process. */
+ * reset process.
+ */
axienet_dma_out32(lp, offset, XAXIDMA_CR_RESET_MASK);
timeout = DELAY_OF_ONE_MILLISEC;
while (axienet_dma_in32(lp, offset) & XAXIDMA_CR_RESET_MASK) {
udelay(1);
if (--timeout == 0) {
- dev_err(dev, "axienet_device_reset DMA "
- "reset timeout!\n");
+ netdev_err(lp->ndev, "%s: DMA reset timeout!\n",
+ __func__);
break;
}
}
@@ -471,19 +472,21 @@ static void axienet_device_reset(struct net_device *ndev)
__axienet_device_reset(lp, &ndev->dev, XAXIDMA_RX_CR_OFFSET);
lp->max_frm_size = XAE_MAX_VLAN_FRAME_SIZE;
+ lp->options |= XAE_OPTION_VLAN;
lp->options &= (~XAE_OPTION_JUMBO);
if ((ndev->mtu > XAE_MTU) &&
- (ndev->mtu <= XAE_JUMBO_MTU) &&
- (lp->jumbo_support)) {
- lp->max_frm_size = ndev->mtu + XAE_HDR_VLAN_SIZE +
- XAE_TRL_SIZE;
- lp->options |= XAE_OPTION_JUMBO;
+ (ndev->mtu <= XAE_JUMBO_MTU)) {
+ lp->max_frm_size = ndev->mtu + VLAN_ETH_HLEN +
+ XAE_TRL_SIZE;
+
+ if (lp->max_frm_size <= lp->rxmem)
+ lp->options |= XAE_OPTION_JUMBO;
}
if (axienet_dma_bd_init(ndev)) {
- dev_err(&ndev->dev, "axienet_device_reset descriptor "
- "allocation failed\n");
+ netdev_err(ndev, "%s: descriptor allocation failed\n",
+ __func__);
}
axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET);
@@ -497,7 +500,8 @@ static void axienet_device_reset(struct net_device *ndev)
axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
/* Sync default options with HW but leave receiver and
- * transmitter disabled.*/
+ * transmitter disabled.
+ */
axienet_setoptions(ndev, lp->options &
~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
axienet_set_mac_address(ndev, NULL);
@@ -558,8 +562,8 @@ static void axienet_adjust_link(struct net_device *ndev)
lp->last_link = link_state;
phy_print_status(phy);
} else {
- dev_err(&ndev->dev, "Error setting Axi Ethernet "
- "mac speed\n");
+ netdev_err(ndev,
+ "Error setting Axi Ethernet mac speed\n");
}
}
}
@@ -617,7 +621,7 @@ static void axienet_start_xmit_done(struct net_device *ndev)
* @lp: Pointer to the axienet_local structure
* @num_frag: The number of BDs to check for
*
- * returns: 0, on success
+ * Return: 0, on success
* NETDEV_TX_BUSY, if any of the descriptors are not free
*
* This function is invoked before BDs are allocated and transmission starts.
@@ -640,7 +644,7 @@ static inline int axienet_check_tx_bd_space(struct axienet_local *lp,
* @skb: sk_buff pointer that contains data to be Txed.
* @ndev: Pointer to net_device structure.
*
- * returns: NETDEV_TX_OK, on success
+ * Return: NETDEV_TX_OK, on success
* NETDEV_TX_BUSY, if any of the descriptors are not free
*
* This function is invoked from upper layers to initiate transmission. The
@@ -726,15 +730,15 @@ static void axienet_recv(struct net_device *ndev)
u32 csumstatus;
u32 size = 0;
u32 packets = 0;
- dma_addr_t tail_p;
+ dma_addr_t tail_p = 0;
struct axienet_local *lp = netdev_priv(ndev);
struct sk_buff *skb, *new_skb;
struct axidma_bd *cur_p;
- tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci;
cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
while ((cur_p->status & XAXIDMA_BD_STS_COMPLETE_MASK)) {
+ tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci;
skb = (struct sk_buff *) (cur_p->sw_id_offset);
length = cur_p->app4 & 0x0000FFFF;
@@ -786,7 +790,8 @@ static void axienet_recv(struct net_device *ndev)
ndev->stats.rx_packets += packets;
ndev->stats.rx_bytes += size;
- axienet_dma_out32(lp, XAXIDMA_RX_TDESC_OFFSET, tail_p);
+ if (tail_p)
+ axienet_dma_out32(lp, XAXIDMA_RX_TDESC_OFFSET, tail_p);
}
/**
@@ -794,7 +799,7 @@ static void axienet_recv(struct net_device *ndev)
* @irq: irq number
* @_ndev: net_device pointer
*
- * returns: IRQ_HANDLED for all cases.
+ * Return: IRQ_HANDLED for all cases.
*
* This is the Axi DMA Tx done Isr. It invokes "axienet_start_xmit_done"
* to complete the BD processing.
@@ -808,6 +813,7 @@ static irqreturn_t axienet_tx_irq(int irq, void *_ndev)
status = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) {
+ axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status);
axienet_start_xmit_done(lp->ndev);
goto out;
}
@@ -831,9 +837,9 @@ static irqreturn_t axienet_tx_irq(int irq, void *_ndev)
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr);
tasklet_schedule(&lp->dma_err_tasklet);
+ axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status);
}
out:
- axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status);
return IRQ_HANDLED;
}
@@ -842,7 +848,7 @@ out:
* @irq: irq number
* @_ndev: net_device pointer
*
- * returns: IRQ_HANDLED for all cases.
+ * Return: IRQ_HANDLED for all cases.
*
* This is the Axi DMA Rx Isr. It invokes "axienet_recv" to complete the BD
* processing.
@@ -856,6 +862,7 @@ static irqreturn_t axienet_rx_irq(int irq, void *_ndev)
status = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) {
+ axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status);
axienet_recv(lp->ndev);
goto out;
}
@@ -879,9 +886,9 @@ static irqreturn_t axienet_rx_irq(int irq, void *_ndev)
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr);
tasklet_schedule(&lp->dma_err_tasklet);
+ axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status);
}
out:
- axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status);
return IRQ_HANDLED;
}
@@ -891,7 +898,7 @@ static void axienet_dma_err_handler(unsigned long data);
* axienet_open - Driver open routine.
* @ndev: Pointer to net_device structure
*
- * returns: 0, on success.
+ * Return: 0, on success.
* -ENODEV, if PHY cannot be connected to
* non-zero error value on failure
*
@@ -914,7 +921,8 @@ static int axienet_open(struct net_device *ndev)
/* Disable the MDIO interface till Axi Ethernet Reset is completed.
* When we do an Axi Ethernet reset, it resets the complete core
* including the MDIO. If MDIO is not disabled when the reset
- * process is started, MDIO will be broken afterwards. */
+ * process is started, MDIO will be broken afterwards.
+ */
axienet_iow(lp, XAE_MDIO_MC_OFFSET,
(mdio_mcreg & (~XAE_MDIO_MC_MDIOEN_MASK)));
axienet_device_reset(ndev);
@@ -925,14 +933,20 @@ static int axienet_open(struct net_device *ndev)
return ret;
if (lp->phy_node) {
- lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node,
+ if (lp->phy_type == XAE_PHY_TYPE_GMII) {
+ lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node,
axienet_adjust_link, 0,
PHY_INTERFACE_MODE_GMII);
- if (!lp->phy_dev) {
- dev_err(lp->dev, "of_phy_connect() failed\n");
- return -ENODEV;
+ } else if (lp->phy_type == XAE_PHY_TYPE_RGMII_2_0) {
+ lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node,
+ axienet_adjust_link, 0,
+ PHY_INTERFACE_MODE_RGMII_ID);
}
- phy_start(lp->phy_dev);
+
+ if (!lp->phy_dev)
+ dev_err(lp->dev, "of_phy_connect() failed\n");
+ else
+ phy_start(lp->phy_dev);
}
/* Enable tasklets for Axi DMA error handling */
@@ -965,7 +979,7 @@ err_tx_irq:
* axienet_stop - Driver stop routine.
* @ndev: Pointer to net_device structure
*
- * returns: 0, on success.
+ * Return: 0, on success.
*
* This is the driver stop routine. It calls phy_disconnect to stop the PHY
* device. It also removes the interrupt handlers and disables the interrupts.
@@ -1005,7 +1019,7 @@ static int axienet_stop(struct net_device *ndev)
* @ndev: Pointer to net_device structure
* @new_mtu: New mtu value to be applied
*
- * returns: Always returns 0 (success).
+ * Return: Always returns 0 (success).
*
* This is the change mtu driver routine. It checks if the Axi Ethernet
* hardware supports jumbo frames before changing the mtu. This can be
@@ -1017,15 +1031,15 @@ static int axienet_change_mtu(struct net_device *ndev, int new_mtu)
if (netif_running(ndev))
return -EBUSY;
- if (lp->jumbo_support) {
- if ((new_mtu > XAE_JUMBO_MTU) || (new_mtu < 64))
- return -EINVAL;
- ndev->mtu = new_mtu;
- } else {
- if ((new_mtu > XAE_MTU) || (new_mtu < 64))
- return -EINVAL;
- ndev->mtu = new_mtu;
- }
+
+ if ((new_mtu + VLAN_ETH_HLEN +
+ XAE_TRL_SIZE) > lp->rxmem)
+ return -EINVAL;
+
+ if ((new_mtu > XAE_JUMBO_MTU) || (new_mtu < 64))
+ return -EINVAL;
+
+ ndev->mtu = new_mtu;
return 0;
}
@@ -1072,6 +1086,8 @@ static const struct net_device_ops axienet_netdev_ops = {
* not be found, the function returns -ENODEV. This function calls the
* relevant PHY ethtool API to get the PHY settings.
* Issue "ethtool ethX" under linux prompt to execute this function.
+ *
+ * Return: 0 on success, -ENODEV if PHY doesn't exist
*/
static int axienet_ethtools_get_settings(struct net_device *ndev,
struct ethtool_cmd *ecmd)
@@ -1093,6 +1109,8 @@ static int axienet_ethtools_get_settings(struct net_device *ndev,
* relevant PHY ethtool API to set the PHY.
* Issue e.g. "ethtool -s ethX speed 1000" under linux prompt to execute this
* function.
+ *
+ * Return: 0 on success, -ENODEV if PHY doesn't exist
*/
static int axienet_ethtools_set_settings(struct net_device *ndev,
struct ethtool_cmd *ecmd)
@@ -1127,6 +1145,8 @@ static void axienet_ethtools_get_drvinfo(struct net_device *ndev,
*
* This implements ethtool command for getting the total register length
* information.
+ *
+ * Return: the total regs length
*/
static int axienet_ethtools_get_regs_len(struct net_device *ndev)
{
@@ -1213,11 +1233,13 @@ axienet_ethtools_get_pauseparam(struct net_device *ndev,
* axienet_ethtools_set_pauseparam - Set device pause parameter(flow control)
* settings.
* @ndev: Pointer to net_device structure
- * @epauseparam:Pointer to ethtool_pauseparam structure
+ * @epauseparm:Pointer to ethtool_pauseparam structure
*
* This implements ethtool command for enabling flow control on Rx and Tx
* paths. Issue "ethtool -A ethX tx on|off" under linux prompt to execute this
* function.
+ *
+ * Return: 0 on success, -EFAULT if device is running
*/
static int
axienet_ethtools_set_pauseparam(struct net_device *ndev,
@@ -1227,8 +1249,8 @@ axienet_ethtools_set_pauseparam(struct net_device *ndev,
struct axienet_local *lp = netdev_priv(ndev);
if (netif_running(ndev)) {
- printk(KERN_ERR "%s: Please stop netif before applying "
- "configruation\n", ndev->name);
+ netdev_err(ndev,
+ "Please stop netif before applying configuration\n");
return -EFAULT;
}
@@ -1254,6 +1276,8 @@ axienet_ethtools_set_pauseparam(struct net_device *ndev,
* This implements ethtool command for getting the DMA interrupt coalescing
* count on Tx and Rx paths. Issue "ethtool -c ethX" under linux prompt to
* execute this function.
+ *
+ * Return: 0 always
*/
static int axienet_ethtools_get_coalesce(struct net_device *ndev,
struct ethtool_coalesce *ecoalesce)
@@ -1277,6 +1301,8 @@ static int axienet_ethtools_get_coalesce(struct net_device *ndev,
* This implements ethtool command for setting the DMA interrupt coalescing
* count on Tx and Rx paths. Issue "ethtool -C ethX rx-frames 5" under linux
* prompt to execute this function.
+ *
+ * Return: 0, on success, Non-zero error value on failure.
*/
static int axienet_ethtools_set_coalesce(struct net_device *ndev,
struct ethtool_coalesce *ecoalesce)
@@ -1284,8 +1310,8 @@ static int axienet_ethtools_set_coalesce(struct net_device *ndev,
struct axienet_local *lp = netdev_priv(ndev);
if (netif_running(ndev)) {
- printk(KERN_ERR "%s: Please stop netif before applying "
- "configruation\n", ndev->name);
+ netdev_err(ndev,
+ "Please stop netif before applying configuration\n");
return -EFAULT;
}
@@ -1354,7 +1380,8 @@ static void axienet_dma_err_handler(unsigned long data)
/* Disable the MDIO interface till Axi Ethernet Reset is completed.
* When we do an Axi Ethernet reset, it resets the complete core
* including the MDIO. So if MDIO is not disabled when the reset
- * process is started, MDIO will be broken afterwards. */
+ * process is started, MDIO will be broken afterwards.
+ */
axienet_iow(lp, XAE_MDIO_MC_OFFSET, (mdio_mcreg &
~XAE_MDIO_MC_MDIOEN_MASK));
@@ -1425,7 +1452,8 @@ static void axienet_dma_err_handler(unsigned long data)
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr);
/* Populate the tail pointer and bring the Rx Axi DMA engine out of
- * halted state. This will make the Rx side ready for reception.*/
+ * halted state. This will make the Rx side ready for reception.
+ */
axienet_dma_out32(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p);
cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET,
@@ -1435,7 +1463,8 @@ static void axienet_dma_err_handler(unsigned long data)
/* Write to the RS (Run-stop) bit in the Tx channel control register.
* Tx channel is now ready to run. But only after we write to the
- * tail pointer register that the Tx channel will start transmitting */
+ * tail pointer register that the Tx channel will start transmitting
+ */
axienet_dma_out32(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p);
cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET,
@@ -1451,7 +1480,8 @@ static void axienet_dma_err_handler(unsigned long data)
axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
/* Sync default options with HW but leave receiver and
- * transmitter disabled.*/
+ * transmitter disabled.
+ */
axienet_setoptions(ndev, lp->options &
~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
axienet_set_mac_address(ndev, NULL);
@@ -1460,11 +1490,10 @@ static void axienet_dma_err_handler(unsigned long data)
}
/**
- * axienet_of_probe - Axi Ethernet probe function.
- * @op: Pointer to platform device structure.
- * @match: Pointer to device id structure
+ * axienet_probe - Axi Ethernet probe function.
+ * @pdev: Pointer to platform device structure.
*
- * returns: 0, on success
+ * Return: 0, on success
* Non-zero error value on failure.
*
* This is the probe routine for Axi Ethernet driver. This is called before
@@ -1472,22 +1501,23 @@ static void axienet_dma_err_handler(unsigned long data)
* device. Parses through device tree and populates fields of
* axienet_local. It registers the Ethernet device.
*/
-static int axienet_of_probe(struct platform_device *op)
+static int axienet_probe(struct platform_device *pdev)
{
- __be32 *p;
- int size, ret = 0;
+ int ret;
struct device_node *np;
struct axienet_local *lp;
struct net_device *ndev;
- const void *addr;
+ u8 mac_addr[6];
+ struct resource *ethres, dmares;
+ u32 value;
ndev = alloc_etherdev(sizeof(*lp));
if (!ndev)
return -ENOMEM;
- platform_set_drvdata(op, ndev);
+ platform_set_drvdata(pdev, ndev);
- SET_NETDEV_DEV(ndev, &op->dev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
ndev->flags &= ~IFF_MULTICAST; /* clear multicast */
ndev->features = NETIF_F_SG;
ndev->netdev_ops = &axienet_netdev_ops;
@@ -1495,21 +1525,23 @@ static int axienet_of_probe(struct platform_device *op)
lp = netdev_priv(ndev);
lp->ndev = ndev;
- lp->dev = &op->dev;
+ lp->dev = &pdev->dev;
lp->options = XAE_OPTION_DEFAULTS;
/* Map device registers */
- lp->regs = of_iomap(op->dev.of_node, 0);
+ ethres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ lp->regs = devm_ioremap_resource(&pdev->dev, ethres);
if (!lp->regs) {
- dev_err(&op->dev, "could not map Axi Ethernet regs.\n");
+ dev_err(&pdev->dev, "could not map Axi Ethernet regs.\n");
ret = -ENOMEM;
- goto nodev;
+ goto free_netdev;
}
+
/* Setup checksum offload, but default to off if not specified */
lp->features = 0;
- p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,txcsum", NULL);
- if (p) {
- switch (be32_to_cpup(p)) {
+ ret = of_property_read_u32(pdev->dev.of_node, "xlnx,txcsum", &value);
+ if (!ret) {
+ switch (value) {
case 1:
lp->csum_offload_on_tx_path =
XAE_FEATURE_PARTIAL_TX_CSUM;
@@ -1528,9 +1560,9 @@ static int axienet_of_probe(struct platform_device *op)
lp->csum_offload_on_tx_path = XAE_NO_CSUM_OFFLOAD;
}
}
- p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,rxcsum", NULL);
- if (p) {
- switch (be32_to_cpup(p)) {
+ ret = of_property_read_u32(pdev->dev.of_node, "xlnx,rxcsum", &value);
+ if (!ret) {
+ switch (value) {
case 1:
lp->csum_offload_on_rx_path =
XAE_FEATURE_PARTIAL_RX_CSUM;
@@ -1546,82 +1578,77 @@ static int axienet_of_probe(struct platform_device *op)
}
}
/* For supporting jumbo frames, the Axi Ethernet hardware must have
- * a larger Rx/Tx Memory. Typically, the size must be more than or
- * equal to 16384 bytes, so that we can enable jumbo option and start
- * supporting jumbo frames. Here we check for memory allocated for
- * Rx/Tx in the hardware from the device-tree and accordingly set
- * flags. */
- p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,rxmem", NULL);
- if (p) {
- if ((be32_to_cpup(p)) >= 0x4000)
- lp->jumbo_support = 1;
- }
- p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,phy-type", NULL);
- if (p)
- lp->phy_type = be32_to_cpup(p);
+ * a larger Rx/Tx Memory. Typically, the size must be large so that
+ * we can enable jumbo option and start supporting jumbo frames.
+ * Here we check for memory allocated for Rx/Tx in the hardware from
+ * the device-tree and accordingly set flags.
+ */
+ of_property_read_u32(pdev->dev.of_node, "xlnx,rxmem", &lp->rxmem);
+ of_property_read_u32(pdev->dev.of_node, "xlnx,phy-type", &lp->phy_type);
/* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
- np = of_parse_phandle(op->dev.of_node, "axistream-connected", 0);
- if (!np) {
- dev_err(&op->dev, "could not find DMA node\n");
- ret = -ENODEV;
- goto err_iounmap;
+ np = of_parse_phandle(pdev->dev.of_node, "axistream-connected", 0);
+ if (IS_ERR(np)) {
+ dev_err(&pdev->dev, "could not find DMA node\n");
+ ret = PTR_ERR(np);
+ goto free_netdev;
}
- lp->dma_regs = of_iomap(np, 0);
- if (lp->dma_regs) {
- dev_dbg(&op->dev, "MEM base: %p\n", lp->dma_regs);
- } else {
- dev_err(&op->dev, "unable to map DMA registers\n");
- of_node_put(np);
+ ret = of_address_to_resource(np, 0, &dmares);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to get DMA resource\n");
+ goto free_netdev;
+ }
+ lp->dma_regs = devm_ioremap_resource(&pdev->dev, &dmares);
+ if (!lp->dma_regs) {
+ dev_err(&pdev->dev, "could not map DMA regs\n");
+ ret = -ENOMEM;
+ goto free_netdev;
}
lp->rx_irq = irq_of_parse_and_map(np, 1);
lp->tx_irq = irq_of_parse_and_map(np, 0);
of_node_put(np);
if ((lp->rx_irq <= 0) || (lp->tx_irq <= 0)) {
- dev_err(&op->dev, "could not determine irqs\n");
+ dev_err(&pdev->dev, "could not determine irqs\n");
ret = -ENOMEM;
- goto err_iounmap_2;
+ goto free_netdev;
}
/* Retrieve the MAC address */
- addr = of_get_property(op->dev.of_node, "local-mac-address", &size);
- if ((!addr) || (size != 6)) {
- dev_err(&op->dev, "could not find MAC address\n");
- ret = -ENODEV;
- goto err_iounmap_2;
+ ret = of_property_read_u8_array(pdev->dev.of_node,
+ "local-mac-address", mac_addr, 6);
+ if (ret) {
+ dev_err(&pdev->dev, "could not find MAC address\n");
+ goto free_netdev;
}
- axienet_set_mac_address(ndev, (void *) addr);
+ axienet_set_mac_address(ndev, (void *)mac_addr);
lp->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD;
lp->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD;
- lp->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0);
- ret = axienet_mdio_setup(lp, op->dev.of_node);
- if (ret)
- dev_warn(&op->dev, "error registering MDIO bus\n");
+ lp->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
+ if (lp->phy_node) {
+ ret = axienet_mdio_setup(lp, pdev->dev.of_node);
+ if (ret)
+ dev_warn(&pdev->dev, "error registering MDIO bus\n");
+ }
ret = register_netdev(lp->ndev);
if (ret) {
dev_err(lp->dev, "register_netdev() error (%i)\n", ret);
- goto err_iounmap_2;
+ goto free_netdev;
}
return 0;
-err_iounmap_2:
- if (lp->dma_regs)
- iounmap(lp->dma_regs);
-err_iounmap:
- iounmap(lp->regs);
-nodev:
+free_netdev:
free_netdev(ndev);
- ndev = NULL;
+
return ret;
}
-static int axienet_of_remove(struct platform_device *op)
+static int axienet_remove(struct platform_device *pdev)
{
- struct net_device *ndev = platform_get_drvdata(op);
+ struct net_device *ndev = platform_get_drvdata(pdev);
struct axienet_local *lp = netdev_priv(ndev);
axienet_mdio_teardown(lp);
@@ -1630,24 +1657,21 @@ static int axienet_of_remove(struct platform_device *op)
of_node_put(lp->phy_node);
lp->phy_node = NULL;
- iounmap(lp->regs);
- if (lp->dma_regs)
- iounmap(lp->dma_regs);
free_netdev(ndev);
return 0;
}
-static struct platform_driver axienet_of_driver = {
- .probe = axienet_of_probe,
- .remove = axienet_of_remove,
+static struct platform_driver axienet_driver = {
+ .probe = axienet_probe,
+ .remove = axienet_remove,
.driver = {
.name = "xilinx_axienet",
.of_match_table = axienet_of_match,
},
};
-module_platform_driver(axienet_of_driver);
+module_platform_driver(axienet_driver);
MODULE_DESCRIPTION("Xilinx Axi Ethernet driver");
MODULE_AUTHOR("Xilinx");
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
index 3b67d60d4378..2a5a16834c01 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
@@ -37,7 +37,7 @@ int axienet_mdio_wait_until_ready(struct axienet_local *lp)
* @phy_id: Address of the PHY device
* @reg: PHY register to read
*
- * returns: The register contents on success, -ETIMEDOUT on a timeout
+ * Return: The register contents on success, -ETIMEDOUT on a timeout
*
* Reads the contents of the requested register from the requested PHY
* address by first writing the details into MCR register. After a while
@@ -80,7 +80,7 @@ static int axienet_mdio_read(struct mii_bus *bus, int phy_id, int reg)
* @reg: PHY register to write to
* @val: Value to be written into the register
*
- * returns: 0 on success, -ETIMEDOUT on a timeout
+ * Return: 0 on success, -ETIMEDOUT on a timeout
*
* Writes the value to the requested register by first writing the value
* into MWD register. The the MCR register is then appropriately setup
@@ -119,7 +119,7 @@ static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg,
* @lp: Pointer to axienet local data structure.
* @np: Pointer to device node
*
- * returns: 0 on success, -ETIMEDOUT on a timeout, -ENOMEM when
+ * Return: 0 on success, -ETIMEDOUT on a timeout, -ENOMEM when
* mdiobus_alloc (to allocate memory for mii bus structure) fails.
*
* Sets up the MDIO interface by initializing the MDIO clock and enabling the
@@ -161,19 +161,19 @@ int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np)
np1 = of_find_node_by_name(NULL, "cpu");
if (!np1) {
- printk(KERN_WARNING "%s(): Could not find CPU device node.",
- __func__);
- printk(KERN_WARNING "Setting MDIO clock divisor to "
- "default %d\n", DEFAULT_CLOCK_DIVISOR);
+ netdev_warn(lp->ndev, "Could not find CPU device node.\n");
+ netdev_warn(lp->ndev,
+ "Setting MDIO clock divisor to default %d\n",
+ DEFAULT_CLOCK_DIVISOR);
clk_div = DEFAULT_CLOCK_DIVISOR;
goto issue;
}
property_p = (u32 *) of_get_property(np1, "clock-frequency", NULL);
if (!property_p) {
- printk(KERN_WARNING "%s(): Could not find CPU property: "
- "clock-frequency.", __func__);
- printk(KERN_WARNING "Setting MDIO clock divisor to "
- "default %d\n", DEFAULT_CLOCK_DIVISOR);
+ netdev_warn(lp->ndev, "clock-frequency property not found.\n");
+ netdev_warn(lp->ndev,
+ "Setting MDIO clock divisor to default %d\n",
+ DEFAULT_CLOCK_DIVISOR);
clk_div = DEFAULT_CLOCK_DIVISOR;
of_node_put(np1);
goto issue;
@@ -183,12 +183,14 @@ int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np)
clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1;
/* If there is any remainder from the division of
* fHOST / (MAX_MDIO_FREQ * 2), then we need to add
- * 1 to the clock divisor or we will surely be above 2.5 MHz */
+ * 1 to the clock divisor or we will surely be above 2.5 MHz
+ */
if (host_clock % (MAX_MDIO_FREQ * 2))
clk_div++;
- printk(KERN_DEBUG "%s(): Setting MDIO clock divisor to %u based "
- "on %u Hz host clock.\n", __func__, clk_div, host_clock);
+ netdev_dbg(lp->ndev,
+ "Setting MDIO clock divisor to %u/%u Hz host clock.\n",
+ clk_div, host_clock);
of_node_put(np1);
issue:
diff --git a/drivers/net/ethernet/xircom/Kconfig b/drivers/net/ethernet/xircom/Kconfig
index 69f56a6de821..d6208a4c9866 100644
--- a/drivers/net/ethernet/xircom/Kconfig
+++ b/drivers/net/ethernet/xircom/Kconfig
@@ -7,9 +7,7 @@ config NET_VENDOR_XIRCOM
default y
depends on PCMCIA
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/ethernet/xscale/Kconfig b/drivers/net/ethernet/xscale/Kconfig
index b81bc9fca378..af3432fe9a5e 100644
--- a/drivers/net/ethernet/xscale/Kconfig
+++ b/drivers/net/ethernet/xscale/Kconfig
@@ -8,9 +8,7 @@ config NET_VENDOR_XSCALE
depends on NET_VENDOR_INTEL && (ARM && ARCH_IXP4XX && \
IXP4XX_NPE && IXP4XX_QMGR)
---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question does not directly affect the
kernel: saying N will just cause the configurator to skip all
diff --git a/drivers/net/fddi/skfp/srf.c b/drivers/net/fddi/skfp/srf.c
index cc27dea3414e..9956680402de 100644
--- a/drivers/net/fddi/skfp/srf.c
+++ b/drivers/net/fddi/skfp/srf.c
@@ -414,7 +414,7 @@ static void smt_send_srf(struct s_smc *smc)
smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ;
mb->sm_len = smt->smt_len + sizeof(struct smt_header) ;
- DB_SMT("SRF: sending SRF at %x, len %d\n",smt,mb->sm_len) ;
+ DB_SMT("SRF: sending SRF at %p, len %d\n",smt,mb->sm_len) ;
DB_SMT("SRF: state SR%d Threshold %d\n",
smc->srf.sr_state,smc->srf.SRThreshold/TICKS_PER_SECOND) ;
#ifdef DEBUG
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
new file mode 100644
index 000000000000..78d49d186e05
--- /dev/null
+++ b/drivers/net/geneve.c
@@ -0,0 +1,523 @@
+/*
+ * GENEVE: Generic Network Virtualization Encapsulation
+ *
+ * Copyright (c) 2015 Red Hat, 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/hash.h>
+#include <net/rtnetlink.h>
+#include <net/geneve.h>
+
+#define GENEVE_NETDEV_VER "0.6"
+
+#define GENEVE_UDP_PORT 6081
+
+#define GENEVE_N_VID (1u << 24)
+#define GENEVE_VID_MASK (GENEVE_N_VID - 1)
+
+#define VNI_HASH_BITS 10
+#define VNI_HASH_SIZE (1<<VNI_HASH_BITS)
+
+static bool log_ecn_error = true;
+module_param(log_ecn_error, bool, 0644);
+MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
+
+/* per-network namespace private data for this module */
+struct geneve_net {
+ struct list_head geneve_list;
+ struct hlist_head vni_list[VNI_HASH_SIZE];
+};
+
+/* Pseudo network device */
+struct geneve_dev {
+ struct hlist_node hlist; /* vni hash table */
+ struct net *net; /* netns for packet i/o */
+ struct net_device *dev; /* netdev for geneve tunnel */
+ struct geneve_sock *sock; /* socket used for geneve tunnel */
+ u8 vni[3]; /* virtual network ID for tunnel */
+ u8 ttl; /* TTL override */
+ u8 tos; /* TOS override */
+ struct sockaddr_in remote; /* IPv4 address for link partner */
+ struct list_head next; /* geneve's per namespace list */
+};
+
+static int geneve_net_id;
+
+static inline __u32 geneve_net_vni_hash(u8 vni[3])
+{
+ __u32 vnid;
+
+ vnid = (vni[0] << 16) | (vni[1] << 8) | vni[2];
+ return hash_32(vnid, VNI_HASH_BITS);
+}
+
+/* geneve receive/decap routine */
+static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb)
+{
+ struct genevehdr *gnvh = geneve_hdr(skb);
+ struct geneve_dev *dummy, *geneve = NULL;
+ struct geneve_net *gn;
+ struct iphdr *iph = NULL;
+ struct pcpu_sw_netstats *stats;
+ struct hlist_head *vni_list_head;
+ int err = 0;
+ __u32 hash;
+
+ iph = ip_hdr(skb); /* Still outer IP header... */
+
+ gn = gs->rcv_data;
+
+ /* Find the device for this VNI */
+ hash = geneve_net_vni_hash(gnvh->vni);
+ vni_list_head = &gn->vni_list[hash];
+ hlist_for_each_entry_rcu(dummy, vni_list_head, hlist) {
+ if (!memcmp(gnvh->vni, dummy->vni, sizeof(dummy->vni)) &&
+ iph->saddr == dummy->remote.sin_addr.s_addr) {
+ geneve = dummy;
+ break;
+ }
+ }
+ if (!geneve)
+ goto drop;
+
+ /* Drop packets w/ critical options,
+ * since we don't support any...
+ */
+ if (gnvh->critical)
+ goto drop;
+
+ skb_reset_mac_header(skb);
+ skb_scrub_packet(skb, !net_eq(geneve->net, dev_net(geneve->dev)));
+ skb->protocol = eth_type_trans(skb, geneve->dev);
+ skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
+
+ /* Ignore packet loops (and multicast echo) */
+ if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr))
+ goto drop;
+
+ skb_reset_network_header(skb);
+
+ iph = ip_hdr(skb); /* Now inner IP header... */
+ err = IP_ECN_decapsulate(iph, skb);
+
+ if (unlikely(err)) {
+ if (log_ecn_error)
+ net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n",
+ &iph->saddr, iph->tos);
+ if (err > 1) {
+ ++geneve->dev->stats.rx_frame_errors;
+ ++geneve->dev->stats.rx_errors;
+ goto drop;
+ }
+ }
+
+ stats = this_cpu_ptr(geneve->dev->tstats);
+ u64_stats_update_begin(&stats->syncp);
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+ u64_stats_update_end(&stats->syncp);
+
+ netif_rx(skb);
+
+ return;
+drop:
+ /* Consume bad packet */
+ kfree_skb(skb);
+}
+
+/* Setup stats when device is created */
+static int geneve_init(struct net_device *dev)
+{
+ dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+ if (!dev->tstats)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void geneve_uninit(struct net_device *dev)
+{
+ free_percpu(dev->tstats);
+}
+
+static int geneve_open(struct net_device *dev)
+{
+ struct geneve_dev *geneve = netdev_priv(dev);
+ struct net *net = geneve->net;
+ struct geneve_net *gn = net_generic(geneve->net, geneve_net_id);
+ struct geneve_sock *gs;
+
+ gs = geneve_sock_add(net, htons(GENEVE_UDP_PORT), geneve_rx, gn,
+ false, false);
+ if (IS_ERR(gs))
+ return PTR_ERR(gs);
+
+ geneve->sock = gs;
+
+ return 0;
+}
+
+static int geneve_stop(struct net_device *dev)
+{
+ struct geneve_dev *geneve = netdev_priv(dev);
+ struct geneve_sock *gs = geneve->sock;
+
+ geneve_sock_release(gs);
+
+ return 0;
+}
+
+static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct geneve_dev *geneve = netdev_priv(dev);
+ struct geneve_sock *gs = geneve->sock;
+ struct rtable *rt = NULL;
+ const struct iphdr *iip; /* interior IP header */
+ struct flowi4 fl4;
+ int err;
+ __be16 sport;
+ __u8 tos, ttl;
+
+ iip = ip_hdr(skb);
+
+ skb_reset_mac_header(skb);
+
+ /* TODO: port min/max limits should be configurable */
+ sport = udp_flow_src_port(dev_net(dev), skb, 0, 0, true);
+
+ tos = geneve->tos;
+ if (tos == 1)
+ tos = ip_tunnel_get_dsfield(iip, skb);
+
+ memset(&fl4, 0, sizeof(fl4));
+ fl4.flowi4_tos = RT_TOS(tos);
+ fl4.daddr = geneve->remote.sin_addr.s_addr;
+ rt = ip_route_output_key(geneve->net, &fl4);
+ if (IS_ERR(rt)) {
+ netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr);
+ dev->stats.tx_carrier_errors++;
+ goto tx_error;
+ }
+ if (rt->dst.dev == dev) { /* is this necessary? */
+ netdev_dbg(dev, "circular route to %pI4\n", &fl4.daddr);
+ dev->stats.collisions++;
+ goto rt_tx_error;
+ }
+
+ tos = ip_tunnel_ecn_encap(tos, iip, skb);
+
+ ttl = geneve->ttl;
+ if (!ttl && IN_MULTICAST(ntohl(fl4.daddr)))
+ ttl = 1;
+
+ ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
+
+ /* no need to handle local destination and encap bypass...yet... */
+
+ err = geneve_xmit_skb(gs, rt, skb, fl4.saddr, fl4.daddr,
+ tos, ttl, 0, sport, htons(GENEVE_UDP_PORT), 0,
+ geneve->vni, 0, NULL, false,
+ !net_eq(geneve->net, dev_net(geneve->dev)));
+ if (err < 0)
+ ip_rt_put(rt);
+
+ iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
+
+ return NETDEV_TX_OK;
+
+rt_tx_error:
+ ip_rt_put(rt);
+tx_error:
+ dev->stats.tx_errors++;
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops geneve_netdev_ops = {
+ .ndo_init = geneve_init,
+ .ndo_uninit = geneve_uninit,
+ .ndo_open = geneve_open,
+ .ndo_stop = geneve_stop,
+ .ndo_start_xmit = geneve_xmit,
+ .ndo_get_stats64 = ip_tunnel_get_stats64,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+};
+
+static void geneve_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ strlcpy(drvinfo->version, GENEVE_NETDEV_VER, sizeof(drvinfo->version));
+ strlcpy(drvinfo->driver, "geneve", sizeof(drvinfo->driver));
+}
+
+static const struct ethtool_ops geneve_ethtool_ops = {
+ .get_drvinfo = geneve_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+};
+
+/* Info for udev, that this is a virtual tunnel endpoint */
+static struct device_type geneve_type = {
+ .name = "geneve",
+};
+
+/* Initialize the device structure. */
+static void geneve_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+
+ dev->netdev_ops = &geneve_netdev_ops;
+ dev->ethtool_ops = &geneve_ethtool_ops;
+ dev->destructor = free_netdev;
+
+ SET_NETDEV_DEVTYPE(dev, &geneve_type);
+
+ dev->tx_queue_len = 0;
+ dev->features |= NETIF_F_LLTX;
+ dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
+ dev->features |= NETIF_F_RXCSUM;
+ dev->features |= NETIF_F_GSO_SOFTWARE;
+
+ dev->vlan_features = dev->features;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
+
+ dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
+ dev->hw_features |= NETIF_F_GSO_SOFTWARE;
+ dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
+
+ netif_keep_dst(dev);
+ dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+}
+
+static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = {
+ [IFLA_GENEVE_ID] = { .type = NLA_U32 },
+ [IFLA_GENEVE_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) },
+ [IFLA_GENEVE_TTL] = { .type = NLA_U8 },
+ [IFLA_GENEVE_TOS] = { .type = NLA_U8 },
+};
+
+static int geneve_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+ if (tb[IFLA_ADDRESS]) {
+ if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+ return -EINVAL;
+
+ if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+ return -EADDRNOTAVAIL;
+ }
+
+ if (!data)
+ return -EINVAL;
+
+ if (data[IFLA_GENEVE_ID]) {
+ __u32 vni = nla_get_u32(data[IFLA_GENEVE_ID]);
+
+ if (vni >= GENEVE_VID_MASK)
+ return -ERANGE;
+ }
+
+ return 0;
+}
+
+static int geneve_newlink(struct net *net, struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[])
+{
+ struct geneve_net *gn = net_generic(net, geneve_net_id);
+ struct geneve_dev *dummy, *geneve = netdev_priv(dev);
+ struct hlist_head *vni_list_head;
+ struct sockaddr_in remote; /* IPv4 address for link partner */
+ __u32 vni, hash;
+ int err;
+
+ if (!data[IFLA_GENEVE_ID] || !data[IFLA_GENEVE_REMOTE])
+ return -EINVAL;
+
+ geneve->net = net;
+ geneve->dev = dev;
+
+ vni = nla_get_u32(data[IFLA_GENEVE_ID]);
+ geneve->vni[0] = (vni & 0x00ff0000) >> 16;
+ geneve->vni[1] = (vni & 0x0000ff00) >> 8;
+ geneve->vni[2] = vni & 0x000000ff;
+
+ geneve->remote.sin_addr.s_addr =
+ nla_get_in_addr(data[IFLA_GENEVE_REMOTE]);
+ if (IN_MULTICAST(ntohl(geneve->remote.sin_addr.s_addr)))
+ return -EINVAL;
+
+ remote = geneve->remote;
+ hash = geneve_net_vni_hash(geneve->vni);
+ vni_list_head = &gn->vni_list[hash];
+ hlist_for_each_entry_rcu(dummy, vni_list_head, hlist) {
+ if (!memcmp(geneve->vni, dummy->vni, sizeof(dummy->vni)) &&
+ !memcmp(&remote, &dummy->remote, sizeof(dummy->remote)))
+ return -EBUSY;
+ }
+
+ if (tb[IFLA_ADDRESS] == NULL)
+ eth_hw_addr_random(dev);
+
+ err = register_netdevice(dev);
+ if (err)
+ return err;
+
+ if (data[IFLA_GENEVE_TTL])
+ geneve->ttl = nla_get_u8(data[IFLA_GENEVE_TTL]);
+
+ if (data[IFLA_GENEVE_TOS])
+ geneve->tos = nla_get_u8(data[IFLA_GENEVE_TOS]);
+
+ list_add(&geneve->next, &gn->geneve_list);
+
+ hlist_add_head_rcu(&geneve->hlist, &gn->vni_list[hash]);
+
+ return 0;
+}
+
+static void geneve_dellink(struct net_device *dev, struct list_head *head)
+{
+ struct geneve_dev *geneve = netdev_priv(dev);
+
+ if (!hlist_unhashed(&geneve->hlist))
+ hlist_del_rcu(&geneve->hlist);
+
+ list_del(&geneve->next);
+ unregister_netdevice_queue(dev, head);
+}
+
+static size_t geneve_get_size(const struct net_device *dev)
+{
+ return nla_total_size(sizeof(__u32)) + /* IFLA_GENEVE_ID */
+ nla_total_size(sizeof(struct in_addr)) + /* IFLA_GENEVE_REMOTE */
+ nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL */
+ nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TOS */
+ 0;
+}
+
+static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+ struct geneve_dev *geneve = netdev_priv(dev);
+ __u32 vni;
+
+ vni = (geneve->vni[0] << 16) | (geneve->vni[1] << 8) | geneve->vni[2];
+ if (nla_put_u32(skb, IFLA_GENEVE_ID, vni))
+ goto nla_put_failure;
+
+ if (nla_put_in_addr(skb, IFLA_GENEVE_REMOTE,
+ geneve->remote.sin_addr.s_addr))
+ goto nla_put_failure;
+
+ if (nla_put_u8(skb, IFLA_GENEVE_TTL, geneve->ttl) ||
+ nla_put_u8(skb, IFLA_GENEVE_TOS, geneve->tos))
+ goto nla_put_failure;
+
+ return 0;
+
+nla_put_failure:
+ return -EMSGSIZE;
+}
+
+static struct rtnl_link_ops geneve_link_ops __read_mostly = {
+ .kind = "geneve",
+ .maxtype = IFLA_GENEVE_MAX,
+ .policy = geneve_policy,
+ .priv_size = sizeof(struct geneve_dev),
+ .setup = geneve_setup,
+ .validate = geneve_validate,
+ .newlink = geneve_newlink,
+ .dellink = geneve_dellink,
+ .get_size = geneve_get_size,
+ .fill_info = geneve_fill_info,
+};
+
+static __net_init int geneve_init_net(struct net *net)
+{
+ struct geneve_net *gn = net_generic(net, geneve_net_id);
+ unsigned int h;
+
+ INIT_LIST_HEAD(&gn->geneve_list);
+
+ for (h = 0; h < VNI_HASH_SIZE; ++h)
+ INIT_HLIST_HEAD(&gn->vni_list[h]);
+
+ return 0;
+}
+
+static void __net_exit geneve_exit_net(struct net *net)
+{
+ struct geneve_net *gn = net_generic(net, geneve_net_id);
+ struct geneve_dev *geneve, *next;
+ struct net_device *dev, *aux;
+ LIST_HEAD(list);
+
+ rtnl_lock();
+
+ /* gather any geneve devices that were moved into this ns */
+ for_each_netdev_safe(net, dev, aux)
+ if (dev->rtnl_link_ops == &geneve_link_ops)
+ unregister_netdevice_queue(dev, &list);
+
+ /* now gather any other geneve devices that were created in this ns */
+ list_for_each_entry_safe(geneve, next, &gn->geneve_list, next) {
+ /* If geneve->dev is in the same netns, it was already added
+ * to the list by the previous loop.
+ */
+ if (!net_eq(dev_net(geneve->dev), net))
+ unregister_netdevice_queue(geneve->dev, &list);
+ }
+
+ /* unregister the devices gathered above */
+ unregister_netdevice_many(&list);
+ rtnl_unlock();
+}
+
+static struct pernet_operations geneve_net_ops = {
+ .init = geneve_init_net,
+ .exit = geneve_exit_net,
+ .id = &geneve_net_id,
+ .size = sizeof(struct geneve_net),
+};
+
+static int __init geneve_init_module(void)
+{
+ int rc;
+
+ rc = register_pernet_subsys(&geneve_net_ops);
+ if (rc)
+ goto out1;
+
+ rc = rtnl_link_register(&geneve_link_ops);
+ if (rc)
+ goto out2;
+
+ return 0;
+out2:
+ unregister_pernet_subsys(&geneve_net_ops);
+out1:
+ return rc;
+}
+late_initcall(geneve_init_module);
+
+static void __exit geneve_cleanup_module(void)
+{
+ rtnl_link_unregister(&geneve_link_ops);
+ unregister_pernet_subsys(&geneve_net_ops);
+}
+module_exit(geneve_cleanup_module);
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION(GENEVE_NETDEV_VER);
+MODULE_AUTHOR("John W. Linville <linville@tuxdriver.com>");
+MODULE_DESCRIPTION("Interface driver for GENEVE encapsulated traffic");
+MODULE_ALIAS_RTNL_LINK("geneve");
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 63ff08a26da8..7856b6ccf5c5 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -76,7 +76,6 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
-#include <linux/netfilter.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/rtnetlink.h>
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 41071d32bc8e..dd4544085db3 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -161,6 +161,7 @@ struct netvsc_device_info {
unsigned char mac_adr[ETH_ALEN];
bool link_state; /* 0 - link up, 1 - link down */
int ring_size;
+ u32 max_num_vrss_chns;
};
enum rndis_device_state {
@@ -611,6 +612,12 @@ struct multi_send_data {
u32 count; /* counter of batched packets */
};
+struct netvsc_stats {
+ u64 packets;
+ u64 bytes;
+ struct u64_stats_sync syncp;
+};
+
/* The context of the netvsc device */
struct net_device_context {
/* point back to our device context */
@@ -618,6 +625,9 @@ struct net_device_context {
struct delayed_work dwork;
struct work_struct work;
u32 msg_enable; /* debug level */
+
+ struct netvsc_stats __percpu *tx_stats;
+ struct netvsc_stats __percpu *rx_stats;
};
/* Per netvsc device */
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 1e09243d5449..23126a74f357 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -228,13 +228,18 @@ static int netvsc_init_buf(struct hv_device *device)
struct netvsc_device *net_device;
struct nvsp_message *init_packet;
struct net_device *ndev;
+ int node;
net_device = get_outbound_net_device(device);
if (!net_device)
return -ENODEV;
ndev = net_device->ndev;
- net_device->recv_buf = vzalloc(net_device->recv_buf_size);
+ node = cpu_to_node(device->channel->target_cpu);
+ net_device->recv_buf = vzalloc_node(net_device->recv_buf_size, node);
+ if (!net_device->recv_buf)
+ net_device->recv_buf = vzalloc(net_device->recv_buf_size);
+
if (!net_device->recv_buf) {
netdev_err(ndev, "unable to allocate receive "
"buffer of size %d\n", net_device->recv_buf_size);
@@ -322,7 +327,9 @@ static int netvsc_init_buf(struct hv_device *device)
/* Now setup the send buffer.
*/
- net_device->send_buf = vzalloc(net_device->send_buf_size);
+ net_device->send_buf = vzalloc_node(net_device->send_buf_size, node);
+ if (!net_device->send_buf)
+ net_device->send_buf = vzalloc(net_device->send_buf_size);
if (!net_device->send_buf) {
netdev_err(ndev, "unable to allocate send "
"buffer of size %d\n", net_device->send_buf_size);
@@ -744,6 +751,7 @@ static inline int netvsc_send_pkt(
u64 req_id;
int ret;
struct hv_page_buffer *pgbuf;
+ u32 ring_avail = hv_ringbuf_avail_percent(&out_channel->outbound);
nvmsg.hdr.msg_type = NVSP_MSG1_TYPE_SEND_RNDIS_PKT;
if (packet->is_data_pkt) {
@@ -770,32 +778,42 @@ static inline int netvsc_send_pkt(
if (out_channel->rescind)
return -ENODEV;
+ /*
+ * It is possible that once we successfully place this packet
+ * on the ringbuffer, we may stop the queue. In that case, we want
+ * to notify the host independent of the xmit_more flag. We don't
+ * need to be precise here; in the worst case we may signal the host
+ * unnecessarily.
+ */
+ if (ring_avail < (RING_AVAIL_PERCENT_LOWATER + 1))
+ packet->xmit_more = false;
+
if (packet->page_buf_cnt) {
pgbuf = packet->cp_partial ? packet->page_buf +
packet->rmsg_pgcnt : packet->page_buf;
- ret = vmbus_sendpacket_pagebuffer(out_channel,
- pgbuf,
- packet->page_buf_cnt,
- &nvmsg,
- sizeof(struct nvsp_message),
- req_id);
+ ret = vmbus_sendpacket_pagebuffer_ctl(out_channel,
+ pgbuf,
+ packet->page_buf_cnt,
+ &nvmsg,
+ sizeof(struct nvsp_message),
+ req_id,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED,
+ !packet->xmit_more);
} else {
- ret = vmbus_sendpacket(
- out_channel, &nvmsg,
- sizeof(struct nvsp_message),
- req_id,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ ret = vmbus_sendpacket_ctl(out_channel, &nvmsg,
+ sizeof(struct nvsp_message),
+ req_id,
+ VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED,
+ !packet->xmit_more);
}
if (ret == 0) {
atomic_inc(&net_device->num_outstanding_sends);
atomic_inc(&net_device->queue_sends[q_idx]);
- if (hv_ringbuf_avail_percent(&out_channel->outbound) <
- RING_AVAIL_PERCENT_LOWATER) {
- netif_tx_stop_queue(netdev_get_tx_queue(
- ndev, q_idx));
+ if (ring_avail < RING_AVAIL_PERCENT_LOWATER) {
+ netif_tx_stop_queue(netdev_get_tx_queue(ndev, q_idx));
if (atomic_read(&net_device->
queue_sends[q_idx]) < 1)
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 5993c7e2d723..358475ed9b59 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -46,6 +46,8 @@ static int ring_size = 128;
module_param(ring_size, int, S_IRUGO);
MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
+static int max_num_vrss_chns = 8;
+
static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE |
NETIF_MSG_LINK | NETIF_MSG_IFUP |
NETIF_MSG_IFDOWN | NETIF_MSG_RX_ERR |
@@ -196,12 +198,12 @@ static bool netvsc_set_hash(u32 *hash, struct sk_buff *skb)
struct flow_keys flow;
int data_len;
- if (!skb_flow_dissect(skb, &flow) ||
- !(flow.n_proto == htons(ETH_P_IP) ||
- flow.n_proto == htons(ETH_P_IPV6)))
+ if (!skb_flow_dissect_flow_keys(skb, &flow) ||
+ !(flow.basic.n_proto == htons(ETH_P_IP) ||
+ flow.basic.n_proto == htons(ETH_P_IPV6)))
return false;
- if (flow.ip_proto == IPPROTO_TCP)
+ if (flow.basic.ip_proto == IPPROTO_TCP)
data_len = 12;
else
data_len = 8;
@@ -391,7 +393,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
u32 skb_length;
u32 pkt_sz;
struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT];
-
+ struct netvsc_stats *tx_stats = this_cpu_ptr(net_device_ctx->tx_stats);
/* We will atmost need two pages to describe the rndis
* header. We can only transmit MAX_PAGE_BUFFER_COUNT number
@@ -580,8 +582,10 @@ do_send:
drop:
if (ret == 0) {
- net->stats.tx_bytes += skb_length;
- net->stats.tx_packets++;
+ u64_stats_update_begin(&tx_stats->syncp);
+ tx_stats->packets++;
+ tx_stats->bytes += skb_length;
+ u64_stats_update_end(&tx_stats->syncp);
} else {
if (ret != -EAGAIN) {
dev_kfree_skb_any(skb);
@@ -644,13 +648,17 @@ int netvsc_recv_callback(struct hv_device *device_obj,
struct ndis_tcp_ip_checksum_info *csum_info)
{
struct net_device *net;
+ struct net_device_context *net_device_ctx;
struct sk_buff *skb;
+ struct netvsc_stats *rx_stats;
net = ((struct netvsc_device *)hv_get_drvdata(device_obj))->ndev;
if (!net || net->reg_state != NETREG_REGISTERED) {
packet->status = NVSP_STAT_FAIL;
return 0;
}
+ net_device_ctx = netdev_priv(net);
+ rx_stats = this_cpu_ptr(net_device_ctx->rx_stats);
/* Allocate a skb - TODO direct I/O to pages? */
skb = netdev_alloc_skb_ip_align(net, packet->total_data_buflen);
@@ -686,8 +694,10 @@ int netvsc_recv_callback(struct hv_device *device_obj,
skb_record_rx_queue(skb, packet->channel->
offermsg.offer.sub_channel_index);
- net->stats.rx_packets++;
- net->stats.rx_bytes += packet->total_data_buflen;
+ u64_stats_update_begin(&rx_stats->syncp);
+ rx_stats->packets++;
+ rx_stats->bytes += packet->total_data_buflen;
+ u64_stats_update_end(&rx_stats->syncp);
/*
* Pass the skb back up. Network stack will deallocate the skb when it
@@ -747,12 +757,53 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
ndevctx->device_ctx = hdev;
hv_set_drvdata(hdev, ndev);
device_info.ring_size = ring_size;
+ device_info.max_num_vrss_chns = max_num_vrss_chns;
rndis_filter_device_add(hdev, &device_info);
netif_tx_wake_all_queues(ndev);
return 0;
}
+static struct rtnl_link_stats64 *netvsc_get_stats64(struct net_device *net,
+ struct rtnl_link_stats64 *t)
+{
+ struct net_device_context *ndev_ctx = netdev_priv(net);
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct netvsc_stats *tx_stats = per_cpu_ptr(ndev_ctx->tx_stats,
+ cpu);
+ struct netvsc_stats *rx_stats = per_cpu_ptr(ndev_ctx->rx_stats,
+ cpu);
+ u64 tx_packets, tx_bytes, rx_packets, rx_bytes;
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin_irq(&tx_stats->syncp);
+ tx_packets = tx_stats->packets;
+ tx_bytes = tx_stats->bytes;
+ } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start));
+
+ do {
+ start = u64_stats_fetch_begin_irq(&rx_stats->syncp);
+ rx_packets = rx_stats->packets;
+ rx_bytes = rx_stats->bytes;
+ } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start));
+
+ t->tx_bytes += tx_bytes;
+ t->tx_packets += tx_packets;
+ t->rx_bytes += rx_bytes;
+ t->rx_packets += rx_packets;
+ }
+
+ t->tx_dropped = net->stats.tx_dropped;
+ t->tx_errors = net->stats.tx_dropped;
+
+ t->rx_dropped = net->stats.rx_dropped;
+ t->rx_errors = net->stats.rx_errors;
+
+ return t;
+}
static int netvsc_set_mac_addr(struct net_device *ndev, void *p)
{
@@ -804,6 +855,7 @@ static const struct net_device_ops device_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = netvsc_set_mac_addr,
.ndo_select_queue = netvsc_select_queue,
+ .ndo_get_stats64 = netvsc_get_stats64,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = netvsc_poll_controller,
#endif
@@ -855,6 +907,14 @@ static void netvsc_link_change(struct work_struct *w)
netdev_notify_peers(net);
}
+static void netvsc_free_netdev(struct net_device *netdev)
+{
+ struct net_device_context *net_device_ctx = netdev_priv(netdev);
+
+ free_percpu(net_device_ctx->tx_stats);
+ free_percpu(net_device_ctx->rx_stats);
+ free_netdev(netdev);
+}
static int netvsc_probe(struct hv_device *dev,
const struct hv_vmbus_device_id *dev_id)
@@ -883,6 +943,18 @@ static int netvsc_probe(struct hv_device *dev,
netdev_dbg(net, "netvsc msg_enable: %d\n",
net_device_ctx->msg_enable);
+ net_device_ctx->tx_stats = netdev_alloc_pcpu_stats(struct netvsc_stats);
+ if (!net_device_ctx->tx_stats) {
+ free_netdev(net);
+ return -ENOMEM;
+ }
+ net_device_ctx->rx_stats = netdev_alloc_pcpu_stats(struct netvsc_stats);
+ if (!net_device_ctx->rx_stats) {
+ free_percpu(net_device_ctx->tx_stats);
+ free_netdev(net);
+ return -ENOMEM;
+ }
+
hv_set_drvdata(dev, net);
INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change);
INIT_WORK(&net_device_ctx->work, do_set_multicast);
@@ -906,10 +978,11 @@ static int netvsc_probe(struct hv_device *dev,
/* Notify the netvsc driver of the new device */
device_info.ring_size = ring_size;
+ device_info.max_num_vrss_chns = max_num_vrss_chns;
ret = rndis_filter_device_add(dev, &device_info);
if (ret != 0) {
netdev_err(net, "unable to add netvsc device (ret %d)\n", ret);
- free_netdev(net);
+ netvsc_free_netdev(net);
hv_set_drvdata(dev, NULL);
return ret;
}
@@ -923,7 +996,7 @@ static int netvsc_probe(struct hv_device *dev,
if (ret != 0) {
pr_err("Unable to register netdev.\n");
rndis_filter_device_remove(dev);
- free_netdev(net);
+ netvsc_free_netdev(net);
} else {
schedule_delayed_work(&net_device_ctx->dwork, 0);
}
@@ -962,7 +1035,7 @@ static int netvsc_remove(struct hv_device *dev)
*/
rndis_filter_device_remove(dev);
- free_netdev(net);
+ netvsc_free_netdev(net);
return 0;
}
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 35a482d526d9..236aeb76ef22 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -1014,6 +1014,9 @@ int rndis_filter_device_add(struct hv_device *dev,
struct ndis_recv_scale_cap rsscap;
u32 rsscap_size = sizeof(struct ndis_recv_scale_cap);
u32 mtu, size;
+ u32 num_rss_qs;
+ const struct cpumask *node_cpu_mask;
+ u32 num_possible_rss_qs;
rndis_device = get_rndis_device();
if (!rndis_device)
@@ -1101,9 +1104,18 @@ int rndis_filter_device_add(struct hv_device *dev,
if (ret || rsscap.num_recv_que < 2)
goto out;
+ num_rss_qs = min(device_info->max_num_vrss_chns, rsscap.num_recv_que);
+
net_device->max_chn = rsscap.num_recv_que;
- net_device->num_chn = (num_online_cpus() < rsscap.num_recv_que) ?
- num_online_cpus() : rsscap.num_recv_que;
+
+ /*
+ * We will limit the VRSS channels to the number CPUs in the NUMA node
+ * the primary channel is currently bound to.
+ */
+ node_cpu_mask = cpumask_of_node(cpu_to_node(dev->channel->target_cpu));
+ num_possible_rss_qs = cpumask_weight(node_cpu_mask);
+ net_device->num_chn = min(num_possible_rss_qs, num_rss_qs);
+
if (net_device->num_chn == 1)
goto out;
diff --git a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig
index 1a3c3e57aa0b..1dd5ab8e5054 100644
--- a/drivers/net/ieee802154/Kconfig
+++ b/drivers/net/ieee802154/Kconfig
@@ -53,3 +53,13 @@ config IEEE802154_CC2520
This driver can also be built as a module. To do so, say M here.
the module will be called 'cc2520'.
+
+config IEEE802154_ATUSB
+ tristate "ATUSB transceiver driver"
+ depends on IEEE802154_DRIVERS && MAC802154 && USB
+ ---help---
+ Say Y here to enable the ATUSB IEEE 802.15.4 wireless
+ controller.
+
+ This driver can also be built as a module. To do so say M here.
+ The module will be called 'atusb'.
diff --git a/drivers/net/ieee802154/Makefile b/drivers/net/ieee802154/Makefile
index d77fa4d77e27..cf1d2a6db023 100644
--- a/drivers/net/ieee802154/Makefile
+++ b/drivers/net/ieee802154/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o
obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o
obj-$(CONFIG_IEEE802154_CC2520) += cc2520.o
+obj-$(CONFIG_IEEE802154_ATUSB) += atusb.o
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
index 67d00fbc2e0e..f7bd9f3ddaac 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -35,6 +35,8 @@
#include <net/mac802154.h>
#include <net/cfg802154.h>
+#include "at86rf230.h"
+
struct at86rf230_local;
/* at86rf2xx chip depend data.
* All timings are in us.
@@ -45,12 +47,14 @@ struct at86rf2xx_chip_data {
u16 t_reset_to_off;
u16 t_off_to_aack;
u16 t_off_to_tx_on;
+ u16 t_off_to_sleep;
+ u16 t_sleep_to_off;
u16 t_frame;
u16 t_p_ack;
int rssi_base_val;
int (*set_channel)(struct at86rf230_local *, u8, u8);
- int (*get_desense_steps)(struct at86rf230_local *, s32);
+ int (*set_txpower)(struct at86rf230_local *, s32);
};
#define AT86RF2XX_MAX_BUF (127 + 3)
@@ -86,6 +90,7 @@ struct at86rf230_local {
struct at86rf2xx_chip_data *data;
struct regmap *regmap;
int slp_tr;
+ bool sleep;
struct completion state_complete;
struct at86rf230_state_change state;
@@ -102,200 +107,6 @@ struct at86rf230_local {
struct at86rf230_state_change tx;
};
-#define RG_TRX_STATUS (0x01)
-#define SR_TRX_STATUS 0x01, 0x1f, 0
-#define SR_RESERVED_01_3 0x01, 0x20, 5
-#define SR_CCA_STATUS 0x01, 0x40, 6
-#define SR_CCA_DONE 0x01, 0x80, 7
-#define RG_TRX_STATE (0x02)
-#define SR_TRX_CMD 0x02, 0x1f, 0
-#define SR_TRAC_STATUS 0x02, 0xe0, 5
-#define RG_TRX_CTRL_0 (0x03)
-#define SR_CLKM_CTRL 0x03, 0x07, 0
-#define SR_CLKM_SHA_SEL 0x03, 0x08, 3
-#define SR_PAD_IO_CLKM 0x03, 0x30, 4
-#define SR_PAD_IO 0x03, 0xc0, 6
-#define RG_TRX_CTRL_1 (0x04)
-#define SR_IRQ_POLARITY 0x04, 0x01, 0
-#define SR_IRQ_MASK_MODE 0x04, 0x02, 1
-#define SR_SPI_CMD_MODE 0x04, 0x0c, 2
-#define SR_RX_BL_CTRL 0x04, 0x10, 4
-#define SR_TX_AUTO_CRC_ON 0x04, 0x20, 5
-#define SR_IRQ_2_EXT_EN 0x04, 0x40, 6
-#define SR_PA_EXT_EN 0x04, 0x80, 7
-#define RG_PHY_TX_PWR (0x05)
-#define SR_TX_PWR 0x05, 0x0f, 0
-#define SR_PA_LT 0x05, 0x30, 4
-#define SR_PA_BUF_LT 0x05, 0xc0, 6
-#define RG_PHY_RSSI (0x06)
-#define SR_RSSI 0x06, 0x1f, 0
-#define SR_RND_VALUE 0x06, 0x60, 5
-#define SR_RX_CRC_VALID 0x06, 0x80, 7
-#define RG_PHY_ED_LEVEL (0x07)
-#define SR_ED_LEVEL 0x07, 0xff, 0
-#define RG_PHY_CC_CCA (0x08)
-#define SR_CHANNEL 0x08, 0x1f, 0
-#define SR_CCA_MODE 0x08, 0x60, 5
-#define SR_CCA_REQUEST 0x08, 0x80, 7
-#define RG_CCA_THRES (0x09)
-#define SR_CCA_ED_THRES 0x09, 0x0f, 0
-#define SR_RESERVED_09_1 0x09, 0xf0, 4
-#define RG_RX_CTRL (0x0a)
-#define SR_PDT_THRES 0x0a, 0x0f, 0
-#define SR_RESERVED_0a_1 0x0a, 0xf0, 4
-#define RG_SFD_VALUE (0x0b)
-#define SR_SFD_VALUE 0x0b, 0xff, 0
-#define RG_TRX_CTRL_2 (0x0c)
-#define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0
-#define SR_SUB_MODE 0x0c, 0x04, 2
-#define SR_BPSK_QPSK 0x0c, 0x08, 3
-#define SR_OQPSK_SUB1_RC_EN 0x0c, 0x10, 4
-#define SR_RESERVED_0c_5 0x0c, 0x60, 5
-#define SR_RX_SAFE_MODE 0x0c, 0x80, 7
-#define RG_ANT_DIV (0x0d)
-#define SR_ANT_CTRL 0x0d, 0x03, 0
-#define SR_ANT_EXT_SW_EN 0x0d, 0x04, 2
-#define SR_ANT_DIV_EN 0x0d, 0x08, 3
-#define SR_RESERVED_0d_2 0x0d, 0x70, 4
-#define SR_ANT_SEL 0x0d, 0x80, 7
-#define RG_IRQ_MASK (0x0e)
-#define SR_IRQ_MASK 0x0e, 0xff, 0
-#define RG_IRQ_STATUS (0x0f)
-#define SR_IRQ_0_PLL_LOCK 0x0f, 0x01, 0
-#define SR_IRQ_1_PLL_UNLOCK 0x0f, 0x02, 1
-#define SR_IRQ_2_RX_START 0x0f, 0x04, 2
-#define SR_IRQ_3_TRX_END 0x0f, 0x08, 3
-#define SR_IRQ_4_CCA_ED_DONE 0x0f, 0x10, 4
-#define SR_IRQ_5_AMI 0x0f, 0x20, 5
-#define SR_IRQ_6_TRX_UR 0x0f, 0x40, 6
-#define SR_IRQ_7_BAT_LOW 0x0f, 0x80, 7
-#define RG_VREG_CTRL (0x10)
-#define SR_RESERVED_10_6 0x10, 0x03, 0
-#define SR_DVDD_OK 0x10, 0x04, 2
-#define SR_DVREG_EXT 0x10, 0x08, 3
-#define SR_RESERVED_10_3 0x10, 0x30, 4
-#define SR_AVDD_OK 0x10, 0x40, 6
-#define SR_AVREG_EXT 0x10, 0x80, 7
-#define RG_BATMON (0x11)
-#define SR_BATMON_VTH 0x11, 0x0f, 0
-#define SR_BATMON_HR 0x11, 0x10, 4
-#define SR_BATMON_OK 0x11, 0x20, 5
-#define SR_RESERVED_11_1 0x11, 0xc0, 6
-#define RG_XOSC_CTRL (0x12)
-#define SR_XTAL_TRIM 0x12, 0x0f, 0
-#define SR_XTAL_MODE 0x12, 0xf0, 4
-#define RG_RX_SYN (0x15)
-#define SR_RX_PDT_LEVEL 0x15, 0x0f, 0
-#define SR_RESERVED_15_2 0x15, 0x70, 4
-#define SR_RX_PDT_DIS 0x15, 0x80, 7
-#define RG_XAH_CTRL_1 (0x17)
-#define SR_RESERVED_17_8 0x17, 0x01, 0
-#define SR_AACK_PROM_MODE 0x17, 0x02, 1
-#define SR_AACK_ACK_TIME 0x17, 0x04, 2
-#define SR_RESERVED_17_5 0x17, 0x08, 3
-#define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4
-#define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5
-#define SR_CSMA_LBT_MODE 0x17, 0x40, 6
-#define SR_RESERVED_17_1 0x17, 0x80, 7
-#define RG_FTN_CTRL (0x18)
-#define SR_RESERVED_18_2 0x18, 0x7f, 0
-#define SR_FTN_START 0x18, 0x80, 7
-#define RG_PLL_CF (0x1a)
-#define SR_RESERVED_1a_2 0x1a, 0x7f, 0
-#define SR_PLL_CF_START 0x1a, 0x80, 7
-#define RG_PLL_DCU (0x1b)
-#define SR_RESERVED_1b_3 0x1b, 0x3f, 0
-#define SR_RESERVED_1b_2 0x1b, 0x40, 6
-#define SR_PLL_DCU_START 0x1b, 0x80, 7
-#define RG_PART_NUM (0x1c)
-#define SR_PART_NUM 0x1c, 0xff, 0
-#define RG_VERSION_NUM (0x1d)
-#define SR_VERSION_NUM 0x1d, 0xff, 0
-#define RG_MAN_ID_0 (0x1e)
-#define SR_MAN_ID_0 0x1e, 0xff, 0
-#define RG_MAN_ID_1 (0x1f)
-#define SR_MAN_ID_1 0x1f, 0xff, 0
-#define RG_SHORT_ADDR_0 (0x20)
-#define SR_SHORT_ADDR_0 0x20, 0xff, 0
-#define RG_SHORT_ADDR_1 (0x21)
-#define SR_SHORT_ADDR_1 0x21, 0xff, 0
-#define RG_PAN_ID_0 (0x22)
-#define SR_PAN_ID_0 0x22, 0xff, 0
-#define RG_PAN_ID_1 (0x23)
-#define SR_PAN_ID_1 0x23, 0xff, 0
-#define RG_IEEE_ADDR_0 (0x24)
-#define SR_IEEE_ADDR_0 0x24, 0xff, 0
-#define RG_IEEE_ADDR_1 (0x25)
-#define SR_IEEE_ADDR_1 0x25, 0xff, 0
-#define RG_IEEE_ADDR_2 (0x26)
-#define SR_IEEE_ADDR_2 0x26, 0xff, 0
-#define RG_IEEE_ADDR_3 (0x27)
-#define SR_IEEE_ADDR_3 0x27, 0xff, 0
-#define RG_IEEE_ADDR_4 (0x28)
-#define SR_IEEE_ADDR_4 0x28, 0xff, 0
-#define RG_IEEE_ADDR_5 (0x29)
-#define SR_IEEE_ADDR_5 0x29, 0xff, 0
-#define RG_IEEE_ADDR_6 (0x2a)
-#define SR_IEEE_ADDR_6 0x2a, 0xff, 0
-#define RG_IEEE_ADDR_7 (0x2b)
-#define SR_IEEE_ADDR_7 0x2b, 0xff, 0
-#define RG_XAH_CTRL_0 (0x2c)
-#define SR_SLOTTED_OPERATION 0x2c, 0x01, 0
-#define SR_MAX_CSMA_RETRIES 0x2c, 0x0e, 1
-#define SR_MAX_FRAME_RETRIES 0x2c, 0xf0, 4
-#define RG_CSMA_SEED_0 (0x2d)
-#define SR_CSMA_SEED_0 0x2d, 0xff, 0
-#define RG_CSMA_SEED_1 (0x2e)
-#define SR_CSMA_SEED_1 0x2e, 0x07, 0
-#define SR_AACK_I_AM_COORD 0x2e, 0x08, 3
-#define SR_AACK_DIS_ACK 0x2e, 0x10, 4
-#define SR_AACK_SET_PD 0x2e, 0x20, 5
-#define SR_AACK_FVN_MODE 0x2e, 0xc0, 6
-#define RG_CSMA_BE (0x2f)
-#define SR_MIN_BE 0x2f, 0x0f, 0
-#define SR_MAX_BE 0x2f, 0xf0, 4
-
-#define CMD_REG 0x80
-#define CMD_REG_MASK 0x3f
-#define CMD_WRITE 0x40
-#define CMD_FB 0x20
-
-#define IRQ_BAT_LOW (1 << 7)
-#define IRQ_TRX_UR (1 << 6)
-#define IRQ_AMI (1 << 5)
-#define IRQ_CCA_ED (1 << 4)
-#define IRQ_TRX_END (1 << 3)
-#define IRQ_RX_START (1 << 2)
-#define IRQ_PLL_UNL (1 << 1)
-#define IRQ_PLL_LOCK (1 << 0)
-
-#define IRQ_ACTIVE_HIGH 0
-#define IRQ_ACTIVE_LOW 1
-
-#define STATE_P_ON 0x00 /* BUSY */
-#define STATE_BUSY_RX 0x01
-#define STATE_BUSY_TX 0x02
-#define STATE_FORCE_TRX_OFF 0x03
-#define STATE_FORCE_TX_ON 0x04 /* IDLE */
-/* 0x05 */ /* INVALID_PARAMETER */
-#define STATE_RX_ON 0x06
-/* 0x07 */ /* SUCCESS */
-#define STATE_TRX_OFF 0x08
-#define STATE_TX_ON 0x09
-/* 0x0a - 0x0e */ /* 0x0a - UNSUPPORTED_ATTRIBUTE */
-#define STATE_SLEEP 0x0F
-#define STATE_PREP_DEEP_SLEEP 0x10
-#define STATE_BUSY_RX_AACK 0x11
-#define STATE_BUSY_TX_ARET 0x12
-#define STATE_RX_AACK_ON 0x16
-#define STATE_TX_ARET_ON 0x19
-#define STATE_RX_ON_NOCLK 0x1C
-#define STATE_RX_AACK_ON_NOCLK 0x1D
-#define STATE_BUSY_RX_AACK_NOCLK 0x1E
-#define STATE_TRANSITION_IN_PROGRESS 0x1F
-
-#define TRX_STATE_MASK (0x1F)
-
#define AT86RF2XX_NUMREGS 0x3F
static void
@@ -304,18 +115,66 @@ at86rf230_async_state_change(struct at86rf230_local *lp,
const u8 state, void (*complete)(void *context),
const bool irq_enable);
+static inline void
+at86rf230_sleep(struct at86rf230_local *lp)
+{
+ if (gpio_is_valid(lp->slp_tr)) {
+ gpio_set_value(lp->slp_tr, 1);
+ usleep_range(lp->data->t_off_to_sleep,
+ lp->data->t_off_to_sleep + 10);
+ lp->sleep = true;
+ }
+}
+
+static inline void
+at86rf230_awake(struct at86rf230_local *lp)
+{
+ if (gpio_is_valid(lp->slp_tr)) {
+ gpio_set_value(lp->slp_tr, 0);
+ usleep_range(lp->data->t_sleep_to_off,
+ lp->data->t_sleep_to_off + 100);
+ lp->sleep = false;
+ }
+}
+
static inline int
__at86rf230_write(struct at86rf230_local *lp,
unsigned int addr, unsigned int data)
{
- return regmap_write(lp->regmap, addr, data);
+ bool sleep = lp->sleep;
+ int ret;
+
+ /* awake for register setting if sleep */
+ if (sleep)
+ at86rf230_awake(lp);
+
+ ret = regmap_write(lp->regmap, addr, data);
+
+ /* sleep again if was sleeping */
+ if (sleep)
+ at86rf230_sleep(lp);
+
+ return ret;
}
static inline int
__at86rf230_read(struct at86rf230_local *lp,
unsigned int addr, unsigned int *data)
{
- return regmap_read(lp->regmap, addr, data);
+ bool sleep = lp->sleep;
+ int ret;
+
+ /* awake for register setting if sleep */
+ if (sleep)
+ at86rf230_awake(lp);
+
+ ret = regmap_read(lp->regmap, addr, data);
+
+ /* sleep again if was sleeping */
+ if (sleep)
+ at86rf230_sleep(lp);
+
+ return ret;
}
static inline int
@@ -337,7 +196,20 @@ at86rf230_write_subreg(struct at86rf230_local *lp,
unsigned int addr, unsigned int mask,
unsigned int shift, unsigned int data)
{
- return regmap_update_bits(lp->regmap, addr, mask, data << shift);
+ bool sleep = lp->sleep;
+ int ret;
+
+ /* awake for register setting if sleep */
+ if (sleep)
+ at86rf230_awake(lp);
+
+ ret = regmap_update_bits(lp->regmap, addr, mask, data << shift);
+
+ /* sleep again if was sleeping */
+ if (sleep)
+ at86rf230_sleep(lp);
+
+ return ret;
}
static inline void
@@ -1010,7 +882,7 @@ at86rf230_xmit_start(void *context)
if (lp->is_tx_from_off) {
lp->is_tx_from_off = false;
at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
- at86rf230_xmit_tx_on,
+ at86rf230_write_frame,
false);
} else {
at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
@@ -1061,13 +933,34 @@ at86rf230_ed(struct ieee802154_hw *hw, u8 *level)
static int
at86rf230_start(struct ieee802154_hw *hw)
{
- return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON);
+ struct at86rf230_local *lp = hw->priv;
+
+ at86rf230_awake(lp);
+ enable_irq(lp->spi->irq);
+
+ return at86rf230_sync_state_change(lp, STATE_RX_AACK_ON);
}
static void
at86rf230_stop(struct ieee802154_hw *hw)
{
- at86rf230_sync_state_change(hw->priv, STATE_FORCE_TRX_OFF);
+ struct at86rf230_local *lp = hw->priv;
+ u8 csma_seed[2];
+
+ at86rf230_sync_state_change(lp, STATE_FORCE_TRX_OFF);
+
+ disable_irq(lp->spi->irq);
+
+ /* It's recommended to set random new csma_seeds before sleep state.
+ * Makes only sense in the stop callback, not doing this inside of
+ * at86rf230_sleep, this is also used when we don't transmit afterwards
+ * when calling start callback again.
+ */
+ get_random_bytes(csma_seed, ARRAY_SIZE(csma_seed));
+ at86rf230_write_subreg(lp, SR_CSMA_SEED_0, csma_seed[0]);
+ at86rf230_write_subreg(lp, SR_CSMA_SEED_1, csma_seed[1]);
+
+ at86rf230_sleep(lp);
}
static int
@@ -1076,6 +969,50 @@ at86rf23x_set_channel(struct at86rf230_local *lp, u8 page, u8 channel)
return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
}
+#define AT86RF2XX_MAX_ED_LEVELS 0xF
+static const s32 at86rf23x_ed_levels[AT86RF2XX_MAX_ED_LEVELS + 1] = {
+ -9100, -8900, -8700, -8500, -8300, -8100, -7900, -7700, -7500, -7300,
+ -7100, -6900, -6700, -6500, -6300, -6100,
+};
+
+static const s32 at86rf212_ed_levels_100[AT86RF2XX_MAX_ED_LEVELS + 1] = {
+ -10000, -9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200,
+ -8000, -7800, -7600, -7400, -7200, -7000,
+};
+
+static const s32 at86rf212_ed_levels_98[AT86RF2XX_MAX_ED_LEVELS + 1] = {
+ -9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200, -8000,
+ -7800, -7600, -7400, -7200, -7000, -6800,
+};
+
+static inline int
+at86rf212_update_cca_ed_level(struct at86rf230_local *lp, int rssi_base_val)
+{
+ unsigned int cca_ed_thres;
+ int rc;
+
+ rc = at86rf230_read_subreg(lp, SR_CCA_ED_THRES, &cca_ed_thres);
+ if (rc < 0)
+ return rc;
+
+ switch (rssi_base_val) {
+ case -98:
+ lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_98;
+ lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_98);
+ lp->hw->phy->cca_ed_level = at86rf212_ed_levels_98[cca_ed_thres];
+ break;
+ case -100:
+ lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_100;
+ lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_100);
+ lp->hw->phy->cca_ed_level = at86rf212_ed_levels_100[cca_ed_thres];
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ return 0;
+}
+
static int
at86rf212_set_channel(struct at86rf230_local *lp, u8 page, u8 channel)
{
@@ -1098,6 +1035,10 @@ at86rf212_set_channel(struct at86rf230_local *lp, u8 page, u8 channel)
if (rc < 0)
return rc;
+ rc = at86rf212_update_cca_ed_level(lp, lp->data->rssi_base_val);
+ if (rc < 0)
+ return rc;
+
/* This sets the symbol_duration according frequency on the 212.
* TODO move this handling while set channel and page in cfg802154.
* We can do that, this timings are according 802.15.4 standard.
@@ -1193,23 +1134,56 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw,
return 0;
}
+#define AT86RF23X_MAX_TX_POWERS 0xF
+static const s32 at86rf233_powers[AT86RF23X_MAX_TX_POWERS + 1] = {
+ 400, 370, 340, 300, 250, 200, 100, 0, -100, -200, -300, -400, -600,
+ -800, -1200, -1700,
+};
+
+static const s32 at86rf231_powers[AT86RF23X_MAX_TX_POWERS + 1] = {
+ 300, 280, 230, 180, 130, 70, 0, -100, -200, -300, -400, -500, -700,
+ -900, -1200, -1700,
+};
+
+#define AT86RF212_MAX_TX_POWERS 0x1F
+static const s32 at86rf212_powers[AT86RF212_MAX_TX_POWERS + 1] = {
+ 500, 400, 300, 200, 100, 0, -100, -200, -300, -400, -500, -600, -700,
+ -800, -900, -1000, -1100, -1200, -1300, -1400, -1500, -1600, -1700,
+ -1800, -1900, -2000, -2100, -2200, -2300, -2400, -2500, -2600,
+};
+
static int
-at86rf230_set_txpower(struct ieee802154_hw *hw, s8 db)
+at86rf23x_set_txpower(struct at86rf230_local *lp, s32 mbm)
{
- struct at86rf230_local *lp = hw->priv;
+ u32 i;
- /* typical maximum output is 5dBm with RG_PHY_TX_PWR 0x60, lower five
- * bits decrease power in 1dB steps. 0x60 represents extra PA gain of
- * 0dB.
- * thus, supported values for db range from -26 to 5, for 31dB of
- * reduction to 0dB of reduction.
- */
- if (db > 5 || db < -26)
- return -EINVAL;
+ for (i = 0; i < lp->hw->phy->supported.tx_powers_size; i++) {
+ if (lp->hw->phy->supported.tx_powers[i] == mbm)
+ return at86rf230_write_subreg(lp, SR_TX_PWR_23X, i);
+ }
+
+ return -EINVAL;
+}
+
+static int
+at86rf212_set_txpower(struct at86rf230_local *lp, s32 mbm)
+{
+ u32 i;
- db = -(db - 5);
+ for (i = 0; i < lp->hw->phy->supported.tx_powers_size; i++) {
+ if (lp->hw->phy->supported.tx_powers[i] == mbm)
+ return at86rf230_write_subreg(lp, SR_TX_PWR_212, i);
+ }
- return __at86rf230_write(lp, RG_PHY_TX_PWR, 0x60 | db);
+ return -EINVAL;
+}
+
+static int
+at86rf230_set_txpower(struct ieee802154_hw *hw, s32 mbm)
+{
+ struct at86rf230_local *lp = hw->priv;
+
+ return lp->data->set_txpower(lp, mbm);
}
static int
@@ -1254,28 +1228,19 @@ at86rf230_set_cca_mode(struct ieee802154_hw *hw,
return at86rf230_write_subreg(lp, SR_CCA_MODE, val);
}
-static int
-at86rf212_get_desens_steps(struct at86rf230_local *lp, s32 level)
-{
- return (level - lp->data->rssi_base_val) * 100 / 207;
-}
-
-static int
-at86rf23x_get_desens_steps(struct at86rf230_local *lp, s32 level)
-{
- return (level - lp->data->rssi_base_val) / 2;
-}
static int
-at86rf230_set_cca_ed_level(struct ieee802154_hw *hw, s32 level)
+at86rf230_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm)
{
struct at86rf230_local *lp = hw->priv;
+ u32 i;
- if (level < lp->data->rssi_base_val || level > 30)
- return -EINVAL;
+ for (i = 0; i < hw->phy->supported.cca_ed_levels_size; i++) {
+ if (hw->phy->supported.cca_ed_levels[i] == mbm)
+ return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, i);
+ }
- return at86rf230_write_subreg(lp, SR_CCA_ED_THRES,
- lp->data->get_desense_steps(lp, level));
+ return -EINVAL;
}
static int
@@ -1361,11 +1326,13 @@ static struct at86rf2xx_chip_data at86rf233_data = {
.t_reset_to_off = 26,
.t_off_to_aack = 80,
.t_off_to_tx_on = 80,
+ .t_off_to_sleep = 35,
+ .t_sleep_to_off = 210,
.t_frame = 4096,
.t_p_ack = 545,
.rssi_base_val = -91,
.set_channel = at86rf23x_set_channel,
- .get_desense_steps = at86rf23x_get_desens_steps
+ .set_txpower = at86rf23x_set_txpower,
};
static struct at86rf2xx_chip_data at86rf231_data = {
@@ -1374,11 +1341,13 @@ static struct at86rf2xx_chip_data at86rf231_data = {
.t_reset_to_off = 37,
.t_off_to_aack = 110,
.t_off_to_tx_on = 110,
+ .t_off_to_sleep = 35,
+ .t_sleep_to_off = 380,
.t_frame = 4096,
.t_p_ack = 545,
.rssi_base_val = -91,
.set_channel = at86rf23x_set_channel,
- .get_desense_steps = at86rf23x_get_desens_steps
+ .set_txpower = at86rf23x_set_txpower,
};
static struct at86rf2xx_chip_data at86rf212_data = {
@@ -1387,11 +1356,13 @@ static struct at86rf2xx_chip_data at86rf212_data = {
.t_reset_to_off = 26,
.t_off_to_aack = 200,
.t_off_to_tx_on = 200,
+ .t_off_to_sleep = 35,
+ .t_sleep_to_off = 380,
.t_frame = 4096,
.t_p_ack = 545,
.rssi_base_val = -100,
.set_channel = at86rf212_set_channel,
- .get_desense_steps = at86rf212_get_desens_steps
+ .set_txpower = at86rf212_set_txpower,
};
static int at86rf230_hw_init(struct at86rf230_local *lp, u8 xtal_trim)
@@ -1563,9 +1534,22 @@ at86rf230_detect_device(struct at86rf230_local *lp)
return -EINVAL;
}
- lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AACK |
- IEEE802154_HW_TXPOWER | IEEE802154_HW_ARET |
- IEEE802154_HW_AFILT | IEEE802154_HW_PROMISCUOUS;
+ lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM |
+ IEEE802154_HW_CSMA_PARAMS |
+ IEEE802154_HW_FRAME_RETRIES | IEEE802154_HW_AFILT |
+ IEEE802154_HW_PROMISCUOUS;
+
+ lp->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER |
+ WPAN_PHY_FLAG_CCA_ED_LEVEL |
+ WPAN_PHY_FLAG_CCA_MODE;
+
+ lp->hw->phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY) |
+ BIT(NL802154_CCA_CARRIER) | BIT(NL802154_CCA_ENERGY_CARRIER);
+ lp->hw->phy->supported.cca_opts = BIT(NL802154_CCA_OPT_ENERGY_CARRIER_AND) |
+ BIT(NL802154_CCA_OPT_ENERGY_CARRIER_OR);
+
+ lp->hw->phy->supported.cca_ed_levels = at86rf23x_ed_levels;
+ lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf23x_ed_levels);
lp->hw->phy->cca.mode = NL802154_CCA_ENERGY;
@@ -1573,36 +1557,49 @@ at86rf230_detect_device(struct at86rf230_local *lp)
case 2:
chip = "at86rf230";
rc = -ENOTSUPP;
- break;
+ goto not_supp;
case 3:
chip = "at86rf231";
lp->data = &at86rf231_data;
- lp->hw->phy->channels_supported[0] = 0x7FFF800;
+ lp->hw->phy->supported.channels[0] = 0x7FFF800;
lp->hw->phy->current_channel = 11;
lp->hw->phy->symbol_duration = 16;
+ lp->hw->phy->supported.tx_powers = at86rf231_powers;
+ lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf231_powers);
break;
case 7:
chip = "at86rf212";
lp->data = &at86rf212_data;
lp->hw->flags |= IEEE802154_HW_LBT;
- lp->hw->phy->channels_supported[0] = 0x00007FF;
- lp->hw->phy->channels_supported[2] = 0x00007FF;
+ lp->hw->phy->supported.channels[0] = 0x00007FF;
+ lp->hw->phy->supported.channels[2] = 0x00007FF;
lp->hw->phy->current_channel = 5;
lp->hw->phy->symbol_duration = 25;
+ lp->hw->phy->supported.lbt = NL802154_SUPPORTED_BOOL_BOTH;
+ lp->hw->phy->supported.tx_powers = at86rf212_powers;
+ lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf212_powers);
+ lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_100;
+ lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_100);
break;
case 11:
chip = "at86rf233";
lp->data = &at86rf233_data;
- lp->hw->phy->channels_supported[0] = 0x7FFF800;
+ lp->hw->phy->supported.channels[0] = 0x7FFF800;
lp->hw->phy->current_channel = 13;
lp->hw->phy->symbol_duration = 16;
+ lp->hw->phy->supported.tx_powers = at86rf233_powers;
+ lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf233_powers);
break;
default:
chip = "unknown";
rc = -ENOTSUPP;
- break;
+ goto not_supp;
}
+ lp->hw->phy->cca_ed_level = lp->hw->phy->supported.cca_ed_levels[7];
+ lp->hw->phy->transmit_power = lp->hw->phy->supported.tx_powers[0];
+
+not_supp:
dev_info(&lp->spi->dev, "Detected %s chip version %d\n", chip, version);
return rc;
@@ -1696,7 +1693,6 @@ static int at86rf230_probe(struct spi_device *spi)
lp->spi = spi;
lp->slp_tr = slp_tr;
hw->parent = &spi->dev;
- hw->vif_data_size = sizeof(*lp);
ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
lp->regmap = devm_regmap_init_spi(spi, &at86rf230_regmap_spi_config);
@@ -1728,13 +1724,19 @@ static int at86rf230_probe(struct spi_device *spi)
irq_type = irq_get_trigger_type(spi->irq);
if (!irq_type)
- irq_type = IRQF_TRIGGER_RISING;
+ irq_type = IRQF_TRIGGER_HIGH;
rc = devm_request_irq(&spi->dev, spi->irq, at86rf230_isr,
IRQF_SHARED | irq_type, dev_name(&spi->dev), lp);
if (rc)
goto free_dev;
+ /* disable_irq by default and wait for starting hardware */
+ disable_irq(spi->irq);
+
+ /* going into sleep by default */
+ at86rf230_sleep(lp);
+
rc = ieee802154_register_hw(lp->hw);
if (rc)
goto free_dev;
diff --git a/drivers/net/ieee802154/at86rf230.h b/drivers/net/ieee802154/at86rf230.h
new file mode 100644
index 000000000000..1e6d1cc677f6
--- /dev/null
+++ b/drivers/net/ieee802154/at86rf230.h
@@ -0,0 +1,220 @@
+/*
+ * AT86RF230/RF231 driver
+ *
+ * Copyright (C) 2009-2012 Siemens AG
+ *
+ * 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.
+ *
+ * Written by:
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ */
+
+#ifndef _AT86RF230_H
+#define _AT86RF230_H
+
+#define RG_TRX_STATUS (0x01)
+#define SR_TRX_STATUS 0x01, 0x1f, 0
+#define SR_RESERVED_01_3 0x01, 0x20, 5
+#define SR_CCA_STATUS 0x01, 0x40, 6
+#define SR_CCA_DONE 0x01, 0x80, 7
+#define RG_TRX_STATE (0x02)
+#define SR_TRX_CMD 0x02, 0x1f, 0
+#define SR_TRAC_STATUS 0x02, 0xe0, 5
+#define RG_TRX_CTRL_0 (0x03)
+#define SR_CLKM_CTRL 0x03, 0x07, 0
+#define SR_CLKM_SHA_SEL 0x03, 0x08, 3
+#define SR_PAD_IO_CLKM 0x03, 0x30, 4
+#define SR_PAD_IO 0x03, 0xc0, 6
+#define RG_TRX_CTRL_1 (0x04)
+#define SR_IRQ_POLARITY 0x04, 0x01, 0
+#define SR_IRQ_MASK_MODE 0x04, 0x02, 1
+#define SR_SPI_CMD_MODE 0x04, 0x0c, 2
+#define SR_RX_BL_CTRL 0x04, 0x10, 4
+#define SR_TX_AUTO_CRC_ON 0x04, 0x20, 5
+#define SR_IRQ_2_EXT_EN 0x04, 0x40, 6
+#define SR_PA_EXT_EN 0x04, 0x80, 7
+#define RG_PHY_TX_PWR (0x05)
+#define SR_TX_PWR_23X 0x05, 0x0f, 0
+#define SR_PA_LT_230 0x05, 0x30, 4
+#define SR_PA_BUF_LT_230 0x05, 0xc0, 6
+#define SR_TX_PWR_212 0x05, 0x1f, 0
+#define SR_GC_PA_212 0x05, 0x60, 5
+#define SR_PA_BOOST_LT_212 0x05, 0x80, 7
+#define RG_PHY_RSSI (0x06)
+#define SR_RSSI 0x06, 0x1f, 0
+#define SR_RND_VALUE 0x06, 0x60, 5
+#define SR_RX_CRC_VALID 0x06, 0x80, 7
+#define RG_PHY_ED_LEVEL (0x07)
+#define SR_ED_LEVEL 0x07, 0xff, 0
+#define RG_PHY_CC_CCA (0x08)
+#define SR_CHANNEL 0x08, 0x1f, 0
+#define SR_CCA_MODE 0x08, 0x60, 5
+#define SR_CCA_REQUEST 0x08, 0x80, 7
+#define RG_CCA_THRES (0x09)
+#define SR_CCA_ED_THRES 0x09, 0x0f, 0
+#define SR_RESERVED_09_1 0x09, 0xf0, 4
+#define RG_RX_CTRL (0x0a)
+#define SR_PDT_THRES 0x0a, 0x0f, 0
+#define SR_RESERVED_0a_1 0x0a, 0xf0, 4
+#define RG_SFD_VALUE (0x0b)
+#define SR_SFD_VALUE 0x0b, 0xff, 0
+#define RG_TRX_CTRL_2 (0x0c)
+#define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0
+#define SR_SUB_MODE 0x0c, 0x04, 2
+#define SR_BPSK_QPSK 0x0c, 0x08, 3
+#define SR_OQPSK_SUB1_RC_EN 0x0c, 0x10, 4
+#define SR_RESERVED_0c_5 0x0c, 0x60, 5
+#define SR_RX_SAFE_MODE 0x0c, 0x80, 7
+#define RG_ANT_DIV (0x0d)
+#define SR_ANT_CTRL 0x0d, 0x03, 0
+#define SR_ANT_EXT_SW_EN 0x0d, 0x04, 2
+#define SR_ANT_DIV_EN 0x0d, 0x08, 3
+#define SR_RESERVED_0d_2 0x0d, 0x70, 4
+#define SR_ANT_SEL 0x0d, 0x80, 7
+#define RG_IRQ_MASK (0x0e)
+#define SR_IRQ_MASK 0x0e, 0xff, 0
+#define RG_IRQ_STATUS (0x0f)
+#define SR_IRQ_0_PLL_LOCK 0x0f, 0x01, 0
+#define SR_IRQ_1_PLL_UNLOCK 0x0f, 0x02, 1
+#define SR_IRQ_2_RX_START 0x0f, 0x04, 2
+#define SR_IRQ_3_TRX_END 0x0f, 0x08, 3
+#define SR_IRQ_4_CCA_ED_DONE 0x0f, 0x10, 4
+#define SR_IRQ_5_AMI 0x0f, 0x20, 5
+#define SR_IRQ_6_TRX_UR 0x0f, 0x40, 6
+#define SR_IRQ_7_BAT_LOW 0x0f, 0x80, 7
+#define RG_VREG_CTRL (0x10)
+#define SR_RESERVED_10_6 0x10, 0x03, 0
+#define SR_DVDD_OK 0x10, 0x04, 2
+#define SR_DVREG_EXT 0x10, 0x08, 3
+#define SR_RESERVED_10_3 0x10, 0x30, 4
+#define SR_AVDD_OK 0x10, 0x40, 6
+#define SR_AVREG_EXT 0x10, 0x80, 7
+#define RG_BATMON (0x11)
+#define SR_BATMON_VTH 0x11, 0x0f, 0
+#define SR_BATMON_HR 0x11, 0x10, 4
+#define SR_BATMON_OK 0x11, 0x20, 5
+#define SR_RESERVED_11_1 0x11, 0xc0, 6
+#define RG_XOSC_CTRL (0x12)
+#define SR_XTAL_TRIM 0x12, 0x0f, 0
+#define SR_XTAL_MODE 0x12, 0xf0, 4
+#define RG_RX_SYN (0x15)
+#define SR_RX_PDT_LEVEL 0x15, 0x0f, 0
+#define SR_RESERVED_15_2 0x15, 0x70, 4
+#define SR_RX_PDT_DIS 0x15, 0x80, 7
+#define RG_XAH_CTRL_1 (0x17)
+#define SR_RESERVED_17_8 0x17, 0x01, 0
+#define SR_AACK_PROM_MODE 0x17, 0x02, 1
+#define SR_AACK_ACK_TIME 0x17, 0x04, 2
+#define SR_RESERVED_17_5 0x17, 0x08, 3
+#define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4
+#define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5
+#define SR_CSMA_LBT_MODE 0x17, 0x40, 6
+#define SR_RESERVED_17_1 0x17, 0x80, 7
+#define RG_FTN_CTRL (0x18)
+#define SR_RESERVED_18_2 0x18, 0x7f, 0
+#define SR_FTN_START 0x18, 0x80, 7
+#define RG_PLL_CF (0x1a)
+#define SR_RESERVED_1a_2 0x1a, 0x7f, 0
+#define SR_PLL_CF_START 0x1a, 0x80, 7
+#define RG_PLL_DCU (0x1b)
+#define SR_RESERVED_1b_3 0x1b, 0x3f, 0
+#define SR_RESERVED_1b_2 0x1b, 0x40, 6
+#define SR_PLL_DCU_START 0x1b, 0x80, 7
+#define RG_PART_NUM (0x1c)
+#define SR_PART_NUM 0x1c, 0xff, 0
+#define RG_VERSION_NUM (0x1d)
+#define SR_VERSION_NUM 0x1d, 0xff, 0
+#define RG_MAN_ID_0 (0x1e)
+#define SR_MAN_ID_0 0x1e, 0xff, 0
+#define RG_MAN_ID_1 (0x1f)
+#define SR_MAN_ID_1 0x1f, 0xff, 0
+#define RG_SHORT_ADDR_0 (0x20)
+#define SR_SHORT_ADDR_0 0x20, 0xff, 0
+#define RG_SHORT_ADDR_1 (0x21)
+#define SR_SHORT_ADDR_1 0x21, 0xff, 0
+#define RG_PAN_ID_0 (0x22)
+#define SR_PAN_ID_0 0x22, 0xff, 0
+#define RG_PAN_ID_1 (0x23)
+#define SR_PAN_ID_1 0x23, 0xff, 0
+#define RG_IEEE_ADDR_0 (0x24)
+#define SR_IEEE_ADDR_0 0x24, 0xff, 0
+#define RG_IEEE_ADDR_1 (0x25)
+#define SR_IEEE_ADDR_1 0x25, 0xff, 0
+#define RG_IEEE_ADDR_2 (0x26)
+#define SR_IEEE_ADDR_2 0x26, 0xff, 0
+#define RG_IEEE_ADDR_3 (0x27)
+#define SR_IEEE_ADDR_3 0x27, 0xff, 0
+#define RG_IEEE_ADDR_4 (0x28)
+#define SR_IEEE_ADDR_4 0x28, 0xff, 0
+#define RG_IEEE_ADDR_5 (0x29)
+#define SR_IEEE_ADDR_5 0x29, 0xff, 0
+#define RG_IEEE_ADDR_6 (0x2a)
+#define SR_IEEE_ADDR_6 0x2a, 0xff, 0
+#define RG_IEEE_ADDR_7 (0x2b)
+#define SR_IEEE_ADDR_7 0x2b, 0xff, 0
+#define RG_XAH_CTRL_0 (0x2c)
+#define SR_SLOTTED_OPERATION 0x2c, 0x01, 0
+#define SR_MAX_CSMA_RETRIES 0x2c, 0x0e, 1
+#define SR_MAX_FRAME_RETRIES 0x2c, 0xf0, 4
+#define RG_CSMA_SEED_0 (0x2d)
+#define SR_CSMA_SEED_0 0x2d, 0xff, 0
+#define RG_CSMA_SEED_1 (0x2e)
+#define SR_CSMA_SEED_1 0x2e, 0x07, 0
+#define SR_AACK_I_AM_COORD 0x2e, 0x08, 3
+#define SR_AACK_DIS_ACK 0x2e, 0x10, 4
+#define SR_AACK_SET_PD 0x2e, 0x20, 5
+#define SR_AACK_FVN_MODE 0x2e, 0xc0, 6
+#define RG_CSMA_BE (0x2f)
+#define SR_MIN_BE 0x2f, 0x0f, 0
+#define SR_MAX_BE 0x2f, 0xf0, 4
+
+#define CMD_REG 0x80
+#define CMD_REG_MASK 0x3f
+#define CMD_WRITE 0x40
+#define CMD_FB 0x20
+
+#define IRQ_BAT_LOW BIT(7)
+#define IRQ_TRX_UR BIT(6)
+#define IRQ_AMI BIT(5)
+#define IRQ_CCA_ED BIT(4)
+#define IRQ_TRX_END BIT(3)
+#define IRQ_RX_START BIT(2)
+#define IRQ_PLL_UNL BIT(1)
+#define IRQ_PLL_LOCK BIT(0)
+
+#define IRQ_ACTIVE_HIGH 0
+#define IRQ_ACTIVE_LOW 1
+
+#define STATE_P_ON 0x00 /* BUSY */
+#define STATE_BUSY_RX 0x01
+#define STATE_BUSY_TX 0x02
+#define STATE_FORCE_TRX_OFF 0x03
+#define STATE_FORCE_TX_ON 0x04 /* IDLE */
+/* 0x05 */ /* INVALID_PARAMETER */
+#define STATE_RX_ON 0x06
+/* 0x07 */ /* SUCCESS */
+#define STATE_TRX_OFF 0x08
+#define STATE_TX_ON 0x09
+/* 0x0a - 0x0e */ /* 0x0a - UNSUPPORTED_ATTRIBUTE */
+#define STATE_SLEEP 0x0F
+#define STATE_PREP_DEEP_SLEEP 0x10
+#define STATE_BUSY_RX_AACK 0x11
+#define STATE_BUSY_TX_ARET 0x12
+#define STATE_RX_AACK_ON 0x16
+#define STATE_TX_ARET_ON 0x19
+#define STATE_RX_ON_NOCLK 0x1C
+#define STATE_RX_AACK_ON_NOCLK 0x1D
+#define STATE_BUSY_RX_AACK_NOCLK 0x1E
+#define STATE_TRANSITION_IN_PROGRESS 0x1F
+
+#define TRX_STATE_MASK (0x1F)
+
+#endif /* !_AT86RF230_H */
diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c
new file mode 100644
index 000000000000..80dfc725b8dc
--- /dev/null
+++ b/drivers/net/ieee802154/atusb.c
@@ -0,0 +1,762 @@
+/*
+ * atusb.c - Driver for the ATUSB IEEE 802.15.4 dongle
+ *
+ * Written 2013 by Werner Almesberger <werner@almesberger.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2
+ *
+ * Based on at86rf230.c and spi_atusb.c.
+ * at86rf230.c is
+ * Copyright (C) 2009 Siemens AG
+ * Written by: Dmitry Eremin-Solenikov <dmitry.baryshkov@siemens.com>
+ *
+ * spi_atusb.c is
+ * Copyright (c) 2011 Richard Sharpe <realrichardsharpe@gmail.com>
+ * Copyright (c) 2011 Stefan Schmidt <stefan@datenfreihafen.org>
+ * Copyright (c) 2011 Werner Almesberger <werner@almesberger.net>
+ *
+ * USB initialization is
+ * Copyright (c) 2013 Alexander Aring <alex.aring@gmail.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/usb.h>
+#include <linux/skbuff.h>
+
+#include <net/cfg802154.h>
+#include <net/mac802154.h>
+
+#include "at86rf230.h"
+#include "atusb.h"
+
+#define ATUSB_JEDEC_ATMEL 0x1f /* JEDEC manufacturer ID */
+
+#define ATUSB_NUM_RX_URBS 4 /* allow for a bit of local latency */
+#define ATUSB_ALLOC_DELAY_MS 100 /* delay after failed allocation */
+#define ATUSB_TX_TIMEOUT_MS 200 /* on the air timeout */
+
+struct atusb {
+ struct ieee802154_hw *hw;
+ struct usb_device *usb_dev;
+ int shutdown; /* non-zero if shutting down */
+ int err; /* set by first error */
+
+ /* RX variables */
+ struct delayed_work work; /* memory allocations */
+ struct usb_anchor idle_urbs; /* URBs waiting to be submitted */
+ struct usb_anchor rx_urbs; /* URBs waiting for reception */
+
+ /* TX variables */
+ struct usb_ctrlrequest tx_dr;
+ struct urb *tx_urb;
+ struct sk_buff *tx_skb;
+ uint8_t tx_ack_seq; /* current TX ACK sequence number */
+};
+
+/* ----- USB commands without data ----------------------------------------- */
+
+/* To reduce the number of error checks in the code, we record the first error
+ * in atusb->err and reject all subsequent requests until the error is cleared.
+ */
+
+static int atusb_control_msg(struct atusb *atusb, unsigned int pipe,
+ __u8 request, __u8 requesttype,
+ __u16 value, __u16 index,
+ void *data, __u16 size, int timeout)
+{
+ struct usb_device *usb_dev = atusb->usb_dev;
+ int ret;
+
+ if (atusb->err)
+ return atusb->err;
+
+ ret = usb_control_msg(usb_dev, pipe, request, requesttype,
+ value, index, data, size, timeout);
+ if (ret < 0) {
+ atusb->err = ret;
+ dev_err(&usb_dev->dev,
+ "atusb_control_msg: req 0x%02x val 0x%x idx 0x%x, error %d\n",
+ request, value, index, ret);
+ }
+ return ret;
+}
+
+static int atusb_command(struct atusb *atusb, uint8_t cmd, uint8_t arg)
+{
+ struct usb_device *usb_dev = atusb->usb_dev;
+
+ dev_dbg(&usb_dev->dev, "atusb_command: cmd = 0x%x\n", cmd);
+ return atusb_control_msg(atusb, usb_sndctrlpipe(usb_dev, 0),
+ cmd, ATUSB_REQ_TO_DEV, arg, 0, NULL, 0, 1000);
+}
+
+static int atusb_write_reg(struct atusb *atusb, uint8_t reg, uint8_t value)
+{
+ struct usb_device *usb_dev = atusb->usb_dev;
+
+ dev_dbg(&usb_dev->dev, "atusb_write_reg: 0x%02x <- 0x%02x\n",
+ reg, value);
+ return atusb_control_msg(atusb, usb_sndctrlpipe(usb_dev, 0),
+ ATUSB_REG_WRITE, ATUSB_REQ_TO_DEV,
+ value, reg, NULL, 0, 1000);
+}
+
+static int atusb_read_reg(struct atusb *atusb, uint8_t reg)
+{
+ struct usb_device *usb_dev = atusb->usb_dev;
+ int ret;
+ uint8_t value;
+
+ dev_dbg(&usb_dev->dev, "atusb: reg = 0x%x\n", reg);
+ ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
+ ATUSB_REG_READ, ATUSB_REQ_FROM_DEV,
+ 0, reg, &value, 1, 1000);
+ return ret >= 0 ? value : ret;
+}
+
+static int atusb_write_subreg(struct atusb *atusb, uint8_t reg, uint8_t mask,
+ uint8_t shift, uint8_t value)
+{
+ struct usb_device *usb_dev = atusb->usb_dev;
+ uint8_t orig, tmp;
+ int ret = 0;
+
+ dev_dbg(&usb_dev->dev, "atusb_write_subreg: 0x%02x <- 0x%02x\n",
+ reg, value);
+
+ orig = atusb_read_reg(atusb, reg);
+
+ /* Write the value only into that part of the register which is allowed
+ * by the mask. All other bits stay as before.
+ */
+ tmp = orig & ~mask;
+ tmp |= (value << shift) & mask;
+
+ if (tmp != orig)
+ ret = atusb_write_reg(atusb, reg, tmp);
+
+ return ret;
+}
+
+static int atusb_get_and_clear_error(struct atusb *atusb)
+{
+ int err = atusb->err;
+
+ atusb->err = 0;
+ return err;
+}
+
+/* ----- skb allocation ---------------------------------------------------- */
+
+#define MAX_PSDU 127
+#define MAX_RX_XFER (1 + MAX_PSDU + 2 + 1) /* PHR+PSDU+CRC+LQI */
+
+#define SKB_ATUSB(skb) (*(struct atusb **)(skb)->cb)
+
+static void atusb_in(struct urb *urb);
+
+static int atusb_submit_rx_urb(struct atusb *atusb, struct urb *urb)
+{
+ struct usb_device *usb_dev = atusb->usb_dev;
+ struct sk_buff *skb = urb->context;
+ int ret;
+
+ if (!skb) {
+ skb = alloc_skb(MAX_RX_XFER, GFP_KERNEL);
+ if (!skb) {
+ dev_warn_ratelimited(&usb_dev->dev,
+ "atusb_in: can't allocate skb\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, MAX_RX_XFER);
+ SKB_ATUSB(skb) = atusb;
+ }
+
+ usb_fill_bulk_urb(urb, usb_dev, usb_rcvbulkpipe(usb_dev, 1),
+ skb->data, MAX_RX_XFER, atusb_in, skb);
+ usb_anchor_urb(urb, &atusb->rx_urbs);
+
+ ret = usb_submit_urb(urb, GFP_KERNEL);
+ if (ret) {
+ usb_unanchor_urb(urb);
+ kfree_skb(skb);
+ urb->context = NULL;
+ }
+ return ret;
+}
+
+static void atusb_work_urbs(struct work_struct *work)
+{
+ struct atusb *atusb =
+ container_of(to_delayed_work(work), struct atusb, work);
+ struct usb_device *usb_dev = atusb->usb_dev;
+ struct urb *urb;
+ int ret;
+
+ if (atusb->shutdown)
+ return;
+
+ do {
+ urb = usb_get_from_anchor(&atusb->idle_urbs);
+ if (!urb)
+ return;
+ ret = atusb_submit_rx_urb(atusb, urb);
+ } while (!ret);
+
+ usb_anchor_urb(urb, &atusb->idle_urbs);
+ dev_warn_ratelimited(&usb_dev->dev,
+ "atusb_in: can't allocate/submit URB (%d)\n", ret);
+ schedule_delayed_work(&atusb->work,
+ msecs_to_jiffies(ATUSB_ALLOC_DELAY_MS) + 1);
+}
+
+/* ----- Asynchronous USB -------------------------------------------------- */
+
+static void atusb_tx_done(struct atusb *atusb, uint8_t seq)
+{
+ struct usb_device *usb_dev = atusb->usb_dev;
+ uint8_t expect = atusb->tx_ack_seq;
+
+ dev_dbg(&usb_dev->dev, "atusb_tx_done (0x%02x/0x%02x)\n", seq, expect);
+ if (seq == expect) {
+ /* TODO check for ifs handling in firmware */
+ ieee802154_xmit_complete(atusb->hw, atusb->tx_skb, false);
+ } else {
+ /* TODO I experience this case when atusb has a tx complete
+ * irq before probing, we should fix the firmware it's an
+ * unlikely case now that seq == expect is then true, but can
+ * happen and fail with a tx_skb = NULL;
+ */
+ ieee802154_wake_queue(atusb->hw);
+ if (atusb->tx_skb)
+ dev_kfree_skb_irq(atusb->tx_skb);
+ }
+}
+
+static void atusb_in_good(struct urb *urb)
+{
+ struct usb_device *usb_dev = urb->dev;
+ struct sk_buff *skb = urb->context;
+ struct atusb *atusb = SKB_ATUSB(skb);
+ uint8_t len, lqi;
+
+ if (!urb->actual_length) {
+ dev_dbg(&usb_dev->dev, "atusb_in: zero-sized URB ?\n");
+ return;
+ }
+
+ len = *skb->data;
+
+ if (urb->actual_length == 1) {
+ atusb_tx_done(atusb, len);
+ return;
+ }
+
+ if (len + 1 > urb->actual_length - 1) {
+ dev_dbg(&usb_dev->dev, "atusb_in: frame len %d+1 > URB %u-1\n",
+ len, urb->actual_length);
+ return;
+ }
+
+ if (!ieee802154_is_valid_psdu_len(len)) {
+ dev_dbg(&usb_dev->dev, "atusb_in: frame corrupted\n");
+ return;
+ }
+
+ lqi = skb->data[len + 1];
+ dev_dbg(&usb_dev->dev, "atusb_in: rx len %d lqi 0x%02x\n", len, lqi);
+ skb_pull(skb, 1); /* remove PHR */
+ skb_trim(skb, len); /* get payload only */
+ ieee802154_rx_irqsafe(atusb->hw, skb, lqi);
+ urb->context = NULL; /* skb is gone */
+}
+
+static void atusb_in(struct urb *urb)
+{
+ struct usb_device *usb_dev = urb->dev;
+ struct sk_buff *skb = urb->context;
+ struct atusb *atusb = SKB_ATUSB(skb);
+
+ dev_dbg(&usb_dev->dev, "atusb_in: status %d len %d\n",
+ urb->status, urb->actual_length);
+ if (urb->status) {
+ if (urb->status == -ENOENT) { /* being killed */
+ kfree_skb(skb);
+ urb->context = NULL;
+ return;
+ }
+ dev_dbg(&usb_dev->dev, "atusb_in: URB error %d\n", urb->status);
+ } else {
+ atusb_in_good(urb);
+ }
+
+ usb_anchor_urb(urb, &atusb->idle_urbs);
+ if (!atusb->shutdown)
+ schedule_delayed_work(&atusb->work, 0);
+}
+
+/* ----- URB allocation/deallocation --------------------------------------- */
+
+static void atusb_free_urbs(struct atusb *atusb)
+{
+ struct urb *urb;
+
+ while (1) {
+ urb = usb_get_from_anchor(&atusb->idle_urbs);
+ if (!urb)
+ break;
+ if (urb->context)
+ kfree_skb(urb->context);
+ usb_free_urb(urb);
+ }
+}
+
+static int atusb_alloc_urbs(struct atusb *atusb, int n)
+{
+ struct urb *urb;
+
+ while (n) {
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ atusb_free_urbs(atusb);
+ return -ENOMEM;
+ }
+ usb_anchor_urb(urb, &atusb->idle_urbs);
+ n--;
+ }
+ return 0;
+}
+
+/* ----- IEEE 802.15.4 interface operations -------------------------------- */
+
+static void atusb_xmit_complete(struct urb *urb)
+{
+ dev_dbg(&urb->dev->dev, "atusb_xmit urb completed");
+}
+
+static int atusb_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
+{
+ struct atusb *atusb = hw->priv;
+ struct usb_device *usb_dev = atusb->usb_dev;
+ int ret;
+
+ dev_dbg(&usb_dev->dev, "atusb_xmit (%d)\n", skb->len);
+ atusb->tx_skb = skb;
+ atusb->tx_ack_seq++;
+ atusb->tx_dr.wIndex = cpu_to_le16(atusb->tx_ack_seq);
+ atusb->tx_dr.wLength = cpu_to_le16(skb->len);
+
+ usb_fill_control_urb(atusb->tx_urb, usb_dev,
+ usb_sndctrlpipe(usb_dev, 0),
+ (unsigned char *)&atusb->tx_dr, skb->data,
+ skb->len, atusb_xmit_complete, NULL);
+ ret = usb_submit_urb(atusb->tx_urb, GFP_ATOMIC);
+ dev_dbg(&usb_dev->dev, "atusb_xmit done (%d)\n", ret);
+ return ret;
+}
+
+static int atusb_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
+{
+ struct atusb *atusb = hw->priv;
+ int ret;
+
+ /* This implicitly sets the CCA (Clear Channel Assessment) mode to 0,
+ * "Mode 3a, Carrier sense OR energy above threshold".
+ * We should probably make this configurable. @@@
+ */
+ ret = atusb_write_reg(atusb, RG_PHY_CC_CCA, channel);
+ if (ret < 0)
+ return ret;
+ msleep(1); /* @@@ ugly synchronization */
+ return 0;
+}
+
+static int atusb_ed(struct ieee802154_hw *hw, u8 *level)
+{
+ BUG_ON(!level);
+ *level = 0xbe;
+ return 0;
+}
+
+static int atusb_set_hw_addr_filt(struct ieee802154_hw *hw,
+ struct ieee802154_hw_addr_filt *filt,
+ unsigned long changed)
+{
+ struct atusb *atusb = hw->priv;
+ struct device *dev = &atusb->usb_dev->dev;
+
+ if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
+ u16 addr = le16_to_cpu(filt->short_addr);
+
+ dev_vdbg(dev, "atusb_set_hw_addr_filt called for saddr\n");
+ atusb_write_reg(atusb, RG_SHORT_ADDR_0, addr);
+ atusb_write_reg(atusb, RG_SHORT_ADDR_1, addr >> 8);
+ }
+
+ if (changed & IEEE802154_AFILT_PANID_CHANGED) {
+ u16 pan = le16_to_cpu(filt->pan_id);
+
+ dev_vdbg(dev, "atusb_set_hw_addr_filt called for pan id\n");
+ atusb_write_reg(atusb, RG_PAN_ID_0, pan);
+ atusb_write_reg(atusb, RG_PAN_ID_1, pan >> 8);
+ }
+
+ if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
+ u8 i, addr[IEEE802154_EXTENDED_ADDR_LEN];
+
+ memcpy(addr, &filt->ieee_addr, IEEE802154_EXTENDED_ADDR_LEN);
+ dev_vdbg(dev, "atusb_set_hw_addr_filt called for IEEE addr\n");
+ for (i = 0; i < 8; i++)
+ atusb_write_reg(atusb, RG_IEEE_ADDR_0 + i, addr[i]);
+ }
+
+ if (changed & IEEE802154_AFILT_PANC_CHANGED) {
+ dev_vdbg(dev,
+ "atusb_set_hw_addr_filt called for panc change\n");
+ if (filt->pan_coord)
+ atusb_write_subreg(atusb, SR_AACK_I_AM_COORD, 1);
+ else
+ atusb_write_subreg(atusb, SR_AACK_I_AM_COORD, 0);
+ }
+
+ return atusb_get_and_clear_error(atusb);
+}
+
+static int atusb_start(struct ieee802154_hw *hw)
+{
+ struct atusb *atusb = hw->priv;
+ struct usb_device *usb_dev = atusb->usb_dev;
+ int ret;
+
+ dev_dbg(&usb_dev->dev, "atusb_start\n");
+ schedule_delayed_work(&atusb->work, 0);
+ atusb_command(atusb, ATUSB_RX_MODE, 1);
+ ret = atusb_get_and_clear_error(atusb);
+ if (ret < 0)
+ usb_kill_anchored_urbs(&atusb->idle_urbs);
+ return ret;
+}
+
+static void atusb_stop(struct ieee802154_hw *hw)
+{
+ struct atusb *atusb = hw->priv;
+ struct usb_device *usb_dev = atusb->usb_dev;
+
+ dev_dbg(&usb_dev->dev, "atusb_stop\n");
+ usb_kill_anchored_urbs(&atusb->idle_urbs);
+ atusb_command(atusb, ATUSB_RX_MODE, 0);
+ atusb_get_and_clear_error(atusb);
+}
+
+#define ATUSB_MAX_TX_POWERS 0xF
+static const s32 atusb_powers[ATUSB_MAX_TX_POWERS + 1] = {
+ 300, 280, 230, 180, 130, 70, 0, -100, -200, -300, -400, -500, -700,
+ -900, -1200, -1700,
+};
+
+static int
+atusb_set_txpower(struct ieee802154_hw *hw, s32 mbm)
+{
+ struct atusb *atusb = hw->priv;
+ u32 i;
+
+ for (i = 0; i < hw->phy->supported.tx_powers_size; i++) {
+ if (hw->phy->supported.tx_powers[i] == mbm)
+ return atusb_write_subreg(atusb, SR_TX_PWR_23X, i);
+ }
+
+ return -EINVAL;
+}
+
+static int
+atusb_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
+{
+ struct atusb *atusb = hw->priv;
+ int ret;
+
+ if (on) {
+ ret = atusb_write_subreg(atusb, SR_AACK_DIS_ACK, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = atusb_write_subreg(atusb, SR_AACK_PROM_MODE, 1);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = atusb_write_subreg(atusb, SR_AACK_PROM_MODE, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = atusb_write_subreg(atusb, SR_AACK_DIS_ACK, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct ieee802154_ops atusb_ops = {
+ .owner = THIS_MODULE,
+ .xmit_async = atusb_xmit,
+ .ed = atusb_ed,
+ .set_channel = atusb_channel,
+ .start = atusb_start,
+ .stop = atusb_stop,
+ .set_hw_addr_filt = atusb_set_hw_addr_filt,
+ .set_txpower = atusb_set_txpower,
+ .set_promiscuous_mode = atusb_set_promiscuous_mode,
+};
+
+/* ----- Firmware and chip version information ----------------------------- */
+
+static int atusb_get_and_show_revision(struct atusb *atusb)
+{
+ struct usb_device *usb_dev = atusb->usb_dev;
+ unsigned char buffer[3];
+ int ret;
+
+ /* Get a couple of the ATMega Firmware values */
+ ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
+ ATUSB_ID, ATUSB_REQ_FROM_DEV, 0, 0,
+ buffer, 3, 1000);
+ if (ret >= 0)
+ dev_info(&usb_dev->dev,
+ "Firmware: major: %u, minor: %u, hardware type: %u\n",
+ buffer[0], buffer[1], buffer[2]);
+ if (buffer[0] == 0 && buffer[1] < 2) {
+ dev_info(&usb_dev->dev,
+ "Firmware version (%u.%u) is predates our first public release.",
+ buffer[0], buffer[1]);
+ dev_info(&usb_dev->dev, "Please update to version 0.2 or newer");
+ }
+
+ return ret;
+}
+
+static int atusb_get_and_show_build(struct atusb *atusb)
+{
+ struct usb_device *usb_dev = atusb->usb_dev;
+ char build[ATUSB_BUILD_SIZE + 1];
+ int ret;
+
+ ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
+ ATUSB_BUILD, ATUSB_REQ_FROM_DEV, 0, 0,
+ build, ATUSB_BUILD_SIZE, 1000);
+ if (ret >= 0) {
+ build[ret] = 0;
+ dev_info(&usb_dev->dev, "Firmware: build %s\n", build);
+ }
+
+ return ret;
+}
+
+static int atusb_get_and_show_chip(struct atusb *atusb)
+{
+ struct usb_device *usb_dev = atusb->usb_dev;
+ uint8_t man_id_0, man_id_1, part_num, version_num;
+
+ man_id_0 = atusb_read_reg(atusb, RG_MAN_ID_0);
+ man_id_1 = atusb_read_reg(atusb, RG_MAN_ID_1);
+ part_num = atusb_read_reg(atusb, RG_PART_NUM);
+ version_num = atusb_read_reg(atusb, RG_VERSION_NUM);
+
+ if (atusb->err)
+ return atusb->err;
+
+ if ((man_id_1 << 8 | man_id_0) != ATUSB_JEDEC_ATMEL) {
+ dev_err(&usb_dev->dev,
+ "non-Atmel transceiver xxxx%02x%02x\n",
+ man_id_1, man_id_0);
+ goto fail;
+ }
+ if (part_num != 3 && part_num != 2) {
+ dev_err(&usb_dev->dev,
+ "unexpected transceiver, part 0x%02x version 0x%02x\n",
+ part_num, version_num);
+ goto fail;
+ }
+
+ dev_info(&usb_dev->dev, "ATUSB: AT86RF231 version %d\n", version_num);
+
+ return 0;
+
+fail:
+ atusb->err = -ENODEV;
+ return -ENODEV;
+}
+
+/* ----- Setup ------------------------------------------------------------- */
+
+static int atusb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *usb_dev = interface_to_usbdev(interface);
+ struct ieee802154_hw *hw;
+ struct atusb *atusb = NULL;
+ int ret = -ENOMEM;
+
+ hw = ieee802154_alloc_hw(sizeof(struct atusb), &atusb_ops);
+ if (!hw)
+ return -ENOMEM;
+
+ atusb = hw->priv;
+ atusb->hw = hw;
+ atusb->usb_dev = usb_get_dev(usb_dev);
+ usb_set_intfdata(interface, atusb);
+
+ atusb->shutdown = 0;
+ atusb->err = 0;
+ INIT_DELAYED_WORK(&atusb->work, atusb_work_urbs);
+ init_usb_anchor(&atusb->idle_urbs);
+ init_usb_anchor(&atusb->rx_urbs);
+
+ if (atusb_alloc_urbs(atusb, ATUSB_NUM_RX_URBS))
+ goto fail;
+
+ atusb->tx_dr.bRequestType = ATUSB_REQ_TO_DEV;
+ atusb->tx_dr.bRequest = ATUSB_TX;
+ atusb->tx_dr.wValue = cpu_to_le16(0);
+
+ atusb->tx_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!atusb->tx_urb)
+ goto fail;
+
+ hw->parent = &usb_dev->dev;
+ hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT |
+ IEEE802154_HW_PROMISCUOUS;
+
+ hw->phy->flags = WPAN_PHY_FLAG_TXPOWER;
+
+ hw->phy->current_page = 0;
+ hw->phy->current_channel = 11; /* reset default */
+ hw->phy->supported.channels[0] = 0x7FFF800;
+ hw->phy->supported.tx_powers = atusb_powers;
+ hw->phy->supported.tx_powers_size = ARRAY_SIZE(atusb_powers);
+ hw->phy->transmit_power = hw->phy->supported.tx_powers[0];
+ ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
+
+ atusb_command(atusb, ATUSB_RF_RESET, 0);
+ atusb_get_and_show_chip(atusb);
+ atusb_get_and_show_revision(atusb);
+ atusb_get_and_show_build(atusb);
+ ret = atusb_get_and_clear_error(atusb);
+ if (ret) {
+ dev_err(&atusb->usb_dev->dev,
+ "%s: initialization failed, error = %d\n",
+ __func__, ret);
+ goto fail;
+ }
+
+ ret = ieee802154_register_hw(hw);
+ if (ret)
+ goto fail;
+
+ /* If we just powered on, we're now in P_ON and need to enter TRX_OFF
+ * explicitly. Any resets after that will send us straight to TRX_OFF,
+ * making the command below redundant.
+ */
+ atusb_write_reg(atusb, RG_TRX_STATE, STATE_FORCE_TRX_OFF);
+ msleep(1); /* reset => TRX_OFF, tTR13 = 37 us */
+
+#if 0
+ /* Calculating the maximum time available to empty the frame buffer
+ * on reception:
+ *
+ * According to [1], the inter-frame gap is
+ * R * 20 * 16 us + 128 us
+ * where R is a random number from 0 to 7. Furthermore, we have 20 bit
+ * times (80 us at 250 kbps) of SHR of the next frame before the
+ * transceiver begins storing data in the frame buffer.
+ *
+ * This yields a minimum time of 208 us between the last data of a
+ * frame and the first data of the next frame. This time is further
+ * reduced by interrupt latency in the atusb firmware.
+ *
+ * atusb currently needs about 500 us to retrieve a maximum-sized
+ * frame. We therefore have to allow reception of a new frame to begin
+ * while we retrieve the previous frame.
+ *
+ * [1] "JN-AN-1035 Calculating data rates in an IEEE 802.15.4-based
+ * network", Jennic 2006.
+ * http://www.jennic.com/download_file.php?supportFile=JN-AN-1035%20Calculating%20802-15-4%20Data%20Rates-1v0.pdf
+ */
+
+ atusb_write_subreg(atusb, SR_RX_SAFE_MODE, 1);
+#endif
+ atusb_write_reg(atusb, RG_IRQ_MASK, 0xff);
+
+ ret = atusb_get_and_clear_error(atusb);
+ if (!ret)
+ return 0;
+
+ dev_err(&atusb->usb_dev->dev,
+ "%s: setup failed, error = %d\n",
+ __func__, ret);
+
+ ieee802154_unregister_hw(hw);
+fail:
+ atusb_free_urbs(atusb);
+ usb_kill_urb(atusb->tx_urb);
+ usb_free_urb(atusb->tx_urb);
+ usb_put_dev(usb_dev);
+ ieee802154_free_hw(hw);
+ return ret;
+}
+
+static void atusb_disconnect(struct usb_interface *interface)
+{
+ struct atusb *atusb = usb_get_intfdata(interface);
+
+ dev_dbg(&atusb->usb_dev->dev, "atusb_disconnect\n");
+
+ atusb->shutdown = 1;
+ cancel_delayed_work_sync(&atusb->work);
+
+ usb_kill_anchored_urbs(&atusb->rx_urbs);
+ atusb_free_urbs(atusb);
+ usb_kill_urb(atusb->tx_urb);
+ usb_free_urb(atusb->tx_urb);
+
+ ieee802154_unregister_hw(atusb->hw);
+
+ ieee802154_free_hw(atusb->hw);
+
+ usb_set_intfdata(interface, NULL);
+ usb_put_dev(atusb->usb_dev);
+
+ pr_debug("atusb_disconnect done\n");
+}
+
+/* The devices we work with */
+static const struct usb_device_id atusb_device_table[] = {
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+ USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = ATUSB_VENDOR_ID,
+ .idProduct = ATUSB_PRODUCT_ID,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC
+ },
+ /* end with null element */
+ {}
+};
+MODULE_DEVICE_TABLE(usb, atusb_device_table);
+
+static struct usb_driver atusb_driver = {
+ .name = "atusb",
+ .probe = atusb_probe,
+ .disconnect = atusb_disconnect,
+ .id_table = atusb_device_table,
+};
+module_usb_driver(atusb_driver);
+
+MODULE_AUTHOR("Alexander Aring <alex.aring@gmail.com>");
+MODULE_AUTHOR("Richard Sharpe <realrichardsharpe@gmail.com>");
+MODULE_AUTHOR("Stefan Schmidt <stefan@datenfreihafen.org>");
+MODULE_AUTHOR("Werner Almesberger <werner@almesberger.net>");
+MODULE_DESCRIPTION("ATUSB IEEE 802.15.4 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ieee802154/atusb.h b/drivers/net/ieee802154/atusb.h
new file mode 100644
index 000000000000..0690edcad57b
--- /dev/null
+++ b/drivers/net/ieee802154/atusb.h
@@ -0,0 +1,84 @@
+/*
+ * atusb.h - Definitions shared between kernel and ATUSB firmware
+ *
+ * Written 2013 by Werner Almesberger <werner@almesberger.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2, or
+ * (at your option) any later version.
+ *
+ * This file should be identical for kernel and firmware.
+ * Kernel: drivers/net/ieee802154/atusb.h
+ * Firmware: ben-wpan/atusb/fw/include/atusb/atusb.h
+ */
+
+#ifndef _ATUSB_H
+#define _ATUSB_H
+
+#define ATUSB_VENDOR_ID 0x20b7 /* Qi Hardware*/
+#define ATUSB_PRODUCT_ID 0x1540 /* 802.15.4, device 0 */
+ /* -- - - */
+
+#define ATUSB_BUILD_SIZE 256 /* maximum build version/date message length */
+
+/* Commands to our device. Make sure this is synced with the firmware */
+enum atusb_requests {
+ ATUSB_ID = 0x00, /* system status/control grp */
+ ATUSB_BUILD,
+ ATUSB_RESET,
+ ATUSB_RF_RESET = 0x10, /* debug/test group */
+ ATUSB_POLL_INT,
+ ATUSB_TEST, /* atusb-sil only */
+ ATUSB_TIMER,
+ ATUSB_GPIO,
+ ATUSB_SLP_TR,
+ ATUSB_GPIO_CLEANUP,
+ ATUSB_REG_WRITE = 0x20, /* transceiver group */
+ ATUSB_REG_READ,
+ ATUSB_BUF_WRITE,
+ ATUSB_BUF_READ,
+ ATUSB_SRAM_WRITE,
+ ATUSB_SRAM_READ,
+ ATUSB_SPI_WRITE = 0x30, /* SPI group */
+ ATUSB_SPI_READ1,
+ ATUSB_SPI_READ2,
+ ATUSB_SPI_WRITE2_SYNC,
+ ATUSB_RX_MODE = 0x40, /* HardMAC group */
+ ATUSB_TX,
+};
+
+/* Direction bRequest wValue wIndex wLength
+ *
+ * ->host ATUSB_ID - - 3
+ * ->host ATUSB_BUILD - - #bytes
+ * host-> ATUSB_RESET - - 0
+ *
+ * host-> ATUSB_RF_RESET - - 0
+ * ->host ATUSB_POLL_INT - - 1
+ * host-> ATUSB_TEST - - 0
+ * ->host ATUSB_TIMER - - #bytes (6)
+ * ->host ATUSB_GPIO dir+data mask+p# 3
+ * host-> ATUSB_SLP_TR - - 0
+ * host-> ATUSB_GPIO_CLEANUP - - 0
+ *
+ * host-> ATUSB_REG_WRITE value addr 0
+ * ->host ATUSB_REG_READ - addr 1
+ * host-> ATUSB_BUF_WRITE - - #bytes
+ * ->host ATUSB_BUF_READ - - #bytes
+ * host-> ATUSB_SRAM_WRITE - addr #bytes
+ * ->host ATUSB_SRAM_READ - addr #bytes
+ *
+ * host-> ATUSB_SPI_WRITE byte0 byte1 #bytes
+ * ->host ATUSB_SPI_READ1 byte0 - #bytes
+ * ->host ATUSB_SPI_READ2 byte0 byte1 #bytes
+ * ->host ATUSB_SPI_WRITE2_SYNC byte0 byte1 0/1
+ *
+ * host-> ATUSB_RX_MODE on - 0
+ * host-> ATUSB_TX flags ack_seq #bytes
+ */
+
+#define ATUSB_REQ_FROM_DEV (USB_TYPE_VENDOR | USB_DIR_IN)
+#define ATUSB_REQ_TO_DEV (USB_TYPE_VENDOR | USB_DIR_OUT)
+
+#endif /* !_ATUSB_H */
diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c
index f833b8bb6663..b6fc29579667 100644
--- a/drivers/net/ieee802154/cc2520.c
+++ b/drivers/net/ieee802154/cc2520.c
@@ -196,6 +196,7 @@ struct cc2520_private {
u8 *buf; /* SPI TX/Rx data buffer */
struct mutex buffer_mutex; /* SPI buffer mutex */
bool is_tx; /* Flag for sync b/w Tx and Rx */
+ bool amplified; /* Flag for CC2591 */
int fifo_pin; /* FIFO GPIO pin number */
struct work_struct fifop_irqwork;/* Workqueue for FIFOP */
spinlock_t lock; /* Lock for is_tx*/
@@ -589,22 +590,23 @@ cc2520_filter(struct ieee802154_hw *hw,
struct ieee802154_hw_addr_filt *filt, unsigned long changed)
{
struct cc2520_private *priv = hw->priv;
+ int ret = 0;
if (changed & IEEE802154_AFILT_PANID_CHANGED) {
u16 panid = le16_to_cpu(filt->pan_id);
dev_vdbg(&priv->spi->dev,
"cc2520_filter called for pan id\n");
- cc2520_write_ram(priv, CC2520RAM_PANID,
- sizeof(panid), (u8 *)&panid);
+ ret = cc2520_write_ram(priv, CC2520RAM_PANID,
+ sizeof(panid), (u8 *)&panid);
}
if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
dev_vdbg(&priv->spi->dev,
"cc2520_filter called for IEEE addr\n");
- cc2520_write_ram(priv, CC2520RAM_IEEEADDR,
- sizeof(filt->ieee_addr),
- (u8 *)&filt->ieee_addr);
+ ret = cc2520_write_ram(priv, CC2520RAM_IEEEADDR,
+ sizeof(filt->ieee_addr),
+ (u8 *)&filt->ieee_addr);
}
if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
@@ -612,20 +614,113 @@ cc2520_filter(struct ieee802154_hw *hw,
dev_vdbg(&priv->spi->dev,
"cc2520_filter called for saddr\n");
- cc2520_write_ram(priv, CC2520RAM_SHORTADDR,
- sizeof(addr), (u8 *)&addr);
+ ret = cc2520_write_ram(priv, CC2520RAM_SHORTADDR,
+ sizeof(addr), (u8 *)&addr);
}
if (changed & IEEE802154_AFILT_PANC_CHANGED) {
dev_vdbg(&priv->spi->dev,
"cc2520_filter called for panc change\n");
if (filt->pan_coord)
- cc2520_write_register(priv, CC2520_FRMFILT0, 0x02);
+ ret = cc2520_write_register(priv, CC2520_FRMFILT0,
+ 0x02);
else
- cc2520_write_register(priv, CC2520_FRMFILT0, 0x00);
+ ret = cc2520_write_register(priv, CC2520_FRMFILT0,
+ 0x00);
}
- return 0;
+ return ret;
+}
+
+static inline int cc2520_set_tx_power(struct cc2520_private *priv, s32 mbm)
+{
+ u8 power;
+
+ switch (mbm) {
+ case 500:
+ power = 0xF7;
+ break;
+ case 300:
+ power = 0xF2;
+ break;
+ case 200:
+ power = 0xAB;
+ break;
+ case 100:
+ power = 0x13;
+ break;
+ case 0:
+ power = 0x32;
+ break;
+ case -200:
+ power = 0x81;
+ break;
+ case -400:
+ power = 0x88;
+ break;
+ case -700:
+ power = 0x2C;
+ break;
+ case -1800:
+ power = 0x03;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return cc2520_write_register(priv, CC2520_TXPOWER, power);
+}
+
+static inline int cc2520_cc2591_set_tx_power(struct cc2520_private *priv,
+ s32 mbm)
+{
+ u8 power;
+
+ switch (mbm) {
+ case 1700:
+ power = 0xF9;
+ break;
+ case 1600:
+ power = 0xF0;
+ break;
+ case 1400:
+ power = 0xA0;
+ break;
+ case 1100:
+ power = 0x2C;
+ break;
+ case -100:
+ power = 0x03;
+ break;
+ case -800:
+ power = 0x01;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return cc2520_write_register(priv, CC2520_TXPOWER, power);
+}
+
+#define CC2520_MAX_TX_POWERS 0x8
+static const s32 cc2520_powers[CC2520_MAX_TX_POWERS + 1] = {
+ 500, 300, 200, 100, 0, -200, -400, -700, -1800,
+};
+
+#define CC2520_CC2591_MAX_TX_POWERS 0x5
+static const s32 cc2520_cc2591_powers[CC2520_CC2591_MAX_TX_POWERS + 1] = {
+ 1700, 1600, 1400, 1100, -100, -800,
+};
+
+static int
+cc2520_set_txpower(struct ieee802154_hw *hw, s32 mbm)
+{
+ struct cc2520_private *priv = hw->priv;
+
+ if (!priv->amplified)
+ return cc2520_set_tx_power(priv, mbm);
+
+ return cc2520_cc2591_set_tx_power(priv, mbm);
}
static const struct ieee802154_ops cc2520_ops = {
@@ -636,6 +731,7 @@ static const struct ieee802154_ops cc2520_ops = {
.ed = cc2520_ed,
.set_channel = cc2520_set_channel,
.set_hw_addr_filt = cc2520_filter,
+ .set_txpower = cc2520_set_txpower,
};
static int cc2520_register(struct cc2520_private *priv)
@@ -649,13 +745,25 @@ static int cc2520_register(struct cc2520_private *priv)
priv->hw->priv = priv;
priv->hw->parent = &priv->spi->dev;
priv->hw->extra_tx_headroom = 0;
- priv->hw->vif_data_size = sizeof(*priv);
ieee802154_random_extended_addr(&priv->hw->phy->perm_extended_addr);
/* We do support only 2.4 Ghz */
- priv->hw->phy->channels_supported[0] = 0x7FFF800;
- priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK |
- IEEE802154_HW_AFILT;
+ priv->hw->phy->supported.channels[0] = 0x7FFF800;
+ priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AFILT;
+
+ priv->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER;
+
+ if (!priv->amplified) {
+ priv->hw->phy->supported.tx_powers = cc2520_powers;
+ priv->hw->phy->supported.tx_powers_size = ARRAY_SIZE(cc2520_powers);
+ priv->hw->phy->transmit_power = priv->hw->phy->supported.tx_powers[4];
+ } else {
+ priv->hw->phy->supported.tx_powers = cc2520_cc2591_powers;
+ priv->hw->phy->supported.tx_powers_size = ARRAY_SIZE(cc2520_cc2591_powers);
+ priv->hw->phy->transmit_power = priv->hw->phy->supported.tx_powers[0];
+ }
+
+ priv->hw->phy->current_channel = 11;
dev_vdbg(&priv->spi->dev, "registered cc2520\n");
ret = ieee802154_register_hw(priv->hw);
@@ -738,7 +846,9 @@ static int cc2520_get_platform_data(struct spi_device *spi,
pdata->vreg = of_get_named_gpio(np, "vreg-gpio", 0);
pdata->reset = of_get_named_gpio(np, "reset-gpio", 0);
- pdata->amplified = of_property_read_bool(np, "amplified");
+ /* CC2591 front end for CC2520 */
+ if (of_property_read_bool(np, "amplified"))
+ priv->amplified = true;
return 0;
}
@@ -781,11 +891,7 @@ static int cc2520_hw_init(struct cc2520_private *priv)
* amplifier. See section 8 page 17 of TI application note AN065.
* http://www.ti.com/lit/an/swra229a/swra229a.pdf
*/
- if (pdata.amplified) {
- ret = cc2520_write_register(priv, CC2520_TXPOWER, 0xF9);
- if (ret)
- goto err_ret;
-
+ if (priv->amplified) {
ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x16);
if (ret)
goto err_ret;
@@ -806,10 +912,6 @@ static int cc2520_hw_init(struct cc2520_private *priv)
if (ret)
goto err_ret;
} else {
- ret = cc2520_write_register(priv, CC2520_TXPOWER, 0xF7);
- if (ret)
- goto err_ret;
-
ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x11);
if (ret)
goto err_ret;
@@ -904,6 +1006,9 @@ static int cc2520_probe(struct spi_device *spi)
spin_lock_init(&priv->lock);
init_completion(&priv->tx_complete);
+ /* Assumption that CC2591 is not connected */
+ priv->amplified = false;
+
/* Request all the gpio's */
if (!gpio_is_valid(pdata.fifo)) {
dev_err(&spi->dev, "fifo gpio is not valid\n");
diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c
index dc2bfb600b4b..860d4aed8274 100644
--- a/drivers/net/ieee802154/fakelb.c
+++ b/drivers/net/ieee802154/fakelb.c
@@ -27,25 +27,27 @@
#include <net/mac802154.h>
#include <net/cfg802154.h>
-static int numlbs = 1;
+static int numlbs = 2;
-struct fakelb_dev_priv {
+static LIST_HEAD(fakelb_phys);
+static DEFINE_SPINLOCK(fakelb_phys_lock);
+
+static LIST_HEAD(fakelb_ifup_phys);
+static DEFINE_RWLOCK(fakelb_ifup_phys_lock);
+
+struct fakelb_phy {
struct ieee802154_hw *hw;
- struct list_head list;
- struct fakelb_priv *fake;
+ u8 page;
+ u8 channel;
- spinlock_t lock;
- bool working;
-};
+ bool suspended;
-struct fakelb_priv {
struct list_head list;
- rwlock_t lock;
+ struct list_head list_ifup;
};
-static int
-fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level)
+static int fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level)
{
BUG_ON(!level);
*level = 0xbe;
@@ -53,78 +55,66 @@ fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level)
return 0;
}
-static int
-fakelb_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
+static int fakelb_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
{
- pr_debug("set channel to %d\n", channel);
+ struct fakelb_phy *phy = hw->priv;
+ write_lock_bh(&fakelb_ifup_phys_lock);
+ phy->page = page;
+ phy->channel = channel;
+ write_unlock_bh(&fakelb_ifup_phys_lock);
return 0;
}
-static void
-fakelb_hw_deliver(struct fakelb_dev_priv *priv, struct sk_buff *skb)
+static int fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
{
- struct sk_buff *newskb;
+ struct fakelb_phy *current_phy = hw->priv, *phy;
- spin_lock(&priv->lock);
- if (priv->working) {
- newskb = pskb_copy(skb, GFP_ATOMIC);
- ieee802154_rx_irqsafe(priv->hw, newskb, 0xcc);
- }
- spin_unlock(&priv->lock);
-}
+ read_lock_bh(&fakelb_ifup_phys_lock);
+ WARN_ON(current_phy->suspended);
+ list_for_each_entry(phy, &fakelb_ifup_phys, list_ifup) {
+ if (current_phy == phy)
+ continue;
-static int
-fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
-{
- struct fakelb_dev_priv *priv = hw->priv;
- struct fakelb_priv *fake = priv->fake;
-
- read_lock_bh(&fake->lock);
- if (priv->list.next == priv->list.prev) {
- /* we are the only one device */
- fakelb_hw_deliver(priv, skb);
- } else {
- struct fakelb_dev_priv *dp;
- list_for_each_entry(dp, &priv->fake->list, list) {
- if (dp != priv &&
- (dp->hw->phy->current_channel ==
- priv->hw->phy->current_channel))
- fakelb_hw_deliver(dp, skb);
+ if (current_phy->page == phy->page &&
+ current_phy->channel == phy->channel) {
+ struct sk_buff *newskb = pskb_copy(skb, GFP_ATOMIC);
+
+ if (newskb)
+ ieee802154_rx_irqsafe(phy->hw, newskb, 0xcc);
}
}
- read_unlock_bh(&fake->lock);
+ read_unlock_bh(&fakelb_ifup_phys_lock);
+ ieee802154_xmit_complete(hw, skb, false);
return 0;
}
-static int
-fakelb_hw_start(struct ieee802154_hw *hw) {
- struct fakelb_dev_priv *priv = hw->priv;
- int ret = 0;
+static int fakelb_hw_start(struct ieee802154_hw *hw)
+{
+ struct fakelb_phy *phy = hw->priv;
- spin_lock(&priv->lock);
- if (priv->working)
- ret = -EBUSY;
- else
- priv->working = 1;
- spin_unlock(&priv->lock);
+ write_lock_bh(&fakelb_ifup_phys_lock);
+ phy->suspended = false;
+ list_add(&phy->list_ifup, &fakelb_ifup_phys);
+ write_unlock_bh(&fakelb_ifup_phys_lock);
- return ret;
+ return 0;
}
-static void
-fakelb_hw_stop(struct ieee802154_hw *hw) {
- struct fakelb_dev_priv *priv = hw->priv;
+static void fakelb_hw_stop(struct ieee802154_hw *hw)
+{
+ struct fakelb_phy *phy = hw->priv;
- spin_lock(&priv->lock);
- priv->working = 0;
- spin_unlock(&priv->lock);
+ write_lock_bh(&fakelb_ifup_phys_lock);
+ phy->suspended = true;
+ list_del(&phy->list_ifup);
+ write_unlock_bh(&fakelb_ifup_phys_lock);
}
static const struct ieee802154_ops fakelb_ops = {
.owner = THIS_MODULE,
- .xmit_sync = fakelb_hw_xmit,
+ .xmit_async = fakelb_hw_xmit,
.ed = fakelb_hw_ed,
.set_channel = fakelb_hw_channel,
.start = fakelb_hw_start,
@@ -135,54 +125,54 @@ static const struct ieee802154_ops fakelb_ops = {
module_param(numlbs, int, 0);
MODULE_PARM_DESC(numlbs, " number of pseudo devices");
-static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake)
+static int fakelb_add_one(struct device *dev)
{
- struct fakelb_dev_priv *priv;
- int err;
struct ieee802154_hw *hw;
+ struct fakelb_phy *phy;
+ int err;
- hw = ieee802154_alloc_hw(sizeof(*priv), &fakelb_ops);
+ hw = ieee802154_alloc_hw(sizeof(*phy), &fakelb_ops);
if (!hw)
return -ENOMEM;
- priv = hw->priv;
- priv->hw = hw;
+ phy = hw->priv;
+ phy->hw = hw;
/* 868 MHz BPSK 802.15.4-2003 */
- hw->phy->channels_supported[0] |= 1;
+ hw->phy->supported.channels[0] |= 1;
/* 915 MHz BPSK 802.15.4-2003 */
- hw->phy->channels_supported[0] |= 0x7fe;
+ hw->phy->supported.channels[0] |= 0x7fe;
/* 2.4 GHz O-QPSK 802.15.4-2003 */
- hw->phy->channels_supported[0] |= 0x7FFF800;
+ hw->phy->supported.channels[0] |= 0x7FFF800;
/* 868 MHz ASK 802.15.4-2006 */
- hw->phy->channels_supported[1] |= 1;
+ hw->phy->supported.channels[1] |= 1;
/* 915 MHz ASK 802.15.4-2006 */
- hw->phy->channels_supported[1] |= 0x7fe;
+ hw->phy->supported.channels[1] |= 0x7fe;
/* 868 MHz O-QPSK 802.15.4-2006 */
- hw->phy->channels_supported[2] |= 1;
+ hw->phy->supported.channels[2] |= 1;
/* 915 MHz O-QPSK 802.15.4-2006 */
- hw->phy->channels_supported[2] |= 0x7fe;
+ hw->phy->supported.channels[2] |= 0x7fe;
/* 2.4 GHz CSS 802.15.4a-2007 */
- hw->phy->channels_supported[3] |= 0x3fff;
+ hw->phy->supported.channels[3] |= 0x3fff;
/* UWB Sub-gigahertz 802.15.4a-2007 */
- hw->phy->channels_supported[4] |= 1;
+ hw->phy->supported.channels[4] |= 1;
/* UWB Low band 802.15.4a-2007 */
- hw->phy->channels_supported[4] |= 0x1e;
+ hw->phy->supported.channels[4] |= 0x1e;
/* UWB High band 802.15.4a-2007 */
- hw->phy->channels_supported[4] |= 0xffe0;
+ hw->phy->supported.channels[4] |= 0xffe0;
/* 750 MHz O-QPSK 802.15.4c-2009 */
- hw->phy->channels_supported[5] |= 0xf;
+ hw->phy->supported.channels[5] |= 0xf;
/* 750 MHz MPSK 802.15.4c-2009 */
- hw->phy->channels_supported[5] |= 0xf0;
+ hw->phy->supported.channels[5] |= 0xf0;
/* 950 MHz BPSK 802.15.4d-2009 */
- hw->phy->channels_supported[6] |= 0x3ff;
+ hw->phy->supported.channels[6] |= 0x3ff;
/* 950 MHz GFSK 802.15.4d-2009 */
- hw->phy->channels_supported[6] |= 0x3ffc00;
+ hw->phy->supported.channels[6] |= 0x3ffc00;
- INIT_LIST_HEAD(&priv->list);
- priv->fake = fake;
-
- spin_lock_init(&priv->lock);
+ ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
+ /* fake phy channel 13 as default */
+ hw->phy->current_channel = 13;
+ phy->channel = hw->phy->current_channel;
hw->parent = dev;
@@ -190,67 +180,55 @@ static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake)
if (err)
goto err_reg;
- write_lock_bh(&fake->lock);
- list_add_tail(&priv->list, &fake->list);
- write_unlock_bh(&fake->lock);
+ spin_lock(&fakelb_phys_lock);
+ list_add_tail(&phy->list, &fakelb_phys);
+ spin_unlock(&fakelb_phys_lock);
return 0;
err_reg:
- ieee802154_free_hw(priv->hw);
+ ieee802154_free_hw(phy->hw);
return err;
}
-static void fakelb_del(struct fakelb_dev_priv *priv)
+static void fakelb_del(struct fakelb_phy *phy)
{
- write_lock_bh(&priv->fake->lock);
- list_del(&priv->list);
- write_unlock_bh(&priv->fake->lock);
+ list_del(&phy->list);
- ieee802154_unregister_hw(priv->hw);
- ieee802154_free_hw(priv->hw);
+ ieee802154_unregister_hw(phy->hw);
+ ieee802154_free_hw(phy->hw);
}
static int fakelb_probe(struct platform_device *pdev)
{
- struct fakelb_priv *priv;
- struct fakelb_dev_priv *dp;
- int err = -ENOMEM;
- int i;
-
- priv = devm_kzalloc(&pdev->dev, sizeof(struct fakelb_priv),
- GFP_KERNEL);
- if (!priv)
- goto err_alloc;
-
- INIT_LIST_HEAD(&priv->list);
- rwlock_init(&priv->lock);
+ struct fakelb_phy *phy, *tmp;
+ int err, i;
for (i = 0; i < numlbs; i++) {
- err = fakelb_add_one(&pdev->dev, priv);
+ err = fakelb_add_one(&pdev->dev);
if (err < 0)
goto err_slave;
}
- platform_set_drvdata(pdev, priv);
dev_info(&pdev->dev, "added ieee802154 hardware\n");
return 0;
err_slave:
- list_for_each_entry(dp, &priv->list, list)
- fakelb_del(dp);
-err_alloc:
+ spin_lock(&fakelb_phys_lock);
+ list_for_each_entry_safe(phy, tmp, &fakelb_phys, list)
+ fakelb_del(phy);
+ spin_unlock(&fakelb_phys_lock);
return err;
}
static int fakelb_remove(struct platform_device *pdev)
{
- struct fakelb_priv *priv = platform_get_drvdata(pdev);
- struct fakelb_dev_priv *dp, *temp;
-
- list_for_each_entry_safe(dp, temp, &priv->list, list)
- fakelb_del(dp);
+ struct fakelb_phy *phy, *tmp;
+ spin_lock(&fakelb_phys_lock);
+ list_for_each_entry_safe(phy, tmp, &fakelb_phys, list)
+ fakelb_del(phy);
+ spin_unlock(&fakelb_phys_lock);
return 0;
}
diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c
index fba2dfd910f7..2549760e039f 100644
--- a/drivers/net/ieee802154/mrf24j40.c
+++ b/drivers/net/ieee802154/mrf24j40.c
@@ -533,6 +533,7 @@ static int mrf24j40_handle_rx(struct mrf24j40 *devrec)
u8 lqi = 0;
u8 val;
int ret = 0;
+ int ret2;
struct sk_buff *skb;
/* Turn off reception of packets off the air. This prevents the
@@ -569,9 +570,9 @@ static int mrf24j40_handle_rx(struct mrf24j40 *devrec)
out:
/* Turn back on reception of packets off the air. */
- ret = read_short_reg(devrec, REG_BBREG1, &val);
- if (ret)
- return ret;
+ ret2 = read_short_reg(devrec, REG_BBREG1, &val);
+ if (ret2)
+ return ret2;
val &= ~0x4; /* Clear RXDECINV */
write_short_reg(devrec, REG_BBREG1, val);
@@ -750,9 +751,8 @@ static int mrf24j40_probe(struct spi_device *spi)
devrec->hw->priv = devrec;
devrec->hw->parent = &devrec->spi->dev;
- devrec->hw->phy->channels_supported[0] = CHANNEL_MASK;
- devrec->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK |
- IEEE802154_HW_AFILT;
+ devrec->hw->phy->supported.channels[0] = CHANNEL_MASK;
+ devrec->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AFILT;
dev_dbg(printdev(devrec), "registered mrf24j40\n");
ret = ieee802154_register_hw(devrec->hw);
diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h
index 54549a6223dd..953a97492fab 100644
--- a/drivers/net/ipvlan/ipvlan.h
+++ b/drivers/net/ipvlan/ipvlan.h
@@ -39,6 +39,8 @@
#define IPVLAN_MAC_FILTER_SIZE (1 << IPVLAN_MAC_FILTER_BITS)
#define IPVLAN_MAC_FILTER_MASK (IPVLAN_MAC_FILTER_SIZE - 1)
+#define IPVLAN_QBACKLOG_LIMIT 1000
+
typedef enum {
IPVL_IPV6 = 0,
IPVL_ICMPV6,
@@ -93,6 +95,8 @@ struct ipvl_port {
struct hlist_head hlhead[IPVLAN_HASH_SIZE];
struct list_head ipvlans;
struct rcu_head rcu;
+ struct work_struct wq;
+ struct sk_buff_head backlog;
int count;
u16 mode;
};
@@ -112,6 +116,7 @@ void ipvlan_set_port_mode(struct ipvl_port *port, u32 nval);
void ipvlan_init_secret(void);
unsigned int ipvlan_mac_hash(const unsigned char *addr);
rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb);
+void ipvlan_process_multicast(struct work_struct *work);
int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev);
void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr);
struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c
index c30b5c300c05..8afbedad620d 100644
--- a/drivers/net/ipvlan/ipvlan_core.c
+++ b/drivers/net/ipvlan/ipvlan_core.c
@@ -189,62 +189,69 @@ unsigned int ipvlan_mac_hash(const unsigned char *addr)
return hash & IPVLAN_MAC_FILTER_MASK;
}
-static void ipvlan_multicast_frame(struct ipvl_port *port, struct sk_buff *skb,
- const struct ipvl_dev *in_dev, bool local)
+void ipvlan_process_multicast(struct work_struct *work)
{
- struct ethhdr *eth = eth_hdr(skb);
+ struct ipvl_port *port = container_of(work, struct ipvl_port, wq);
+ struct ethhdr *ethh;
struct ipvl_dev *ipvlan;
- struct sk_buff *nskb;
+ struct sk_buff *skb, *nskb;
+ struct sk_buff_head list;
unsigned int len;
unsigned int mac_hash;
int ret;
+ u8 pkt_type;
+ bool hlocal, dlocal;
- if (skb->protocol == htons(ETH_P_PAUSE))
- return;
-
- rcu_read_lock();
- list_for_each_entry_rcu(ipvlan, &port->ipvlans, pnode) {
- if (local && (ipvlan == in_dev))
- continue;
+ __skb_queue_head_init(&list);
- mac_hash = ipvlan_mac_hash(eth->h_dest);
- if (!test_bit(mac_hash, ipvlan->mac_filters))
- continue;
+ spin_lock_bh(&port->backlog.lock);
+ skb_queue_splice_tail_init(&port->backlog, &list);
+ spin_unlock_bh(&port->backlog.lock);
- ret = NET_RX_DROP;
- len = skb->len + ETH_HLEN;
- nskb = skb_clone(skb, GFP_ATOMIC);
- if (!nskb)
- goto mcast_acct;
+ while ((skb = __skb_dequeue(&list)) != NULL) {
+ ethh = eth_hdr(skb);
+ hlocal = ether_addr_equal(ethh->h_source, port->dev->dev_addr);
+ mac_hash = ipvlan_mac_hash(ethh->h_dest);
- if (ether_addr_equal(eth->h_dest, ipvlan->phy_dev->broadcast))
- nskb->pkt_type = PACKET_BROADCAST;
+ if (ether_addr_equal(ethh->h_dest, port->dev->broadcast))
+ pkt_type = PACKET_BROADCAST;
else
- nskb->pkt_type = PACKET_MULTICAST;
-
- nskb->dev = ipvlan->dev;
- if (local)
- ret = dev_forward_skb(ipvlan->dev, nskb);
- else
- ret = netif_rx(nskb);
-mcast_acct:
- ipvlan_count_rx(ipvlan, len, ret == NET_RX_SUCCESS, true);
- }
- rcu_read_unlock();
-
- /* Locally generated? ...Forward a copy to the main-device as
- * well. On the RX side we'll ignore it (wont give it to any
- * of the virtual devices.
- */
- if (local) {
- nskb = skb_clone(skb, GFP_ATOMIC);
- if (nskb) {
- if (ether_addr_equal(eth->h_dest, port->dev->broadcast))
- nskb->pkt_type = PACKET_BROADCAST;
+ pkt_type = PACKET_MULTICAST;
+
+ dlocal = false;
+ rcu_read_lock();
+ list_for_each_entry_rcu(ipvlan, &port->ipvlans, pnode) {
+ if (hlocal && (ipvlan->dev == skb->dev)) {
+ dlocal = true;
+ continue;
+ }
+ if (!test_bit(mac_hash, ipvlan->mac_filters))
+ continue;
+
+ ret = NET_RX_DROP;
+ len = skb->len + ETH_HLEN;
+ nskb = skb_clone(skb, GFP_ATOMIC);
+ if (!nskb)
+ goto acct;
+
+ nskb->pkt_type = pkt_type;
+ nskb->dev = ipvlan->dev;
+ if (hlocal)
+ ret = dev_forward_skb(ipvlan->dev, nskb);
else
- nskb->pkt_type = PACKET_MULTICAST;
-
- dev_forward_skb(port->dev, nskb);
+ ret = netif_rx(nskb);
+acct:
+ ipvlan_count_rx(ipvlan, len, ret == NET_RX_SUCCESS, true);
+ }
+ rcu_read_unlock();
+
+ if (dlocal) {
+ /* If the packet originated here, send it out. */
+ skb->dev = port->dev;
+ skb->pkt_type = pkt_type;
+ dev_queue_xmit(skb);
+ } else {
+ kfree_skb(skb);
}
}
}
@@ -446,6 +453,26 @@ out:
return ret;
}
+static void ipvlan_multicast_enqueue(struct ipvl_port *port,
+ struct sk_buff *skb)
+{
+ if (skb->protocol == htons(ETH_P_PAUSE)) {
+ kfree_skb(skb);
+ return;
+ }
+
+ spin_lock(&port->backlog.lock);
+ if (skb_queue_len(&port->backlog) < IPVLAN_QBACKLOG_LIMIT) {
+ __skb_queue_tail(&port->backlog, skb);
+ spin_unlock(&port->backlog.lock);
+ schedule_work(&port->wq);
+ } else {
+ spin_unlock(&port->backlog.lock);
+ atomic_long_inc(&skb->dev->rx_dropped);
+ kfree_skb(skb);
+ }
+}
+
static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev)
{
const struct ipvl_dev *ipvlan = netdev_priv(dev);
@@ -493,11 +520,8 @@ static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev)
return dev_forward_skb(ipvlan->phy_dev, skb);
} else if (is_multicast_ether_addr(eth->h_dest)) {
- u8 ip_summed = skb->ip_summed;
-
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- ipvlan_multicast_frame(ipvlan->port, skb, ipvlan, true);
- skb->ip_summed = ip_summed;
+ ipvlan_multicast_enqueue(ipvlan->port, skb);
+ return NET_XMIT_SUCCESS;
}
skb->dev = ipvlan->phy_dev;
@@ -581,8 +605,18 @@ static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb,
int addr_type;
if (is_multicast_ether_addr(eth->h_dest)) {
- if (ipvlan_external_frame(skb, port))
- ipvlan_multicast_frame(port, skb, NULL, false);
+ if (ipvlan_external_frame(skb, port)) {
+ struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
+
+ /* External frames are queued for device local
+ * distribution, but a copy is given to master
+ * straight away to avoid sending duplicates later
+ * when work-queue processes this frame. This is
+ * achieved by returning RX_HANDLER_PASS.
+ */
+ if (nskb)
+ ipvlan_multicast_enqueue(port, nskb);
+ }
} else {
struct ipvl_addr *addr;
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index 77b92a0fe557..1acc283160d9 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -54,6 +54,9 @@ static int ipvlan_port_create(struct net_device *dev)
for (idx = 0; idx < IPVLAN_HASH_SIZE; idx++)
INIT_HLIST_HEAD(&port->hlhead[idx]);
+ skb_queue_head_init(&port->backlog);
+ INIT_WORK(&port->wq, ipvlan_process_multicast);
+
err = netdev_rx_handler_register(dev, ipvlan_handle_frame, port);
if (err)
goto err;
@@ -72,6 +75,8 @@ static void ipvlan_port_destroy(struct net_device *dev)
dev->priv_flags &= ~IFF_IPVLAN_MASTER;
netdev_rx_handler_unregister(dev);
+ cancel_work_sync(&port->wq);
+ __skb_queue_purge(&port->backlog);
kfree_rcu(port, rcu);
}
@@ -213,17 +218,6 @@ static void ipvlan_change_rx_flags(struct net_device *dev, int change)
dev_set_allmulti(phy_dev, dev->flags & IFF_ALLMULTI? 1 : -1);
}
-static void ipvlan_set_broadcast_mac_filter(struct ipvl_dev *ipvlan, bool set)
-{
- struct net_device *dev = ipvlan->dev;
- unsigned int hashbit = ipvlan_mac_hash(dev->broadcast);
-
- if (set && !test_bit(hashbit, ipvlan->mac_filters))
- __set_bit(hashbit, ipvlan->mac_filters);
- else if (!set && test_bit(hashbit, ipvlan->mac_filters))
- __clear_bit(hashbit, ipvlan->mac_filters);
-}
-
static void ipvlan_set_multicast_mac_filter(struct net_device *dev)
{
struct ipvl_dev *ipvlan = netdev_priv(dev);
@@ -238,6 +232,12 @@ static void ipvlan_set_multicast_mac_filter(struct net_device *dev)
netdev_for_each_mc_addr(ha, dev)
__set_bit(ipvlan_mac_hash(ha->addr), mc_filters);
+ /* Turn-on broadcast bit irrespective of address family,
+ * since broadcast is deferred to a work-queue, hence no
+ * impact on fast-path processing.
+ */
+ __set_bit(ipvlan_mac_hash(dev->broadcast), mc_filters);
+
bitmap_copy(ipvlan->mac_filters, mc_filters,
IPVLAN_MAC_FILTER_SIZE);
}
@@ -705,7 +705,6 @@ static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
*/
if (netif_running(ipvlan->dev))
ipvlan_ht_addr_add(ipvlan, addr);
- ipvlan_set_broadcast_mac_filter(ipvlan, true);
return 0;
}
@@ -722,8 +721,6 @@ static void ipvlan_del_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
list_del(&addr->anode);
ipvlan->ipv4cnt--;
WARN_ON(ipvlan->ipv4cnt < 0);
- if (!ipvlan->ipv4cnt)
- ipvlan_set_broadcast_mac_filter(ipvlan, false);
kfree_rcu(addr, rcu);
return;
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index f6c916312577..25f21968fa5c 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -848,7 +848,9 @@ static void irda_usb_receive(struct urb *urb)
* Jean II */
self->rx_defer_timer.function = irda_usb_rx_defer_expired;
self->rx_defer_timer.data = (unsigned long) urb;
- mod_timer(&self->rx_defer_timer, jiffies + (10 * HZ / 1000));
+ mod_timer(&self->rx_defer_timer,
+ jiffies + msecs_to_jiffies(10));
+
return;
}
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 8c350c5d54ad..6a64197f5bce 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -263,27 +263,21 @@ out:
static void macvtap_del_queues(struct net_device *dev)
{
struct macvlan_dev *vlan = netdev_priv(dev);
- struct macvtap_queue *q, *tmp, *qlist[MAX_MACVTAP_QUEUES];
- int i, j = 0;
+ struct macvtap_queue *q, *tmp;
ASSERT_RTNL();
list_for_each_entry_safe(q, tmp, &vlan->queue_list, next) {
list_del_init(&q->next);
- qlist[j++] = q;
RCU_INIT_POINTER(q->vlan, NULL);
if (q->enabled)
vlan->numvtaps--;
vlan->numqueues--;
+ sock_put(&q->sk);
}
- for (i = 0; i < vlan->numvtaps; i++)
- RCU_INIT_POINTER(vlan->taps[i], NULL);
BUG_ON(vlan->numvtaps);
BUG_ON(vlan->numqueues);
/* guarantee that any future macvtap_set_queue will fail */
vlan->numvtaps = MAX_MACVTAP_QUEUES;
-
- for (--j; j >= 0; j--)
- sock_put(&qlist[j]->sk);
}
static rx_handler_result_t macvtap_handle_frame(struct sk_buff **pskb)
@@ -476,7 +470,7 @@ static int macvtap_open(struct inode *inode, struct file *file)
err = -ENOMEM;
q = (struct macvtap_queue *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL,
- &macvtap_proto);
+ &macvtap_proto, 0);
if (!q)
goto out;
@@ -1006,6 +1000,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
unsigned int __user *up = argp;
unsigned short u;
int __user *sp = argp;
+ struct sockaddr sa;
int s;
int ret;
@@ -1101,6 +1096,37 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
rtnl_unlock();
return ret;
+ case SIOCGIFHWADDR:
+ rtnl_lock();
+ vlan = macvtap_get_vlan(q);
+ if (!vlan) {
+ rtnl_unlock();
+ return -ENOLINK;
+ }
+ ret = 0;
+ u = vlan->dev->type;
+ if (copy_to_user(&ifr->ifr_name, vlan->dev->name, IFNAMSIZ) ||
+ copy_to_user(&ifr->ifr_hwaddr.sa_data, vlan->dev->dev_addr, ETH_ALEN) ||
+ put_user(u, &ifr->ifr_hwaddr.sa_family))
+ ret = -EFAULT;
+ macvtap_put_vlan(vlan);
+ rtnl_unlock();
+ return ret;
+
+ case SIOCSIFHWADDR:
+ if (copy_from_user(&sa, &ifr->ifr_hwaddr, sizeof(sa)))
+ return -EFAULT;
+ rtnl_lock();
+ vlan = macvtap_get_vlan(q);
+ if (!vlan) {
+ rtnl_unlock();
+ return -ENOLINK;
+ }
+ ret = dev_set_mac_address(vlan->dev, &sa);
+ macvtap_put_vlan(vlan);
+ rtnl_unlock();
+ return ret;
+
default:
return -EINVAL;
}
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 70641d2c0429..cf18940f4e84 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -24,13 +24,6 @@ config AMD_PHY
---help---
Currently supports the am79c874
-config AMD_XGBE_PHY
- tristate "Driver for the AMD 10GbE (amd-xgbe) PHYs"
- depends on (OF || ACPI) && HAS_IOMEM
- depends on ARM64 || COMPILE_TEST
- ---help---
- Currently supports the AMD 10GbE PHY
-
config MARVELL_PHY
tristate "Drivers for Marvell PHYs"
---help---
@@ -119,6 +112,11 @@ config MICREL_PHY
---help---
Supports the KSZ9021, VSC8201, KS8001 PHYs.
+config DP83867_PHY
+ tristate "Drivers for Texas Instruments DP83867 Gigabit PHY"
+ ---help---
+ Currently supports the DP83867 PHY.
+
config FIXED_PHY
tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
depends on PHYLIB
@@ -212,7 +210,6 @@ config MDIO_BCM_UNIMAC
This hardware can be found in the Broadcom GENET Ethernet MAC
controllers as well as some Broadcom Ethernet switches such as the
Starfighter 2 switches.
-
endif # PHYLIB
config MICREL_KS8995MA
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 501ea7699a2d..fcc25a0c45cd 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
obj-$(CONFIG_NATIONAL_PHY) += national.o
obj-$(CONFIG_DP83640_PHY) += dp83640.o
+obj-$(CONFIG_DP83867_PHY) += dp83867.o
obj-$(CONFIG_STE10XP) += ste10Xp.o
obj-$(CONFIG_MICREL_PHY) += micrel.o
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
@@ -33,5 +34,4 @@ obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o
obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o
obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o
obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o
-obj-$(CONFIG_AMD_XGBE_PHY) += amd-xgbe-phy.o
obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o
diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c
deleted file mode 100644
index 34a75cba3b73..000000000000
--- a/drivers/net/phy/amd-xgbe-phy.c
+++ /dev/null
@@ -1,1901 +0,0 @@
-/*
- * AMD 10Gb Ethernet PHY driver
- *
- * This file is available to you under your choice of the following two
- * licenses:
- *
- * License 1: GPLv2
- *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
- *
- * This file is free software; you may copy, redistribute and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or (at
- * your option) any later version.
- *
- * This file is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- *
- * License 2: Modified BSD
- *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Advanced Micro Devices, Inc. nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/unistd.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/workqueue.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/mii.h>
-#include <linux/ethtool.h>
-#include <linux/phy.h>
-#include <linux/mdio.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_device.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/property.h>
-#include <linux/acpi.h>
-#include <linux/jiffies.h>
-
-MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_VERSION("1.0.0-a");
-MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
-
-#define XGBE_PHY_ID 0x000162d0
-#define XGBE_PHY_MASK 0xfffffff0
-
-#define XGBE_PHY_SPEEDSET_PROPERTY "amd,speed-set"
-#define XGBE_PHY_BLWC_PROPERTY "amd,serdes-blwc"
-#define XGBE_PHY_CDR_RATE_PROPERTY "amd,serdes-cdr-rate"
-#define XGBE_PHY_PQ_SKEW_PROPERTY "amd,serdes-pq-skew"
-#define XGBE_PHY_TX_AMP_PROPERTY "amd,serdes-tx-amp"
-#define XGBE_PHY_DFE_CFG_PROPERTY "amd,serdes-dfe-tap-config"
-#define XGBE_PHY_DFE_ENA_PROPERTY "amd,serdes-dfe-tap-enable"
-
-#define XGBE_PHY_SPEEDS 3
-#define XGBE_PHY_SPEED_1000 0
-#define XGBE_PHY_SPEED_2500 1
-#define XGBE_PHY_SPEED_10000 2
-
-#define XGBE_AN_MS_TIMEOUT 500
-
-#define XGBE_AN_INT_CMPLT 0x01
-#define XGBE_AN_INC_LINK 0x02
-#define XGBE_AN_PG_RCV 0x04
-#define XGBE_AN_INT_MASK 0x07
-
-#define XNP_MCF_NULL_MESSAGE 0x001
-#define XNP_ACK_PROCESSED BIT(12)
-#define XNP_MP_FORMATTED BIT(13)
-#define XNP_NP_EXCHANGE BIT(15)
-
-#define XGBE_PHY_RATECHANGE_COUNT 500
-
-#define XGBE_PHY_KR_TRAINING_START 0x01
-#define XGBE_PHY_KR_TRAINING_ENABLE 0x02
-
-#define XGBE_PHY_FEC_ENABLE 0x01
-#define XGBE_PHY_FEC_FORWARD 0x02
-#define XGBE_PHY_FEC_MASK 0x03
-
-#ifndef MDIO_PMA_10GBR_PMD_CTRL
-#define MDIO_PMA_10GBR_PMD_CTRL 0x0096
-#endif
-
-#ifndef MDIO_PMA_10GBR_FEC_ABILITY
-#define MDIO_PMA_10GBR_FEC_ABILITY 0x00aa
-#endif
-
-#ifndef MDIO_PMA_10GBR_FEC_CTRL
-#define MDIO_PMA_10GBR_FEC_CTRL 0x00ab
-#endif
-
-#ifndef MDIO_AN_XNP
-#define MDIO_AN_XNP 0x0016
-#endif
-
-#ifndef MDIO_AN_LPX
-#define MDIO_AN_LPX 0x0019
-#endif
-
-#ifndef MDIO_AN_INTMASK
-#define MDIO_AN_INTMASK 0x8001
-#endif
-
-#ifndef MDIO_AN_INT
-#define MDIO_AN_INT 0x8002
-#endif
-
-#ifndef MDIO_CTRL1_SPEED1G
-#define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
-#endif
-
-/* SerDes integration register offsets */
-#define SIR0_KR_RT_1 0x002c
-#define SIR0_STATUS 0x0040
-#define SIR1_SPEED 0x0000
-
-/* SerDes integration register entry bit positions and sizes */
-#define SIR0_KR_RT_1_RESET_INDEX 11
-#define SIR0_KR_RT_1_RESET_WIDTH 1
-#define SIR0_STATUS_RX_READY_INDEX 0
-#define SIR0_STATUS_RX_READY_WIDTH 1
-#define SIR0_STATUS_TX_READY_INDEX 8
-#define SIR0_STATUS_TX_READY_WIDTH 1
-#define SIR1_SPEED_CDR_RATE_INDEX 12
-#define SIR1_SPEED_CDR_RATE_WIDTH 4
-#define SIR1_SPEED_DATARATE_INDEX 4
-#define SIR1_SPEED_DATARATE_WIDTH 2
-#define SIR1_SPEED_PLLSEL_INDEX 3
-#define SIR1_SPEED_PLLSEL_WIDTH 1
-#define SIR1_SPEED_RATECHANGE_INDEX 6
-#define SIR1_SPEED_RATECHANGE_WIDTH 1
-#define SIR1_SPEED_TXAMP_INDEX 8
-#define SIR1_SPEED_TXAMP_WIDTH 4
-#define SIR1_SPEED_WORDMODE_INDEX 0
-#define SIR1_SPEED_WORDMODE_WIDTH 3
-
-#define SPEED_10000_BLWC 0
-#define SPEED_10000_CDR 0x7
-#define SPEED_10000_PLL 0x1
-#define SPEED_10000_PQ 0x12
-#define SPEED_10000_RATE 0x0
-#define SPEED_10000_TXAMP 0xa
-#define SPEED_10000_WORD 0x7
-#define SPEED_10000_DFE_TAP_CONFIG 0x1
-#define SPEED_10000_DFE_TAP_ENABLE 0x7f
-
-#define SPEED_2500_BLWC 1
-#define SPEED_2500_CDR 0x2
-#define SPEED_2500_PLL 0x0
-#define SPEED_2500_PQ 0xa
-#define SPEED_2500_RATE 0x1
-#define SPEED_2500_TXAMP 0xf
-#define SPEED_2500_WORD 0x1
-#define SPEED_2500_DFE_TAP_CONFIG 0x3
-#define SPEED_2500_DFE_TAP_ENABLE 0x0
-
-#define SPEED_1000_BLWC 1
-#define SPEED_1000_CDR 0x2
-#define SPEED_1000_PLL 0x0
-#define SPEED_1000_PQ 0xa
-#define SPEED_1000_RATE 0x3
-#define SPEED_1000_TXAMP 0xf
-#define SPEED_1000_WORD 0x1
-#define SPEED_1000_DFE_TAP_CONFIG 0x3
-#define SPEED_1000_DFE_TAP_ENABLE 0x0
-
-/* SerDes RxTx register offsets */
-#define RXTX_REG6 0x0018
-#define RXTX_REG20 0x0050
-#define RXTX_REG22 0x0058
-#define RXTX_REG114 0x01c8
-#define RXTX_REG129 0x0204
-
-/* SerDes RxTx register entry bit positions and sizes */
-#define RXTX_REG6_RESETB_RXD_INDEX 8
-#define RXTX_REG6_RESETB_RXD_WIDTH 1
-#define RXTX_REG20_BLWC_ENA_INDEX 2
-#define RXTX_REG20_BLWC_ENA_WIDTH 1
-#define RXTX_REG114_PQ_REG_INDEX 9
-#define RXTX_REG114_PQ_REG_WIDTH 7
-#define RXTX_REG129_RXDFE_CONFIG_INDEX 14
-#define RXTX_REG129_RXDFE_CONFIG_WIDTH 2
-
-/* Bit setting and getting macros
- * The get macro will extract the current bit field value from within
- * the variable
- *
- * The set macro will clear the current bit field value within the
- * variable and then set the bit field of the variable to the
- * specified value
- */
-#define GET_BITS(_var, _index, _width) \
- (((_var) >> (_index)) & ((0x1 << (_width)) - 1))
-
-#define SET_BITS(_var, _index, _width, _val) \
-do { \
- (_var) &= ~(((0x1 << (_width)) - 1) << (_index)); \
- (_var) |= (((_val) & ((0x1 << (_width)) - 1)) << (_index)); \
-} while (0)
-
-#define XSIR_GET_BITS(_var, _prefix, _field) \
- GET_BITS((_var), \
- _prefix##_##_field##_INDEX, \
- _prefix##_##_field##_WIDTH)
-
-#define XSIR_SET_BITS(_var, _prefix, _field, _val) \
- SET_BITS((_var), \
- _prefix##_##_field##_INDEX, \
- _prefix##_##_field##_WIDTH, (_val))
-
-/* Macros for reading or writing SerDes integration registers
- * The ioread macros will get bit fields or full values using the
- * register definitions formed using the input names
- *
- * The iowrite macros will set bit fields or full values using the
- * register definitions formed using the input names
- */
-#define XSIR0_IOREAD(_priv, _reg) \
- ioread16((_priv)->sir0_regs + _reg)
-
-#define XSIR0_IOREAD_BITS(_priv, _reg, _field) \
- GET_BITS(XSIR0_IOREAD((_priv), _reg), \
- _reg##_##_field##_INDEX, \
- _reg##_##_field##_WIDTH)
-
-#define XSIR0_IOWRITE(_priv, _reg, _val) \
- iowrite16((_val), (_priv)->sir0_regs + _reg)
-
-#define XSIR0_IOWRITE_BITS(_priv, _reg, _field, _val) \
-do { \
- u16 reg_val = XSIR0_IOREAD((_priv), _reg); \
- SET_BITS(reg_val, \
- _reg##_##_field##_INDEX, \
- _reg##_##_field##_WIDTH, (_val)); \
- XSIR0_IOWRITE((_priv), _reg, reg_val); \
-} while (0)
-
-#define XSIR1_IOREAD(_priv, _reg) \
- ioread16((_priv)->sir1_regs + _reg)
-
-#define XSIR1_IOREAD_BITS(_priv, _reg, _field) \
- GET_BITS(XSIR1_IOREAD((_priv), _reg), \
- _reg##_##_field##_INDEX, \
- _reg##_##_field##_WIDTH)
-
-#define XSIR1_IOWRITE(_priv, _reg, _val) \
- iowrite16((_val), (_priv)->sir1_regs + _reg)
-
-#define XSIR1_IOWRITE_BITS(_priv, _reg, _field, _val) \
-do { \
- u16 reg_val = XSIR1_IOREAD((_priv), _reg); \
- SET_BITS(reg_val, \
- _reg##_##_field##_INDEX, \
- _reg##_##_field##_WIDTH, (_val)); \
- XSIR1_IOWRITE((_priv), _reg, reg_val); \
-} while (0)
-
-/* Macros for reading or writing SerDes RxTx registers
- * The ioread macros will get bit fields or full values using the
- * register definitions formed using the input names
- *
- * The iowrite macros will set bit fields or full values using the
- * register definitions formed using the input names
- */
-#define XRXTX_IOREAD(_priv, _reg) \
- ioread16((_priv)->rxtx_regs + _reg)
-
-#define XRXTX_IOREAD_BITS(_priv, _reg, _field) \
- GET_BITS(XRXTX_IOREAD((_priv), _reg), \
- _reg##_##_field##_INDEX, \
- _reg##_##_field##_WIDTH)
-
-#define XRXTX_IOWRITE(_priv, _reg, _val) \
- iowrite16((_val), (_priv)->rxtx_regs + _reg)
-
-#define XRXTX_IOWRITE_BITS(_priv, _reg, _field, _val) \
-do { \
- u16 reg_val = XRXTX_IOREAD((_priv), _reg); \
- SET_BITS(reg_val, \
- _reg##_##_field##_INDEX, \
- _reg##_##_field##_WIDTH, (_val)); \
- XRXTX_IOWRITE((_priv), _reg, reg_val); \
-} while (0)
-
-static const u32 amd_xgbe_phy_serdes_blwc[] = {
- SPEED_1000_BLWC,
- SPEED_2500_BLWC,
- SPEED_10000_BLWC,
-};
-
-static const u32 amd_xgbe_phy_serdes_cdr_rate[] = {
- SPEED_1000_CDR,
- SPEED_2500_CDR,
- SPEED_10000_CDR,
-};
-
-static const u32 amd_xgbe_phy_serdes_pq_skew[] = {
- SPEED_1000_PQ,
- SPEED_2500_PQ,
- SPEED_10000_PQ,
-};
-
-static const u32 amd_xgbe_phy_serdes_tx_amp[] = {
- SPEED_1000_TXAMP,
- SPEED_2500_TXAMP,
- SPEED_10000_TXAMP,
-};
-
-static const u32 amd_xgbe_phy_serdes_dfe_tap_cfg[] = {
- SPEED_1000_DFE_TAP_CONFIG,
- SPEED_2500_DFE_TAP_CONFIG,
- SPEED_10000_DFE_TAP_CONFIG,
-};
-
-static const u32 amd_xgbe_phy_serdes_dfe_tap_ena[] = {
- SPEED_1000_DFE_TAP_ENABLE,
- SPEED_2500_DFE_TAP_ENABLE,
- SPEED_10000_DFE_TAP_ENABLE,
-};
-
-enum amd_xgbe_phy_an {
- AMD_XGBE_AN_READY = 0,
- AMD_XGBE_AN_PAGE_RECEIVED,
- AMD_XGBE_AN_INCOMPAT_LINK,
- AMD_XGBE_AN_COMPLETE,
- AMD_XGBE_AN_NO_LINK,
- AMD_XGBE_AN_ERROR,
-};
-
-enum amd_xgbe_phy_rx {
- AMD_XGBE_RX_BPA = 0,
- AMD_XGBE_RX_XNP,
- AMD_XGBE_RX_COMPLETE,
- AMD_XGBE_RX_ERROR,
-};
-
-enum amd_xgbe_phy_mode {
- AMD_XGBE_MODE_KR,
- AMD_XGBE_MODE_KX,
-};
-
-enum amd_xgbe_phy_speedset {
- AMD_XGBE_PHY_SPEEDSET_1000_10000 = 0,
- AMD_XGBE_PHY_SPEEDSET_2500_10000,
-};
-
-struct amd_xgbe_phy_priv {
- struct platform_device *pdev;
- struct acpi_device *adev;
- struct device *dev;
-
- struct phy_device *phydev;
-
- /* SerDes related mmio resources */
- struct resource *rxtx_res;
- struct resource *sir0_res;
- struct resource *sir1_res;
-
- /* SerDes related mmio registers */
- void __iomem *rxtx_regs; /* SerDes Rx/Tx CSRs */
- void __iomem *sir0_regs; /* SerDes integration registers (1/2) */
- void __iomem *sir1_regs; /* SerDes integration registers (2/2) */
-
- int an_irq;
- char an_irq_name[IFNAMSIZ + 32];
- struct work_struct an_irq_work;
- unsigned int an_irq_allocated;
-
- unsigned int speed_set;
-
- /* SerDes UEFI configurable settings.
- * Switching between modes/speeds requires new values for some
- * SerDes settings. The values can be supplied as device
- * properties in array format. The first array entry is for
- * 1GbE, second for 2.5GbE and third for 10GbE
- */
- u32 serdes_blwc[XGBE_PHY_SPEEDS];
- u32 serdes_cdr_rate[XGBE_PHY_SPEEDS];
- u32 serdes_pq_skew[XGBE_PHY_SPEEDS];
- u32 serdes_tx_amp[XGBE_PHY_SPEEDS];
- u32 serdes_dfe_tap_cfg[XGBE_PHY_SPEEDS];
- u32 serdes_dfe_tap_ena[XGBE_PHY_SPEEDS];
-
- /* Auto-negotiation state machine support */
- struct mutex an_mutex;
- enum amd_xgbe_phy_an an_result;
- enum amd_xgbe_phy_an an_state;
- enum amd_xgbe_phy_rx kr_state;
- enum amd_xgbe_phy_rx kx_state;
- struct work_struct an_work;
- struct workqueue_struct *an_workqueue;
- unsigned int an_supported;
- unsigned int parallel_detect;
- unsigned int fec_ability;
- unsigned long an_start;
-
- unsigned int lpm_ctrl; /* CTRL1 for resume */
-};
-
-static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev)
-{
- int ret;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
- if (ret < 0)
- return ret;
-
- ret |= XGBE_PHY_KR_TRAINING_ENABLE;
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret);
-
- return 0;
-}
-
-static int amd_xgbe_an_disable_kr_training(struct phy_device *phydev)
-{
- int ret;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
- if (ret < 0)
- return ret;
-
- ret &= ~XGBE_PHY_KR_TRAINING_ENABLE;
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret);
-
- return 0;
-}
-
-static int amd_xgbe_phy_pcs_power_cycle(struct phy_device *phydev)
-{
- int ret;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- return ret;
-
- ret |= MDIO_CTRL1_LPOWER;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
-
- usleep_range(75, 100);
-
- ret &= ~MDIO_CTRL1_LPOWER;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
-
- return 0;
-}
-
-static void amd_xgbe_phy_serdes_start_ratechange(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
-
- /* Assert Rx and Tx ratechange */
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, RATECHANGE, 1);
-}
-
-static void amd_xgbe_phy_serdes_complete_ratechange(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- unsigned int wait;
- u16 status;
-
- /* Release Rx and Tx ratechange */
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, RATECHANGE, 0);
-
- /* Wait for Rx and Tx ready */
- wait = XGBE_PHY_RATECHANGE_COUNT;
- while (wait--) {
- usleep_range(50, 75);
-
- status = XSIR0_IOREAD(priv, SIR0_STATUS);
- if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) &&
- XSIR_GET_BITS(status, SIR0_STATUS, TX_READY))
- goto rx_reset;
- }
-
- netdev_dbg(phydev->attached_dev, "SerDes rx/tx not ready (%#hx)\n",
- status);
-
-rx_reset:
- /* Perform Rx reset for the DFE changes */
- XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RESETB_RXD, 0);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RESETB_RXD, 1);
-}
-
-static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- int ret;
-
- /* Enable KR training */
- ret = amd_xgbe_an_enable_kr_training(phydev);
- if (ret < 0)
- return ret;
-
- /* Set PCS to KR/10G speed */
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
- if (ret < 0)
- return ret;
-
- ret &= ~MDIO_PCS_CTRL2_TYPE;
- ret |= MDIO_PCS_CTRL2_10GBR;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2, ret);
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- return ret;
-
- ret &= ~MDIO_CTRL1_SPEEDSEL;
- ret |= MDIO_CTRL1_SPEED10G;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
-
- ret = amd_xgbe_phy_pcs_power_cycle(phydev);
- if (ret < 0)
- return ret;
-
- /* Set SerDes to 10G speed */
- amd_xgbe_phy_serdes_start_ratechange(phydev);
-
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_10000_RATE);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_10000_WORD);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_10000_PLL);
-
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE,
- priv->serdes_cdr_rate[XGBE_PHY_SPEED_10000]);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP,
- priv->serdes_tx_amp[XGBE_PHY_SPEED_10000]);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA,
- priv->serdes_blwc[XGBE_PHY_SPEED_10000]);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG,
- priv->serdes_pq_skew[XGBE_PHY_SPEED_10000]);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG,
- priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_10000]);
- XRXTX_IOWRITE(priv, RXTX_REG22,
- priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_10000]);
-
- amd_xgbe_phy_serdes_complete_ratechange(phydev);
-
- return 0;
-}
-
-static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- int ret;
-
- /* Disable KR training */
- ret = amd_xgbe_an_disable_kr_training(phydev);
- if (ret < 0)
- return ret;
-
- /* Set PCS to KX/1G speed */
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
- if (ret < 0)
- return ret;
-
- ret &= ~MDIO_PCS_CTRL2_TYPE;
- ret |= MDIO_PCS_CTRL2_10GBX;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2, ret);
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- return ret;
-
- ret &= ~MDIO_CTRL1_SPEEDSEL;
- ret |= MDIO_CTRL1_SPEED1G;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
-
- ret = amd_xgbe_phy_pcs_power_cycle(phydev);
- if (ret < 0)
- return ret;
-
- /* Set SerDes to 2.5G speed */
- amd_xgbe_phy_serdes_start_ratechange(phydev);
-
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_2500_RATE);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_2500_WORD);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_2500_PLL);
-
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE,
- priv->serdes_cdr_rate[XGBE_PHY_SPEED_2500]);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP,
- priv->serdes_tx_amp[XGBE_PHY_SPEED_2500]);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA,
- priv->serdes_blwc[XGBE_PHY_SPEED_2500]);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG,
- priv->serdes_pq_skew[XGBE_PHY_SPEED_2500]);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG,
- priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_2500]);
- XRXTX_IOWRITE(priv, RXTX_REG22,
- priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_2500]);
-
- amd_xgbe_phy_serdes_complete_ratechange(phydev);
-
- return 0;
-}
-
-static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- int ret;
-
- /* Disable KR training */
- ret = amd_xgbe_an_disable_kr_training(phydev);
- if (ret < 0)
- return ret;
-
- /* Set PCS to KX/1G speed */
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
- if (ret < 0)
- return ret;
-
- ret &= ~MDIO_PCS_CTRL2_TYPE;
- ret |= MDIO_PCS_CTRL2_10GBX;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2, ret);
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- return ret;
-
- ret &= ~MDIO_CTRL1_SPEEDSEL;
- ret |= MDIO_CTRL1_SPEED1G;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
-
- ret = amd_xgbe_phy_pcs_power_cycle(phydev);
- if (ret < 0)
- return ret;
-
- /* Set SerDes to 1G speed */
- amd_xgbe_phy_serdes_start_ratechange(phydev);
-
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_1000_RATE);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_1000_WORD);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_1000_PLL);
-
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE,
- priv->serdes_cdr_rate[XGBE_PHY_SPEED_1000]);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP,
- priv->serdes_tx_amp[XGBE_PHY_SPEED_1000]);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA,
- priv->serdes_blwc[XGBE_PHY_SPEED_1000]);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG,
- priv->serdes_pq_skew[XGBE_PHY_SPEED_1000]);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG,
- priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_1000]);
- XRXTX_IOWRITE(priv, RXTX_REG22,
- priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_1000]);
-
- amd_xgbe_phy_serdes_complete_ratechange(phydev);
-
- return 0;
-}
-
-static int amd_xgbe_phy_cur_mode(struct phy_device *phydev,
- enum amd_xgbe_phy_mode *mode)
-{
- int ret;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
- if (ret < 0)
- return ret;
-
- if ((ret & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR)
- *mode = AMD_XGBE_MODE_KR;
- else
- *mode = AMD_XGBE_MODE_KX;
-
- return 0;
-}
-
-static bool amd_xgbe_phy_in_kr_mode(struct phy_device *phydev)
-{
- enum amd_xgbe_phy_mode mode;
-
- if (amd_xgbe_phy_cur_mode(phydev, &mode))
- return false;
-
- return (mode == AMD_XGBE_MODE_KR);
-}
-
-static int amd_xgbe_phy_switch_mode(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- int ret;
-
- /* If we are in KR switch to KX, and vice-versa */
- if (amd_xgbe_phy_in_kr_mode(phydev)) {
- if (priv->speed_set == AMD_XGBE_PHY_SPEEDSET_1000_10000)
- ret = amd_xgbe_phy_gmii_mode(phydev);
- else
- ret = amd_xgbe_phy_gmii_2500_mode(phydev);
- } else {
- ret = amd_xgbe_phy_xgmii_mode(phydev);
- }
-
- return ret;
-}
-
-static int amd_xgbe_phy_set_mode(struct phy_device *phydev,
- enum amd_xgbe_phy_mode mode)
-{
- enum amd_xgbe_phy_mode cur_mode;
- int ret;
-
- ret = amd_xgbe_phy_cur_mode(phydev, &cur_mode);
- if (ret)
- return ret;
-
- if (mode != cur_mode)
- ret = amd_xgbe_phy_switch_mode(phydev);
-
- return ret;
-}
-
-static bool amd_xgbe_phy_use_xgmii_mode(struct phy_device *phydev)
-{
- if (phydev->autoneg == AUTONEG_ENABLE) {
- if (phydev->advertising & ADVERTISED_10000baseKR_Full)
- return true;
- } else {
- if (phydev->speed == SPEED_10000)
- return true;
- }
-
- return false;
-}
-
-static bool amd_xgbe_phy_use_gmii_2500_mode(struct phy_device *phydev)
-{
- if (phydev->autoneg == AUTONEG_ENABLE) {
- if (phydev->advertising & ADVERTISED_2500baseX_Full)
- return true;
- } else {
- if (phydev->speed == SPEED_2500)
- return true;
- }
-
- return false;
-}
-
-static bool amd_xgbe_phy_use_gmii_mode(struct phy_device *phydev)
-{
- if (phydev->autoneg == AUTONEG_ENABLE) {
- if (phydev->advertising & ADVERTISED_1000baseKX_Full)
- return true;
- } else {
- if (phydev->speed == SPEED_1000)
- return true;
- }
-
- return false;
-}
-
-static int amd_xgbe_phy_set_an(struct phy_device *phydev, bool enable,
- bool restart)
-{
- int ret;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
- if (ret < 0)
- return ret;
-
- ret &= ~MDIO_AN_CTRL1_ENABLE;
-
- if (enable)
- ret |= MDIO_AN_CTRL1_ENABLE;
-
- if (restart)
- ret |= MDIO_AN_CTRL1_RESTART;
-
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret);
-
- return 0;
-}
-
-static int amd_xgbe_phy_restart_an(struct phy_device *phydev)
-{
- return amd_xgbe_phy_set_an(phydev, true, true);
-}
-
-static int amd_xgbe_phy_disable_an(struct phy_device *phydev)
-{
- return amd_xgbe_phy_set_an(phydev, false, false);
-}
-
-static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev,
- enum amd_xgbe_phy_rx *state)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- int ad_reg, lp_reg, ret;
-
- *state = AMD_XGBE_RX_COMPLETE;
-
- /* If we're not in KR mode then we're done */
- if (!amd_xgbe_phy_in_kr_mode(phydev))
- return AMD_XGBE_AN_PAGE_RECEIVED;
-
- /* Enable/Disable FEC */
- ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
- if (ad_reg < 0)
- return AMD_XGBE_AN_ERROR;
-
- lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA + 2);
- if (lp_reg < 0)
- return AMD_XGBE_AN_ERROR;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL);
- if (ret < 0)
- return AMD_XGBE_AN_ERROR;
-
- ret &= ~XGBE_PHY_FEC_MASK;
- if ((ad_reg & 0xc000) && (lp_reg & 0xc000))
- ret |= priv->fec_ability;
-
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL, ret);
-
- /* Start KR training */
- ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
- if (ret < 0)
- return AMD_XGBE_AN_ERROR;
-
- if (ret & XGBE_PHY_KR_TRAINING_ENABLE) {
- XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1);
-
- ret |= XGBE_PHY_KR_TRAINING_START;
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
- ret);
-
- XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0);
- }
-
- return AMD_XGBE_AN_PAGE_RECEIVED;
-}
-
-static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev,
- enum amd_xgbe_phy_rx *state)
-{
- u16 msg;
-
- *state = AMD_XGBE_RX_XNP;
-
- msg = XNP_MCF_NULL_MESSAGE;
- msg |= XNP_MP_FORMATTED;
-
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP + 2, 0);
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0);
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP, msg);
-
- return AMD_XGBE_AN_PAGE_RECEIVED;
-}
-
-static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev,
- enum amd_xgbe_phy_rx *state)
-{
- unsigned int link_support;
- int ret, ad_reg, lp_reg;
-
- /* Read Base Ability register 2 first */
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA + 1);
- if (ret < 0)
- return AMD_XGBE_AN_ERROR;
-
- /* Check for a supported mode, otherwise restart in a different one */
- link_support = amd_xgbe_phy_in_kr_mode(phydev) ? 0x80 : 0x20;
- if (!(ret & link_support))
- return AMD_XGBE_AN_INCOMPAT_LINK;
-
- /* Check Extended Next Page support */
- ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
- if (ad_reg < 0)
- return AMD_XGBE_AN_ERROR;
-
- lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA);
- if (lp_reg < 0)
- return AMD_XGBE_AN_ERROR;
-
- return ((ad_reg & XNP_NP_EXCHANGE) || (lp_reg & XNP_NP_EXCHANGE)) ?
- amd_xgbe_an_tx_xnp(phydev, state) :
- amd_xgbe_an_tx_training(phydev, state);
-}
-
-static enum amd_xgbe_phy_an amd_xgbe_an_rx_xnp(struct phy_device *phydev,
- enum amd_xgbe_phy_rx *state)
-{
- int ad_reg, lp_reg;
-
- /* Check Extended Next Page support */
- ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP);
- if (ad_reg < 0)
- return AMD_XGBE_AN_ERROR;
-
- lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPX);
- if (lp_reg < 0)
- return AMD_XGBE_AN_ERROR;
-
- return ((ad_reg & XNP_NP_EXCHANGE) || (lp_reg & XNP_NP_EXCHANGE)) ?
- amd_xgbe_an_tx_xnp(phydev, state) :
- amd_xgbe_an_tx_training(phydev, state);
-}
-
-static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- enum amd_xgbe_phy_rx *state;
- unsigned long an_timeout;
- int ret;
-
- if (!priv->an_start) {
- priv->an_start = jiffies;
- } else {
- an_timeout = priv->an_start +
- msecs_to_jiffies(XGBE_AN_MS_TIMEOUT);
- if (time_after(jiffies, an_timeout)) {
- /* Auto-negotiation timed out, reset state */
- priv->kr_state = AMD_XGBE_RX_BPA;
- priv->kx_state = AMD_XGBE_RX_BPA;
-
- priv->an_start = jiffies;
- }
- }
-
- state = amd_xgbe_phy_in_kr_mode(phydev) ? &priv->kr_state
- : &priv->kx_state;
-
- switch (*state) {
- case AMD_XGBE_RX_BPA:
- ret = amd_xgbe_an_rx_bpa(phydev, state);
- break;
-
- case AMD_XGBE_RX_XNP:
- ret = amd_xgbe_an_rx_xnp(phydev, state);
- break;
-
- default:
- ret = AMD_XGBE_AN_ERROR;
- }
-
- return ret;
-}
-
-static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- int ret;
-
- /* Be sure we aren't looping trying to negotiate */
- if (amd_xgbe_phy_in_kr_mode(phydev)) {
- priv->kr_state = AMD_XGBE_RX_ERROR;
-
- if (!(phydev->advertising & SUPPORTED_1000baseKX_Full) &&
- !(phydev->advertising & SUPPORTED_2500baseX_Full))
- return AMD_XGBE_AN_NO_LINK;
-
- if (priv->kx_state != AMD_XGBE_RX_BPA)
- return AMD_XGBE_AN_NO_LINK;
- } else {
- priv->kx_state = AMD_XGBE_RX_ERROR;
-
- if (!(phydev->advertising & SUPPORTED_10000baseKR_Full))
- return AMD_XGBE_AN_NO_LINK;
-
- if (priv->kr_state != AMD_XGBE_RX_BPA)
- return AMD_XGBE_AN_NO_LINK;
- }
-
- ret = amd_xgbe_phy_disable_an(phydev);
- if (ret)
- return AMD_XGBE_AN_ERROR;
-
- ret = amd_xgbe_phy_switch_mode(phydev);
- if (ret)
- return AMD_XGBE_AN_ERROR;
-
- ret = amd_xgbe_phy_restart_an(phydev);
- if (ret)
- return AMD_XGBE_AN_ERROR;
-
- return AMD_XGBE_AN_INCOMPAT_LINK;
-}
-
-static irqreturn_t amd_xgbe_an_isr(int irq, void *data)
-{
- struct amd_xgbe_phy_priv *priv = (struct amd_xgbe_phy_priv *)data;
-
- /* Interrupt reason must be read and cleared outside of IRQ context */
- disable_irq_nosync(priv->an_irq);
-
- queue_work(priv->an_workqueue, &priv->an_irq_work);
-
- return IRQ_HANDLED;
-}
-
-static void amd_xgbe_an_irq_work(struct work_struct *work)
-{
- struct amd_xgbe_phy_priv *priv = container_of(work,
- struct amd_xgbe_phy_priv,
- an_irq_work);
-
- /* Avoid a race between enabling the IRQ and exiting the work by
- * waiting for the work to finish and then queueing it
- */
- flush_work(&priv->an_work);
- queue_work(priv->an_workqueue, &priv->an_work);
-}
-
-static void amd_xgbe_an_state_machine(struct work_struct *work)
-{
- struct amd_xgbe_phy_priv *priv = container_of(work,
- struct amd_xgbe_phy_priv,
- an_work);
- struct phy_device *phydev = priv->phydev;
- enum amd_xgbe_phy_an cur_state = priv->an_state;
- int int_reg, int_mask;
-
- mutex_lock(&priv->an_mutex);
-
- /* Read the interrupt */
- int_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT);
- if (!int_reg)
- goto out;
-
-next_int:
- if (int_reg < 0) {
- priv->an_state = AMD_XGBE_AN_ERROR;
- int_mask = XGBE_AN_INT_MASK;
- } else if (int_reg & XGBE_AN_PG_RCV) {
- priv->an_state = AMD_XGBE_AN_PAGE_RECEIVED;
- int_mask = XGBE_AN_PG_RCV;
- } else if (int_reg & XGBE_AN_INC_LINK) {
- priv->an_state = AMD_XGBE_AN_INCOMPAT_LINK;
- int_mask = XGBE_AN_INC_LINK;
- } else if (int_reg & XGBE_AN_INT_CMPLT) {
- priv->an_state = AMD_XGBE_AN_COMPLETE;
- int_mask = XGBE_AN_INT_CMPLT;
- } else {
- priv->an_state = AMD_XGBE_AN_ERROR;
- int_mask = 0;
- }
-
- /* Clear the interrupt to be processed */
- int_reg &= ~int_mask;
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, int_reg);
-
- priv->an_result = priv->an_state;
-
-again:
- cur_state = priv->an_state;
-
- switch (priv->an_state) {
- case AMD_XGBE_AN_READY:
- priv->an_supported = 0;
- break;
-
- case AMD_XGBE_AN_PAGE_RECEIVED:
- priv->an_state = amd_xgbe_an_page_received(phydev);
- priv->an_supported++;
- break;
-
- case AMD_XGBE_AN_INCOMPAT_LINK:
- priv->an_supported = 0;
- priv->parallel_detect = 0;
- priv->an_state = amd_xgbe_an_incompat_link(phydev);
- break;
-
- case AMD_XGBE_AN_COMPLETE:
- priv->parallel_detect = priv->an_supported ? 0 : 1;
- netdev_dbg(phydev->attached_dev, "%s successful\n",
- priv->an_supported ? "Auto negotiation"
- : "Parallel detection");
- break;
-
- case AMD_XGBE_AN_NO_LINK:
- break;
-
- default:
- priv->an_state = AMD_XGBE_AN_ERROR;
- }
-
- if (priv->an_state == AMD_XGBE_AN_NO_LINK) {
- int_reg = 0;
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
- } else if (priv->an_state == AMD_XGBE_AN_ERROR) {
- netdev_err(phydev->attached_dev,
- "error during auto-negotiation, state=%u\n",
- cur_state);
-
- int_reg = 0;
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
- }
-
- if (priv->an_state >= AMD_XGBE_AN_COMPLETE) {
- priv->an_result = priv->an_state;
- priv->an_state = AMD_XGBE_AN_READY;
- priv->kr_state = AMD_XGBE_RX_BPA;
- priv->kx_state = AMD_XGBE_RX_BPA;
- priv->an_start = 0;
- }
-
- if (cur_state != priv->an_state)
- goto again;
-
- if (int_reg)
- goto next_int;
-
-out:
- enable_irq(priv->an_irq);
-
- mutex_unlock(&priv->an_mutex);
-}
-
-static int amd_xgbe_an_init(struct phy_device *phydev)
-{
- int ret;
-
- /* Set up Advertisement register 3 first */
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
- if (ret < 0)
- return ret;
-
- if (phydev->advertising & SUPPORTED_10000baseR_FEC)
- ret |= 0xc000;
- else
- ret &= ~0xc000;
-
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, ret);
-
- /* Set up Advertisement register 2 next */
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
- if (ret < 0)
- return ret;
-
- if (phydev->advertising & SUPPORTED_10000baseKR_Full)
- ret |= 0x80;
- else
- ret &= ~0x80;
-
- if ((phydev->advertising & SUPPORTED_1000baseKX_Full) ||
- (phydev->advertising & SUPPORTED_2500baseX_Full))
- ret |= 0x20;
- else
- ret &= ~0x20;
-
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, ret);
-
- /* Set up Advertisement register 1 last */
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
- if (ret < 0)
- return ret;
-
- if (phydev->advertising & SUPPORTED_Pause)
- ret |= 0x400;
- else
- ret &= ~0x400;
-
- if (phydev->advertising & SUPPORTED_Asym_Pause)
- ret |= 0x800;
- else
- ret &= ~0x800;
-
- /* We don't intend to perform XNP */
- ret &= ~XNP_NP_EXCHANGE;
-
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, ret);
-
- return 0;
-}
-
-static int amd_xgbe_phy_soft_reset(struct phy_device *phydev)
-{
- int count, ret;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- return ret;
-
- ret |= MDIO_CTRL1_RESET;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
-
- count = 50;
- do {
- msleep(20);
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- return ret;
- } while ((ret & MDIO_CTRL1_RESET) && --count);
-
- if (ret & MDIO_CTRL1_RESET)
- return -ETIMEDOUT;
-
- /* Disable auto-negotiation for now */
- ret = amd_xgbe_phy_disable_an(phydev);
- if (ret < 0)
- return ret;
-
- /* Clear auto-negotiation interrupts */
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
-
- return 0;
-}
-
-static int amd_xgbe_phy_config_init(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- struct net_device *netdev = phydev->attached_dev;
- int ret;
-
- if (!priv->an_irq_allocated) {
- /* Allocate the auto-negotiation workqueue and interrupt */
- snprintf(priv->an_irq_name, sizeof(priv->an_irq_name) - 1,
- "%s-pcs", netdev_name(netdev));
-
- priv->an_workqueue =
- create_singlethread_workqueue(priv->an_irq_name);
- if (!priv->an_workqueue) {
- netdev_err(netdev, "phy workqueue creation failed\n");
- return -ENOMEM;
- }
-
- ret = devm_request_irq(priv->dev, priv->an_irq,
- amd_xgbe_an_isr, 0, priv->an_irq_name,
- priv);
- if (ret) {
- netdev_err(netdev, "phy irq request failed\n");
- destroy_workqueue(priv->an_workqueue);
- return ret;
- }
-
- priv->an_irq_allocated = 1;
- }
-
- /* Set initial mode - call the mode setting routines
- * directly to insure we are properly configured
- */
- if (amd_xgbe_phy_use_xgmii_mode(phydev))
- ret = amd_xgbe_phy_xgmii_mode(phydev);
- else if (amd_xgbe_phy_use_gmii_mode(phydev))
- ret = amd_xgbe_phy_gmii_mode(phydev);
- else if (amd_xgbe_phy_use_gmii_2500_mode(phydev))
- ret = amd_xgbe_phy_gmii_2500_mode(phydev);
- else
- ret = -EINVAL;
- if (ret < 0)
- return ret;
-
- /* Set up advertisement registers based on current settings */
- ret = amd_xgbe_an_init(phydev);
- if (ret)
- return ret;
-
- /* Enable auto-negotiation interrupts */
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07);
-
- return 0;
-}
-
-static int amd_xgbe_phy_setup_forced(struct phy_device *phydev)
-{
- int ret;
-
- /* Disable auto-negotiation */
- ret = amd_xgbe_phy_disable_an(phydev);
- if (ret < 0)
- return ret;
-
- /* Validate/Set specified speed */
- switch (phydev->speed) {
- case SPEED_10000:
- ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR);
- break;
-
- case SPEED_2500:
- case SPEED_1000:
- ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX);
- break;
-
- default:
- ret = -EINVAL;
- }
-
- if (ret < 0)
- return ret;
-
- /* Validate duplex mode */
- if (phydev->duplex != DUPLEX_FULL)
- return -EINVAL;
-
- phydev->pause = 0;
- phydev->asym_pause = 0;
-
- return 0;
-}
-
-static int __amd_xgbe_phy_config_aneg(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- u32 mmd_mask = phydev->c45_ids.devices_in_package;
- int ret;
-
- if (phydev->autoneg != AUTONEG_ENABLE)
- return amd_xgbe_phy_setup_forced(phydev);
-
- /* Make sure we have the AN MMD present */
- if (!(mmd_mask & MDIO_DEVS_AN))
- return -EINVAL;
-
- /* Disable auto-negotiation interrupt */
- disable_irq(priv->an_irq);
-
- /* Start auto-negotiation in a supported mode */
- if (phydev->advertising & SUPPORTED_10000baseKR_Full)
- ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR);
- else if ((phydev->advertising & SUPPORTED_1000baseKX_Full) ||
- (phydev->advertising & SUPPORTED_2500baseX_Full))
- ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX);
- else
- ret = -EINVAL;
- if (ret < 0) {
- enable_irq(priv->an_irq);
- return ret;
- }
-
- /* Disable and stop any in progress auto-negotiation */
- ret = amd_xgbe_phy_disable_an(phydev);
- if (ret < 0)
- return ret;
-
- /* Clear any auto-negotitation interrupts */
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
-
- priv->an_result = AMD_XGBE_AN_READY;
- priv->an_state = AMD_XGBE_AN_READY;
- priv->kr_state = AMD_XGBE_RX_BPA;
- priv->kx_state = AMD_XGBE_RX_BPA;
-
- /* Re-enable auto-negotiation interrupt */
- enable_irq(priv->an_irq);
-
- /* Set up advertisement registers based on current settings */
- ret = amd_xgbe_an_init(phydev);
- if (ret)
- return ret;
-
- /* Enable and start auto-negotiation */
- return amd_xgbe_phy_restart_an(phydev);
-}
-
-static int amd_xgbe_phy_config_aneg(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- int ret;
-
- mutex_lock(&priv->an_mutex);
-
- ret = __amd_xgbe_phy_config_aneg(phydev);
-
- mutex_unlock(&priv->an_mutex);
-
- return ret;
-}
-
-static int amd_xgbe_phy_aneg_done(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
-
- return (priv->an_result == AMD_XGBE_AN_COMPLETE);
-}
-
-static int amd_xgbe_phy_update_link(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- int ret;
-
- /* If we're doing auto-negotiation don't report link down */
- if (priv->an_state != AMD_XGBE_AN_READY) {
- phydev->link = 1;
- return 0;
- }
-
- /* Link status is latched low, so read once to clear
- * and then read again to get current state
- */
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1);
- if (ret < 0)
- return ret;
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1);
- if (ret < 0)
- return ret;
-
- phydev->link = (ret & MDIO_STAT1_LSTATUS) ? 1 : 0;
-
- return 0;
-}
-
-static int amd_xgbe_phy_read_status(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- u32 mmd_mask = phydev->c45_ids.devices_in_package;
- int ret, ad_ret, lp_ret;
-
- ret = amd_xgbe_phy_update_link(phydev);
- if (ret)
- return ret;
-
- if ((phydev->autoneg == AUTONEG_ENABLE) &&
- !priv->parallel_detect) {
- if (!(mmd_mask & MDIO_DEVS_AN))
- return -EINVAL;
-
- if (!amd_xgbe_phy_aneg_done(phydev))
- return 0;
-
- /* Compare Advertisement and Link Partner register 1 */
- ad_ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
- if (ad_ret < 0)
- return ad_ret;
- lp_ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA);
- if (lp_ret < 0)
- return lp_ret;
-
- ad_ret &= lp_ret;
- phydev->pause = (ad_ret & 0x400) ? 1 : 0;
- phydev->asym_pause = (ad_ret & 0x800) ? 1 : 0;
-
- /* Compare Advertisement and Link Partner register 2 */
- ad_ret = phy_read_mmd(phydev, MDIO_MMD_AN,
- MDIO_AN_ADVERTISE + 1);
- if (ad_ret < 0)
- return ad_ret;
- lp_ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA + 1);
- if (lp_ret < 0)
- return lp_ret;
-
- ad_ret &= lp_ret;
- if (ad_ret & 0x80) {
- phydev->speed = SPEED_10000;
- ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR);
- if (ret)
- return ret;
- } else {
- switch (priv->speed_set) {
- case AMD_XGBE_PHY_SPEEDSET_1000_10000:
- phydev->speed = SPEED_1000;
- break;
-
- case AMD_XGBE_PHY_SPEEDSET_2500_10000:
- phydev->speed = SPEED_2500;
- break;
- }
-
- ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX);
- if (ret)
- return ret;
- }
-
- phydev->duplex = DUPLEX_FULL;
- } else {
- if (amd_xgbe_phy_in_kr_mode(phydev)) {
- phydev->speed = SPEED_10000;
- } else {
- switch (priv->speed_set) {
- case AMD_XGBE_PHY_SPEEDSET_1000_10000:
- phydev->speed = SPEED_1000;
- break;
-
- case AMD_XGBE_PHY_SPEEDSET_2500_10000:
- phydev->speed = SPEED_2500;
- break;
- }
- }
- phydev->duplex = DUPLEX_FULL;
- phydev->pause = 0;
- phydev->asym_pause = 0;
- }
-
- return 0;
-}
-
-static int amd_xgbe_phy_suspend(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- int ret;
-
- mutex_lock(&phydev->lock);
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- goto unlock;
-
- priv->lpm_ctrl = ret;
-
- ret |= MDIO_CTRL1_LPOWER;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
-
- ret = 0;
-
-unlock:
- mutex_unlock(&phydev->lock);
-
- return ret;
-}
-
-static int amd_xgbe_phy_resume(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
-
- mutex_lock(&phydev->lock);
-
- priv->lpm_ctrl &= ~MDIO_CTRL1_LPOWER;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, priv->lpm_ctrl);
-
- mutex_unlock(&phydev->lock);
-
- return 0;
-}
-
-static unsigned int amd_xgbe_phy_resource_count(struct platform_device *pdev,
- unsigned int type)
-{
- unsigned int count;
- int i;
-
- for (i = 0, count = 0; i < pdev->num_resources; i++) {
- struct resource *r = &pdev->resource[i];
-
- if (type == resource_type(r))
- count++;
- }
-
- return count;
-}
-
-static int amd_xgbe_phy_probe(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv;
- struct platform_device *phy_pdev;
- struct device *dev, *phy_dev;
- unsigned int phy_resnum, phy_irqnum;
- int ret;
-
- if (!phydev->bus || !phydev->bus->parent)
- return -EINVAL;
-
- dev = phydev->bus->parent;
-
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->pdev = to_platform_device(dev);
- priv->adev = ACPI_COMPANION(dev);
- priv->dev = dev;
- priv->phydev = phydev;
- mutex_init(&priv->an_mutex);
- INIT_WORK(&priv->an_irq_work, amd_xgbe_an_irq_work);
- INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine);
-
- if (!priv->adev || acpi_disabled) {
- struct device_node *bus_node;
- struct device_node *phy_node;
-
- bus_node = priv->dev->of_node;
- phy_node = of_parse_phandle(bus_node, "phy-handle", 0);
- if (!phy_node) {
- dev_err(dev, "unable to parse phy-handle\n");
- ret = -EINVAL;
- goto err_priv;
- }
-
- phy_pdev = of_find_device_by_node(phy_node);
- of_node_put(phy_node);
-
- if (!phy_pdev) {
- dev_err(dev, "unable to obtain phy device\n");
- ret = -EINVAL;
- goto err_priv;
- }
-
- phy_resnum = 0;
- phy_irqnum = 0;
- } else {
- /* In ACPI, the XGBE and PHY resources are the grouped
- * together with the PHY resources at the end
- */
- phy_pdev = priv->pdev;
- phy_resnum = amd_xgbe_phy_resource_count(phy_pdev,
- IORESOURCE_MEM) - 3;
- phy_irqnum = amd_xgbe_phy_resource_count(phy_pdev,
- IORESOURCE_IRQ) - 1;
- }
- phy_dev = &phy_pdev->dev;
-
- /* Get the device mmio areas */
- priv->rxtx_res = platform_get_resource(phy_pdev, IORESOURCE_MEM,
- phy_resnum++);
- priv->rxtx_regs = devm_ioremap_resource(dev, priv->rxtx_res);
- if (IS_ERR(priv->rxtx_regs)) {
- dev_err(dev, "rxtx ioremap failed\n");
- ret = PTR_ERR(priv->rxtx_regs);
- goto err_put;
- }
-
- priv->sir0_res = platform_get_resource(phy_pdev, IORESOURCE_MEM,
- phy_resnum++);
- priv->sir0_regs = devm_ioremap_resource(dev, priv->sir0_res);
- if (IS_ERR(priv->sir0_regs)) {
- dev_err(dev, "sir0 ioremap failed\n");
- ret = PTR_ERR(priv->sir0_regs);
- goto err_rxtx;
- }
-
- priv->sir1_res = platform_get_resource(phy_pdev, IORESOURCE_MEM,
- phy_resnum++);
- priv->sir1_regs = devm_ioremap_resource(dev, priv->sir1_res);
- if (IS_ERR(priv->sir1_regs)) {
- dev_err(dev, "sir1 ioremap failed\n");
- ret = PTR_ERR(priv->sir1_regs);
- goto err_sir0;
- }
-
- /* Get the auto-negotiation interrupt */
- ret = platform_get_irq(phy_pdev, phy_irqnum);
- if (ret < 0) {
- dev_err(dev, "platform_get_irq failed\n");
- goto err_sir1;
- }
- priv->an_irq = ret;
-
- /* Get the device speed set property */
- ret = device_property_read_u32(phy_dev, XGBE_PHY_SPEEDSET_PROPERTY,
- &priv->speed_set);
- if (ret) {
- dev_err(dev, "invalid %s property\n",
- XGBE_PHY_SPEEDSET_PROPERTY);
- goto err_sir1;
- }
-
- switch (priv->speed_set) {
- case AMD_XGBE_PHY_SPEEDSET_1000_10000:
- case AMD_XGBE_PHY_SPEEDSET_2500_10000:
- break;
- default:
- dev_err(dev, "invalid %s property\n",
- XGBE_PHY_SPEEDSET_PROPERTY);
- ret = -EINVAL;
- goto err_sir1;
- }
-
- if (device_property_present(phy_dev, XGBE_PHY_BLWC_PROPERTY)) {
- ret = device_property_read_u32_array(phy_dev,
- XGBE_PHY_BLWC_PROPERTY,
- priv->serdes_blwc,
- XGBE_PHY_SPEEDS);
- if (ret) {
- dev_err(dev, "invalid %s property\n",
- XGBE_PHY_BLWC_PROPERTY);
- goto err_sir1;
- }
- } else {
- memcpy(priv->serdes_blwc, amd_xgbe_phy_serdes_blwc,
- sizeof(priv->serdes_blwc));
- }
-
- if (device_property_present(phy_dev, XGBE_PHY_CDR_RATE_PROPERTY)) {
- ret = device_property_read_u32_array(phy_dev,
- XGBE_PHY_CDR_RATE_PROPERTY,
- priv->serdes_cdr_rate,
- XGBE_PHY_SPEEDS);
- if (ret) {
- dev_err(dev, "invalid %s property\n",
- XGBE_PHY_CDR_RATE_PROPERTY);
- goto err_sir1;
- }
- } else {
- memcpy(priv->serdes_cdr_rate, amd_xgbe_phy_serdes_cdr_rate,
- sizeof(priv->serdes_cdr_rate));
- }
-
- if (device_property_present(phy_dev, XGBE_PHY_PQ_SKEW_PROPERTY)) {
- ret = device_property_read_u32_array(phy_dev,
- XGBE_PHY_PQ_SKEW_PROPERTY,
- priv->serdes_pq_skew,
- XGBE_PHY_SPEEDS);
- if (ret) {
- dev_err(dev, "invalid %s property\n",
- XGBE_PHY_PQ_SKEW_PROPERTY);
- goto err_sir1;
- }
- } else {
- memcpy(priv->serdes_pq_skew, amd_xgbe_phy_serdes_pq_skew,
- sizeof(priv->serdes_pq_skew));
- }
-
- if (device_property_present(phy_dev, XGBE_PHY_TX_AMP_PROPERTY)) {
- ret = device_property_read_u32_array(phy_dev,
- XGBE_PHY_TX_AMP_PROPERTY,
- priv->serdes_tx_amp,
- XGBE_PHY_SPEEDS);
- if (ret) {
- dev_err(dev, "invalid %s property\n",
- XGBE_PHY_TX_AMP_PROPERTY);
- goto err_sir1;
- }
- } else {
- memcpy(priv->serdes_tx_amp, amd_xgbe_phy_serdes_tx_amp,
- sizeof(priv->serdes_tx_amp));
- }
-
- if (device_property_present(phy_dev, XGBE_PHY_DFE_CFG_PROPERTY)) {
- ret = device_property_read_u32_array(phy_dev,
- XGBE_PHY_DFE_CFG_PROPERTY,
- priv->serdes_dfe_tap_cfg,
- XGBE_PHY_SPEEDS);
- if (ret) {
- dev_err(dev, "invalid %s property\n",
- XGBE_PHY_DFE_CFG_PROPERTY);
- goto err_sir1;
- }
- } else {
- memcpy(priv->serdes_dfe_tap_cfg,
- amd_xgbe_phy_serdes_dfe_tap_cfg,
- sizeof(priv->serdes_dfe_tap_cfg));
- }
-
- if (device_property_present(phy_dev, XGBE_PHY_DFE_ENA_PROPERTY)) {
- ret = device_property_read_u32_array(phy_dev,
- XGBE_PHY_DFE_ENA_PROPERTY,
- priv->serdes_dfe_tap_ena,
- XGBE_PHY_SPEEDS);
- if (ret) {
- dev_err(dev, "invalid %s property\n",
- XGBE_PHY_DFE_ENA_PROPERTY);
- goto err_sir1;
- }
- } else {
- memcpy(priv->serdes_dfe_tap_ena,
- amd_xgbe_phy_serdes_dfe_tap_ena,
- sizeof(priv->serdes_dfe_tap_ena));
- }
-
- /* Initialize supported features */
- phydev->supported = SUPPORTED_Autoneg;
- phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
- phydev->supported |= SUPPORTED_Backplane;
- phydev->supported |= SUPPORTED_10000baseKR_Full;
- switch (priv->speed_set) {
- case AMD_XGBE_PHY_SPEEDSET_1000_10000:
- phydev->supported |= SUPPORTED_1000baseKX_Full;
- break;
- case AMD_XGBE_PHY_SPEEDSET_2500_10000:
- phydev->supported |= SUPPORTED_2500baseX_Full;
- break;
- }
-
- ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_ABILITY);
- if (ret < 0)
- return ret;
- priv->fec_ability = ret & XGBE_PHY_FEC_MASK;
- if (priv->fec_ability & XGBE_PHY_FEC_ENABLE)
- phydev->supported |= SUPPORTED_10000baseR_FEC;
-
- phydev->advertising = phydev->supported;
-
- phydev->priv = priv;
-
- if (!priv->adev || acpi_disabled)
- platform_device_put(phy_pdev);
-
- return 0;
-
-err_sir1:
- devm_iounmap(dev, priv->sir1_regs);
- devm_release_mem_region(dev, priv->sir1_res->start,
- resource_size(priv->sir1_res));
-
-err_sir0:
- devm_iounmap(dev, priv->sir0_regs);
- devm_release_mem_region(dev, priv->sir0_res->start,
- resource_size(priv->sir0_res));
-
-err_rxtx:
- devm_iounmap(dev, priv->rxtx_regs);
- devm_release_mem_region(dev, priv->rxtx_res->start,
- resource_size(priv->rxtx_res));
-
-err_put:
- if (!priv->adev || acpi_disabled)
- platform_device_put(phy_pdev);
-
-err_priv:
- devm_kfree(dev, priv);
-
- return ret;
-}
-
-static void amd_xgbe_phy_remove(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- struct device *dev = priv->dev;
-
- if (priv->an_irq_allocated) {
- devm_free_irq(dev, priv->an_irq, priv);
-
- flush_workqueue(priv->an_workqueue);
- destroy_workqueue(priv->an_workqueue);
- }
-
- /* Release resources */
- devm_iounmap(dev, priv->sir1_regs);
- devm_release_mem_region(dev, priv->sir1_res->start,
- resource_size(priv->sir1_res));
-
- devm_iounmap(dev, priv->sir0_regs);
- devm_release_mem_region(dev, priv->sir0_res->start,
- resource_size(priv->sir0_res));
-
- devm_iounmap(dev, priv->rxtx_regs);
- devm_release_mem_region(dev, priv->rxtx_res->start,
- resource_size(priv->rxtx_res));
-
- devm_kfree(dev, priv);
-}
-
-static int amd_xgbe_match_phy_device(struct phy_device *phydev)
-{
- return phydev->c45_ids.device_ids[MDIO_MMD_PCS] == XGBE_PHY_ID;
-}
-
-static struct phy_driver amd_xgbe_phy_driver[] = {
- {
- .phy_id = XGBE_PHY_ID,
- .phy_id_mask = XGBE_PHY_MASK,
- .name = "AMD XGBE PHY",
- .features = 0,
- .flags = PHY_IS_INTERNAL,
- .probe = amd_xgbe_phy_probe,
- .remove = amd_xgbe_phy_remove,
- .soft_reset = amd_xgbe_phy_soft_reset,
- .config_init = amd_xgbe_phy_config_init,
- .suspend = amd_xgbe_phy_suspend,
- .resume = amd_xgbe_phy_resume,
- .config_aneg = amd_xgbe_phy_config_aneg,
- .aneg_done = amd_xgbe_phy_aneg_done,
- .read_status = amd_xgbe_phy_read_status,
- .match_phy_device = amd_xgbe_match_phy_device,
- .driver = {
- .owner = THIS_MODULE,
- },
- },
-};
-
-module_phy_driver(amd_xgbe_phy_driver);
-
-static struct mdio_device_id __maybe_unused amd_xgbe_phy_ids[] = {
- { XGBE_PHY_ID, XGBE_PHY_MASK },
- { }
-};
-MODULE_DEVICE_TABLE(mdio, amd_xgbe_phy_ids);
diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
index b5dc59de094e..4dea85bfc545 100644
--- a/drivers/net/phy/bcm7xxx.c
+++ b/drivers/net/phy/bcm7xxx.c
@@ -136,8 +136,8 @@ static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
/* AFE_RX_LP_COUNTER, set RX bandwidth to maximum */
phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
- /* AFE_TX_CONFIG, set 1000BT Cfeed=110 for all ports */
- phy_write_misc(phydev, AFE_TX_CONFIG, 0x0061);
+ /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
+ phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
/* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
@@ -167,6 +167,9 @@ static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev)
/* AFE_RXCONFIG_1, provide more margin for INL/DNL measurement */
phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
+ /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
+ phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
+
/* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c
index 0d16c7d9e1bf..2a328703b4ae 100644
--- a/drivers/net/phy/davicom.c
+++ b/drivers/net/phy/davicom.c
@@ -158,6 +158,18 @@ static struct phy_driver dm91xx_driver[] = {
.config_intr = dm9161_config_intr,
.driver = { .owner = THIS_MODULE,},
}, {
+ .phy_id = 0x0181b8b0,
+ .name = "Davicom DM9161B/C",
+ .phy_id_mask = 0x0ffffff0,
+ .features = PHY_BASIC_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = dm9161_config_init,
+ .config_aneg = dm9161_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = dm9161_ack_interrupt,
+ .config_intr = dm9161_config_intr,
+ .driver = { .owner = THIS_MODULE,},
+}, {
.phy_id = 0x0181b8a0,
.name = "Davicom DM9161A",
.phy_id_mask = 0x0ffffff0,
@@ -186,6 +198,7 @@ module_phy_driver(dm91xx_driver);
static struct mdio_device_id __maybe_unused davicom_tbl[] = {
{ 0x0181b880, 0x0ffffff0 },
+ { 0x0181b8b0, 0x0ffffff0 },
{ 0x0181b8a0, 0x0ffffff0 },
{ 0x00181b80, 0x0ffffff0 },
{ }
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
new file mode 100644
index 000000000000..c7a12e2e07b7
--- /dev/null
+++ b/drivers/net/phy/dp83867.c
@@ -0,0 +1,239 @@
+/*
+ * Driver for the Texas Instruments DP83867 PHY
+ *
+ * Copyright (C) 2015 Texas Instruments Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/ethtool.h>
+#include <linux/kernel.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+
+#include <dt-bindings/net/ti-dp83867.h>
+
+#define DP83867_PHY_ID 0x2000a231
+#define DP83867_DEVADDR 0x1f
+
+#define MII_DP83867_PHYCTRL 0x10
+#define MII_DP83867_MICR 0x12
+#define MII_DP83867_ISR 0x13
+#define DP83867_CTRL 0x1f
+
+/* Extended Registers */
+#define DP83867_RGMIICTL 0x0032
+#define DP83867_RGMIIDCTL 0x0086
+
+#define DP83867_SW_RESET BIT(15)
+#define DP83867_SW_RESTART BIT(14)
+
+/* MICR Interrupt bits */
+#define MII_DP83867_MICR_AN_ERR_INT_EN BIT(15)
+#define MII_DP83867_MICR_SPEED_CHNG_INT_EN BIT(14)
+#define MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN BIT(13)
+#define MII_DP83867_MICR_PAGE_RXD_INT_EN BIT(12)
+#define MII_DP83867_MICR_AUTONEG_COMP_INT_EN BIT(11)
+#define MII_DP83867_MICR_LINK_STS_CHNG_INT_EN BIT(10)
+#define MII_DP83867_MICR_FALSE_CARRIER_INT_EN BIT(8)
+#define MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN BIT(4)
+#define MII_DP83867_MICR_WOL_INT_EN BIT(3)
+#define MII_DP83867_MICR_XGMII_ERR_INT_EN BIT(2)
+#define MII_DP83867_MICR_POL_CHNG_INT_EN BIT(1)
+#define MII_DP83867_MICR_JABBER_INT_EN BIT(0)
+
+/* RGMIICTL bits */
+#define DP83867_RGMII_TX_CLK_DELAY_EN BIT(1)
+#define DP83867_RGMII_RX_CLK_DELAY_EN BIT(0)
+
+/* PHY CTRL bits */
+#define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14
+
+/* RGMIIDCTL bits */
+#define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4
+
+struct dp83867_private {
+ int rx_id_delay;
+ int tx_id_delay;
+ int fifo_depth;
+};
+
+static int dp83867_ack_interrupt(struct phy_device *phydev)
+{
+ int err = phy_read(phydev, MII_DP83867_ISR);
+
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int dp83867_config_intr(struct phy_device *phydev)
+{
+ int micr_status;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ micr_status = phy_read(phydev, MII_DP83867_MICR);
+ if (micr_status < 0)
+ return micr_status;
+
+ micr_status |=
+ (MII_DP83867_MICR_AN_ERR_INT_EN |
+ MII_DP83867_MICR_SPEED_CHNG_INT_EN |
+ MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN |
+ MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN);
+
+ return phy_write(phydev, MII_DP83867_MICR, micr_status);
+ }
+
+ micr_status = 0x0;
+ return phy_write(phydev, MII_DP83867_MICR, micr_status);
+}
+
+#ifdef CONFIG_OF_MDIO
+static int dp83867_of_init(struct phy_device *phydev)
+{
+ struct dp83867_private *dp83867 = phydev->priv;
+ struct device *dev = &phydev->dev;
+ struct device_node *of_node = dev->of_node;
+ int ret;
+
+ if (!of_node && dev->parent->of_node)
+ of_node = dev->parent->of_node;
+
+ if (!phydev->dev.of_node)
+ return -ENODEV;
+
+ ret = of_property_read_u32(of_node, "ti,rx-internal-delay",
+ &dp83867->rx_id_delay);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(of_node, "ti,tx-internal-delay",
+ &dp83867->tx_id_delay);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(of_node, "ti,fifo-depth",
+ &dp83867->fifo_depth);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+#else
+static int dp83867_of_init(struct phy_device *phydev)
+{
+ return 0;
+}
+#endif /* CONFIG_OF_MDIO */
+
+static int dp83867_config_init(struct phy_device *phydev)
+{
+ struct dp83867_private *dp83867;
+ int ret;
+ u16 val, delay;
+
+ if (!phydev->priv) {
+ dp83867 = devm_kzalloc(&phydev->dev, sizeof(*dp83867),
+ GFP_KERNEL);
+ if (!dp83867)
+ return -ENOMEM;
+
+ phydev->priv = dp83867;
+ ret = dp83867_of_init(phydev);
+ if (ret)
+ return ret;
+ } else {
+ dp83867 = (struct dp83867_private *)phydev->priv;
+ }
+
+ if (phy_interface_is_rgmii(phydev)) {
+ ret = phy_write(phydev, MII_DP83867_PHYCTRL,
+ (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT));
+ if (ret)
+ return ret;
+ }
+
+ if ((phydev->interface >= PHY_INTERFACE_MODE_RGMII_ID) ||
+ (phydev->interface <= PHY_INTERFACE_MODE_RGMII_RXID)) {
+ val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL,
+ DP83867_DEVADDR, phydev->addr);
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+ val |= (DP83867_RGMII_TX_CLK_DELAY_EN | DP83867_RGMII_RX_CLK_DELAY_EN);
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+ val |= DP83867_RGMII_TX_CLK_DELAY_EN;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+ val |= DP83867_RGMII_RX_CLK_DELAY_EN;
+
+ phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
+ DP83867_DEVADDR, phydev->addr, val);
+
+ delay = (dp83867->rx_id_delay |
+ (dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT));
+
+ phy_write_mmd_indirect(phydev, DP83867_RGMIIDCTL,
+ DP83867_DEVADDR, phydev->addr, delay);
+ }
+
+ return 0;
+}
+
+static int dp83867_phy_reset(struct phy_device *phydev)
+{
+ int err;
+
+ err = phy_write(phydev, DP83867_CTRL, DP83867_SW_RESET);
+ if (err < 0)
+ return err;
+
+ return dp83867_config_init(phydev);
+}
+
+static struct phy_driver dp83867_driver[] = {
+ {
+ .phy_id = DP83867_PHY_ID,
+ .phy_id_mask = 0xfffffff0,
+ .name = "TI DP83867",
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+
+ .config_init = dp83867_config_init,
+ .soft_reset = dp83867_phy_reset,
+
+ /* IRQ related */
+ .ack_interrupt = dp83867_ack_interrupt,
+ .config_intr = dp83867_config_intr,
+
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+
+ .driver = {.owner = THIS_MODULE,}
+ },
+};
+module_phy_driver(dp83867_driver);
+
+static struct mdio_device_id __maybe_unused dp83867_tbl[] = {
+ { DP83867_PHY_ID, 0xfffffff0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, dp83867_tbl);
+
+MODULE_DESCRIPTION("Texas Instruments DP83867 PHY driver");
+MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
index 8644f039d922..0dbc445a5fa0 100644
--- a/drivers/net/phy/icplus.c
+++ b/drivers/net/phy/icplus.c
@@ -139,10 +139,7 @@ static int ip1001_config_init(struct phy_device *phydev)
if (c < 0)
return c;
- if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
- (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
- (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
- (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
+ if (phy_interface_is_rgmii(phydev)) {
c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
if (c < 0)
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 1b1698f98818..f721444c2b0a 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -317,10 +317,7 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
if (err < 0)
return err;
- if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
- (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
- (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
- (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
+ if (phy_interface_is_rgmii(phydev)) {
mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) &
MII_88E1121_PHY_MSCR_DELAY_MASK;
@@ -469,10 +466,7 @@ static int m88e1111_config_init(struct phy_device *phydev)
int err;
int temp;
- if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
- (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
- (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
- (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
+ if (phy_interface_is_rgmii(phydev)) {
temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
if (temp < 0)
diff --git a/drivers/net/phy/mdio-bcm-unimac.c b/drivers/net/phy/mdio-bcm-unimac.c
index 414fdf1f343f..fc7abc50b4f1 100644
--- a/drivers/net/phy/mdio-bcm-unimac.c
+++ b/drivers/net/phy/mdio-bcm-unimac.c
@@ -81,7 +81,13 @@ static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
return -ETIMEDOUT;
cmd = __raw_readl(priv->base + MDIO_CMD);
- if (cmd & MDIO_READ_FAIL)
+
+ /* Some broken devices are known not to release the line during
+ * turn-around, e.g: Broadcom BCM53125 external switches, so check for
+ * that condition here and ignore the MDIO controller read failure
+ * indication.
+ */
+ if (!(bus->phy_ignore_ta_mask & 1 << phy_id) && (cmd & MDIO_READ_FAIL))
return -EIO;
return cmd & 0xffff;
diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
index daec9b05d168..61a543c788cc 100644
--- a/drivers/net/phy/mdio-bitbang.c
+++ b/drivers/net/phy/mdio-bitbang.c
@@ -165,8 +165,11 @@ static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
ctrl->ops->set_mdio_dir(ctrl, 0);
- /* check the turnaround bit: the PHY should be driving it to zero */
- if (mdiobb_get_bit(ctrl) != 0) {
+ /* check the turnaround bit: the PHY should be driving it to zero, if this
+ * PHY is listed in phy_ignore_ta_mask as having broken TA, skip that
+ */
+ if (mdiobb_get_bit(ctrl) != 0 &&
+ !(bus->phy_ignore_ta_mask & (1 << phy))) {
/* PHY didn't drive TA low -- flush any bits it
* may be trying to send.
*/
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 53d18150f4e2..7dc21e56a7aa 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -158,6 +158,7 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
new_bus->name = "GPIO Bitbanged MDIO",
new_bus->phy_mask = pdata->phy_mask;
+ new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask;
new_bus->irq = pdata->irqs;
new_bus->parent = dev;
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index ebdc357c5131..499185eaf413 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -288,9 +288,10 @@ static int kszphy_config_init(struct phy_device *phydev)
}
static int ksz9021_load_values_from_of(struct phy_device *phydev,
- struct device_node *of_node, u16 reg,
- char *field1, char *field2,
- char *field3, char *field4)
+ const struct device_node *of_node,
+ u16 reg,
+ const char *field1, const char *field2,
+ const char *field3, const char *field4)
{
int val1 = -1;
int val2 = -2;
@@ -336,8 +337,8 @@ static int ksz9021_load_values_from_of(struct phy_device *phydev,
static int ksz9021_config_init(struct phy_device *phydev)
{
- struct device *dev = &phydev->dev;
- struct device_node *of_node = dev->of_node;
+ const struct device *dev = &phydev->dev;
+ const struct device_node *of_node = dev->of_node;
if (!of_node && dev->parent->of_node)
of_node = dev->parent->of_node;
@@ -365,6 +366,11 @@ static int ksz9021_config_init(struct phy_device *phydev)
#define KSZ9031_PS_TO_REG 60
/* Extended registers */
+/* MMD Address 0x0 */
+#define MII_KSZ9031RN_FLP_BURST_TX_LO 3
+#define MII_KSZ9031RN_FLP_BURST_TX_HI 4
+
+/* MMD Address 0x2 */
#define MII_KSZ9031RN_CONTROL_PAD_SKEW 4
#define MII_KSZ9031RN_RX_DATA_PAD_SKEW 5
#define MII_KSZ9031RN_TX_DATA_PAD_SKEW 6
@@ -389,9 +395,9 @@ static int ksz9031_extended_read(struct phy_device *phydev,
}
static int ksz9031_of_load_skew_values(struct phy_device *phydev,
- struct device_node *of_node,
+ const struct device_node *of_node,
u16 reg, size_t field_sz,
- char *field[], u8 numfields)
+ const char *field[], u8 numfields)
{
int val[4] = {-1, -2, -3, -4};
int matches = 0;
@@ -425,20 +431,36 @@ static int ksz9031_of_load_skew_values(struct phy_device *phydev,
return ksz9031_extended_write(phydev, OP_DATA, 2, reg, newval);
}
+static int ksz9031_center_flp_timing(struct phy_device *phydev)
+{
+ int result;
+
+ /* Center KSZ9031RNX FLP timing at 16ms. */
+ result = ksz9031_extended_write(phydev, OP_DATA, 0,
+ MII_KSZ9031RN_FLP_BURST_TX_HI, 0x0006);
+ result = ksz9031_extended_write(phydev, OP_DATA, 0,
+ MII_KSZ9031RN_FLP_BURST_TX_LO, 0x1A80);
+
+ if (result)
+ return result;
+
+ return genphy_restart_aneg(phydev);
+}
+
static int ksz9031_config_init(struct phy_device *phydev)
{
- struct device *dev = &phydev->dev;
- struct device_node *of_node = dev->of_node;
- char *clk_skews[2] = {"rxc-skew-ps", "txc-skew-ps"};
- char *rx_data_skews[4] = {
+ const struct device *dev = &phydev->dev;
+ const struct device_node *of_node = dev->of_node;
+ static const char *clk_skews[2] = {"rxc-skew-ps", "txc-skew-ps"};
+ static const char *rx_data_skews[4] = {
"rxd0-skew-ps", "rxd1-skew-ps",
"rxd2-skew-ps", "rxd3-skew-ps"
};
- char *tx_data_skews[4] = {
+ static const char *tx_data_skews[4] = {
"txd0-skew-ps", "txd1-skew-ps",
"txd2-skew-ps", "txd3-skew-ps"
};
- char *control_skews[2] = {"txen-skew-ps", "rxdv-skew-ps"};
+ static const char *control_skews[2] = {"txen-skew-ps", "rxdv-skew-ps"};
if (!of_node && dev->parent->of_node)
of_node = dev->parent->of_node;
@@ -460,7 +482,8 @@ static int ksz9031_config_init(struct phy_device *phydev)
MII_KSZ9031RN_TX_DATA_PAD_SKEW, 4,
tx_data_skews, 4);
}
- return 0;
+
+ return ksz9031_center_flp_timing(phydev);
}
#define KSZ8873MLL_GLOBAL_CONTROL_4 0x06
@@ -519,7 +542,7 @@ ksz9021_wr_mmd_phyreg(struct phy_device *phydev, int ptrad, int devnum,
static int kszphy_probe(struct phy_device *phydev)
{
const struct kszphy_type *type = phydev->drv->driver_data;
- struct device_node *np = phydev->dev.of_node;
+ const struct device_node *np = phydev->dev.of_node;
struct kszphy_priv *priv;
struct clk *clk;
int ret;
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 47cd578052fc..b2197b506acb 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -58,6 +58,31 @@ static const char *phy_speed_to_str(int speed)
}
}
+#define PHY_STATE_STR(_state) \
+ case PHY_##_state: \
+ return __stringify(_state); \
+
+static const char *phy_state_to_str(enum phy_state st)
+{
+ switch (st) {
+ PHY_STATE_STR(DOWN)
+ PHY_STATE_STR(STARTING)
+ PHY_STATE_STR(READY)
+ PHY_STATE_STR(PENDING)
+ PHY_STATE_STR(UP)
+ PHY_STATE_STR(AN)
+ PHY_STATE_STR(RUNNING)
+ PHY_STATE_STR(NOLINK)
+ PHY_STATE_STR(FORCING)
+ PHY_STATE_STR(CHANGELINK)
+ PHY_STATE_STR(HALTED)
+ PHY_STATE_STR(RESUMING)
+ }
+
+ return NULL;
+}
+
+
/**
* phy_print_status - Convenience function to print out the current phy status
* @phydev: the phy_device struct
@@ -784,10 +809,13 @@ void phy_state_machine(struct work_struct *work)
struct phy_device *phydev =
container_of(dwork, struct phy_device, state_queue);
bool needs_aneg = false, do_suspend = false;
+ enum phy_state old_state;
int err = 0;
mutex_lock(&phydev->lock);
+ old_state = phydev->state;
+
if (phydev->drv->link_change_notify)
phydev->drv->link_change_notify(phydev);
@@ -952,6 +980,9 @@ void phy_state_machine(struct work_struct *work)
if (err < 0)
phy_error(phydev);
+ dev_dbg(&phydev->dev, "PHY state change %s -> %s\n",
+ phy_state_to_str(old_state), phy_state_to_str(phydev->state));
+
queue_delayed_work(system_power_efficient_wq, &phydev->state_queue,
PHY_STATE_TIME * HZ);
}
@@ -1062,8 +1093,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
if ((phydev->duplex == DUPLEX_FULL) &&
((phydev->interface == PHY_INTERFACE_MODE_MII) ||
(phydev->interface == PHY_INTERFACE_MODE_GMII) ||
- (phydev->interface >= PHY_INTERFACE_MODE_RGMII &&
- phydev->interface <= PHY_INTERFACE_MODE_RGMII_TXID) ||
+ phy_interface_is_rgmii(phydev) ||
phy_is_internal(phydev))) {
int eee_lp, eee_cap, eee_adv;
u32 lp, cap, adv;
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 96a0f0fab3ca..45353613b2ed 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -22,8 +22,12 @@
#define RTL821x_INER 0x12
#define RTL821x_INER_INIT 0x6400
#define RTL821x_INSR 0x13
+#define RTL8211E_INER_LINK_STATUS 0x400
-#define RTL8211E_INER_LINK_STATUS 0x400
+#define RTL8211F_INER_LINK_STATUS 0x0010
+#define RTL8211F_INSR 0x1d
+#define RTL8211F_PAGE_SELECT 0x1f
+#define RTL8211F_TX_DELAY 0x100
MODULE_DESCRIPTION("Realtek PHY driver");
MODULE_AUTHOR("Johnson Leung");
@@ -38,6 +42,18 @@ static int rtl821x_ack_interrupt(struct phy_device *phydev)
return (err < 0) ? err : 0;
}
+static int rtl8211f_ack_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ phy_write(phydev, RTL8211F_PAGE_SELECT, 0xa43);
+ err = phy_read(phydev, RTL8211F_INSR);
+ /* restore to default page 0 */
+ phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);
+
+ return (err < 0) ? err : 0;
+}
+
static int rtl8211b_config_intr(struct phy_device *phydev)
{
int err;
@@ -64,6 +80,41 @@ static int rtl8211e_config_intr(struct phy_device *phydev)
return err;
}
+static int rtl8211f_config_intr(struct phy_device *phydev)
+{
+ int err;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ err = phy_write(phydev, RTL821x_INER,
+ RTL8211F_INER_LINK_STATUS);
+ else
+ err = phy_write(phydev, RTL821x_INER, 0);
+
+ return err;
+}
+
+static int rtl8211f_config_init(struct phy_device *phydev)
+{
+ int ret;
+ u16 reg;
+
+ ret = genphy_config_init(phydev);
+ if (ret < 0)
+ return ret;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
+ /* enable TXDLY */
+ phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08);
+ reg = phy_read(phydev, 0x11);
+ reg |= RTL8211F_TX_DELAY;
+ phy_write(phydev, 0x11, reg);
+ /* restore to default page 0 */
+ phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);
+ }
+
+ return 0;
+}
+
static struct phy_driver realtek_drvs[] = {
{
.phy_id = 0x00008201,
@@ -98,6 +149,20 @@ static struct phy_driver realtek_drvs[] = {
.suspend = genphy_suspend,
.resume = genphy_resume,
.driver = { .owner = THIS_MODULE,},
+ }, {
+ .phy_id = 0x001cc916,
+ .name = "RTL8211F Gigabit Ethernet",
+ .phy_id_mask = 0x001fffff,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &genphy_config_aneg,
+ .config_init = &rtl8211f_config_init,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &rtl8211f_ack_interrupt,
+ .config_intr = &rtl8211f_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .driver = { .owner = THIS_MODULE },
},
};
@@ -106,6 +171,7 @@ module_phy_driver(realtek_drvs);
static struct mdio_device_id __maybe_unused realtek_tbl[] = {
{ 0x001cc912, 0x001fffff },
{ 0x001cc915, 0x001fffff },
+ { 0x001cc916, 0x001fffff },
{ }
};
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index b62a5e3a1c65..3837ae344f63 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -550,11 +550,11 @@ static struct proto pppoe_sk_proto __read_mostly = {
* Initialize a new struct sock.
*
**********************************************************************/
-static int pppoe_create(struct net *net, struct socket *sock)
+static int pppoe_create(struct net *net, struct socket *sock, int kern)
{
struct sock *sk;
- sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto);
+ sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto, kern);
if (!sk)
return -ENOMEM;
diff --git a/drivers/net/ppp/pppox.c b/drivers/net/ppp/pppox.c
index 2940e9fe351b..0e1b30622477 100644
--- a/drivers/net/ppp/pppox.c
+++ b/drivers/net/ppp/pppox.c
@@ -118,7 +118,7 @@ static int pppox_create(struct net *net, struct socket *sock, int protocol,
!try_module_get(pppox_protos[protocol]->owner))
goto out;
- rc = pppox_protos[protocol]->create(net, sock);
+ rc = pppox_protos[protocol]->create(net, sock, kern);
module_put(pppox_protos[protocol]->owner);
out:
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index e3bfbd4d0136..686f37daa262 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -28,8 +28,6 @@
#include <linux/file.h>
#include <linux/in.h>
#include <linux/ip.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
#include <linux/rcupdate.h>
#include <linux/spinlock.h>
@@ -561,14 +559,14 @@ static void pptp_sock_destruct(struct sock *sk)
skb_queue_purge(&sk->sk_receive_queue);
}
-static int pptp_create(struct net *net, struct socket *sock)
+static int pptp_create(struct net *net, struct socket *sock, int kern)
{
int error = -ENOMEM;
struct sock *sk;
struct pppox_sock *po;
struct pptp_opt *opt;
- sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pptp_sk_proto);
+ sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pptp_sk_proto, kern);
if (!sk)
goto out;
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 6928448f6b7f..daa054b3ff03 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1924,7 +1924,7 @@ static netdev_features_t team_fix_features(struct net_device *dev,
struct team *team = netdev_priv(dev);
netdev_features_t mask;
- mask = features | NETIF_F_HW_SWITCH_OFFLOAD;
+ mask = features;
features &= ~NETIF_F_ONE_FOR_ALL;
features |= NETIF_F_ALL_FOR_ALL;
@@ -1977,8 +1977,12 @@ static const struct net_device_ops team_netdev_ops = {
.ndo_del_slave = team_del_slave,
.ndo_fix_features = team_fix_features,
.ndo_change_carrier = team_change_carrier,
- .ndo_bridge_setlink = ndo_dflt_netdev_switch_port_bridge_setlink,
- .ndo_bridge_dellink = ndo_dflt_netdev_switch_port_bridge_dellink,
+ .ndo_bridge_setlink = switchdev_port_bridge_setlink,
+ .ndo_bridge_getlink = switchdev_port_bridge_getlink,
+ .ndo_bridge_dellink = switchdev_port_bridge_dellink,
+ .ndo_fdb_add = switchdev_port_fdb_add,
+ .ndo_fdb_del = switchdev_port_fdb_del,
+ .ndo_fdb_dump = switchdev_port_fdb_dump,
.ndo_features_check = passthru_features_check,
};
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index e470ae59d405..1a1c4f7b3ec5 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -146,7 +146,6 @@ struct tun_file {
struct socket socket;
struct socket_wq wq;
struct tun_struct __rcu *tun;
- struct net *net;
struct fasync_struct *fasync;
/* only used for fasnyc */
unsigned int flags;
@@ -493,10 +492,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
tun->dev->reg_state == NETREG_REGISTERED)
unregister_netdevice(tun->dev);
}
-
- BUG_ON(!test_bit(SOCK_EXTERNALLY_ALLOCATED,
- &tfile->socket.flags));
- sk_release_kernel(&tfile->sk);
+ sock_put(&tfile->sk);
}
}
@@ -1492,18 +1488,10 @@ out:
return ret;
}
-static int tun_release(struct socket *sock)
-{
- if (sock->sk)
- sock_put(sock->sk);
- return 0;
-}
-
/* Ops structure to mimic raw sockets with tun */
static const struct proto_ops tun_socket_ops = {
.sendmsg = tun_sendmsg,
.recvmsg = tun_recvmsg,
- .release = tun_release,
};
static struct proto tun_proto = {
@@ -1865,7 +1853,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
if (cmd == TUNSETIFF && !tun) {
ifr.ifr_name[IFNAMSIZ-1] = '\0';
- ret = tun_set_iff(tfile->net, file, &ifr);
+ ret = tun_set_iff(sock_net(&tfile->sk), file, &ifr);
if (ret)
goto unlock;
@@ -2154,16 +2142,16 @@ out:
static int tun_chr_open(struct inode *inode, struct file * file)
{
+ struct net *net = current->nsproxy->net_ns;
struct tun_file *tfile;
DBG1(KERN_INFO, "tunX: tun_chr_open\n");
- tfile = (struct tun_file *)sk_alloc(&init_net, AF_UNSPEC, GFP_KERNEL,
- &tun_proto);
+ tfile = (struct tun_file *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL,
+ &tun_proto, 0);
if (!tfile)
return -ENOMEM;
RCU_INIT_POINTER(tfile->tun, NULL);
- tfile->net = get_net(current->nsproxy->net_ns);
tfile->flags = 0;
tfile->ifindex = 0;
@@ -2174,13 +2162,11 @@ static int tun_chr_open(struct inode *inode, struct file * file)
tfile->socket.ops = &tun_socket_ops;
sock_init_data(&tfile->socket, &tfile->sk);
- sk_change_net(&tfile->sk, tfile->net);
tfile->sk.sk_write_space = tun_sock_write_space;
tfile->sk.sk_sndbuf = INT_MAX;
file->private_data = tfile;
- set_bit(SOCK_EXTERNALLY_ALLOCATED, &tfile->socket.flags);
INIT_LIST_HEAD(&tfile->next);
sock_set_flag(&tfile->sk, SOCK_ZEROCOPY);
@@ -2191,10 +2177,8 @@ static int tun_chr_open(struct inode *inode, struct file * file)
static int tun_chr_close(struct inode *inode, struct file *file)
{
struct tun_file *tfile = file->private_data;
- struct net *net = tfile->net;
tun_detach(tfile, true);
- put_net(net);
return 0;
}
diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h
index 3718d024f638..221a53025fd0 100644
--- a/drivers/net/vmxnet3/vmxnet3_defs.h
+++ b/drivers/net/vmxnet3/vmxnet3_defs.h
@@ -1,7 +1,7 @@
/*
* Linux driver for VMware's vmxnet3 ethernet NIC.
*
- * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
+ * Copyright (C) 2008-2015, VMware, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -277,6 +277,40 @@ struct Vmxnet3_RxCompDesc {
#endif /* __BIG_ENDIAN_BITFIELD */
};
+struct Vmxnet3_RxCompDescExt {
+ __le32 dword1;
+ u8 segCnt; /* Number of aggregated packets */
+ u8 dupAckCnt; /* Number of duplicate Acks */
+ __le16 tsDelta; /* TCP timestamp difference */
+ __le32 dword2;
+#ifdef __BIG_ENDIAN_BITFIELD
+ u32 gen:1; /* generation bit */
+ u32 type:7; /* completion type */
+ u32 fcs:1; /* Frame CRC correct */
+ u32 frg:1; /* IP Fragment */
+ u32 v4:1; /* IPv4 */
+ u32 v6:1; /* IPv6 */
+ u32 ipc:1; /* IP Checksum Correct */
+ u32 tcp:1; /* TCP packet */
+ u32 udp:1; /* UDP packet */
+ u32 tuc:1; /* TCP/UDP Checksum Correct */
+ u32 mss:16;
+#else
+ u32 mss:16;
+ u32 tuc:1; /* TCP/UDP Checksum Correct */
+ u32 udp:1; /* UDP packet */
+ u32 tcp:1; /* TCP packet */
+ u32 ipc:1; /* IP Checksum Correct */
+ u32 v6:1; /* IPv6 */
+ u32 v4:1; /* IPv4 */
+ u32 frg:1; /* IP Fragment */
+ u32 fcs:1; /* Frame CRC correct */
+ u32 type:7; /* completion type */
+ u32 gen:1; /* generation bit */
+#endif /* __BIG_ENDIAN_BITFIELD */
+};
+
+
/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.dword[3] */
#define VMXNET3_RCD_TUC_SHIFT 16
#define VMXNET3_RCD_IPC_SHIFT 19
@@ -310,6 +344,7 @@ union Vmxnet3_GenericDesc {
struct Vmxnet3_RxDesc rxd;
struct Vmxnet3_TxCompDesc tcd;
struct Vmxnet3_RxCompDesc rcd;
+ struct Vmxnet3_RxCompDescExt rcdExt;
};
#define VMXNET3_INIT_GEN 1
@@ -361,6 +396,7 @@ enum {
/* completion descriptor types */
#define VMXNET3_CDTYPE_TXCOMP 0 /* Tx Completion Descriptor */
#define VMXNET3_CDTYPE_RXCOMP 3 /* Rx Completion Descriptor */
+#define VMXNET3_CDTYPE_RXCOMP_LRO 4 /* Rx Completion Descriptor for LRO */
enum {
VMXNET3_GOS_BITS_UNK = 0, /* unknown */
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 61c0840c448c..da11bb5e9c7f 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -861,6 +861,9 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
, skb_headlen(skb));
}
+ if (skb->len <= VMXNET3_HDR_COPY_SIZE)
+ ctx->copy_size = skb->len;
+
/* make sure headers are accessible directly */
if (unlikely(!pskb_may_pull(skb, ctx->copy_size)))
goto err;
@@ -1160,6 +1163,52 @@ vmxnet3_rx_error(struct vmxnet3_rx_queue *rq, struct Vmxnet3_RxCompDesc *rcd,
}
+static u32
+vmxnet3_get_hdr_len(struct vmxnet3_adapter *adapter, struct sk_buff *skb,
+ union Vmxnet3_GenericDesc *gdesc)
+{
+ u32 hlen, maplen;
+ union {
+ void *ptr;
+ struct ethhdr *eth;
+ struct iphdr *ipv4;
+ struct ipv6hdr *ipv6;
+ struct tcphdr *tcp;
+ } hdr;
+ BUG_ON(gdesc->rcd.tcp == 0);
+
+ maplen = skb_headlen(skb);
+ if (unlikely(sizeof(struct iphdr) + sizeof(struct tcphdr) > maplen))
+ return 0;
+
+ hdr.eth = eth_hdr(skb);
+ if (gdesc->rcd.v4) {
+ BUG_ON(hdr.eth->h_proto != htons(ETH_P_IP));
+ hdr.ptr += sizeof(struct ethhdr);
+ BUG_ON(hdr.ipv4->protocol != IPPROTO_TCP);
+ hlen = hdr.ipv4->ihl << 2;
+ hdr.ptr += hdr.ipv4->ihl << 2;
+ } else if (gdesc->rcd.v6) {
+ BUG_ON(hdr.eth->h_proto != htons(ETH_P_IPV6));
+ hdr.ptr += sizeof(struct ethhdr);
+ /* Use an estimated value, since we also need to handle
+ * TSO case.
+ */
+ if (hdr.ipv6->nexthdr != IPPROTO_TCP)
+ return sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
+ hlen = sizeof(struct ipv6hdr);
+ hdr.ptr += sizeof(struct ipv6hdr);
+ } else {
+ /* Non-IP pkt, dont estimate header length */
+ return 0;
+ }
+
+ if (hlen + sizeof(struct tcphdr) > maplen)
+ return 0;
+
+ return (hlen + (hdr.tcp->doff << 2));
+}
+
static int
vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
struct vmxnet3_adapter *adapter, int quota)
@@ -1171,6 +1220,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
bool skip_page_frags = false;
struct Vmxnet3_RxCompDesc *rcd;
struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx;
+ u16 segCnt = 0, mss = 0;
#ifdef __BIG_ENDIAN_BITFIELD
struct Vmxnet3_RxDesc rxCmdDesc;
struct Vmxnet3_RxCompDesc rxComp;
@@ -1259,7 +1309,19 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
PCI_DMA_FROMDEVICE);
rxd->addr = cpu_to_le64(rbi->dma_addr);
rxd->len = rbi->len;
-
+ if (adapter->version == 2 &&
+ rcd->type == VMXNET3_CDTYPE_RXCOMP_LRO) {
+ struct Vmxnet3_RxCompDescExt *rcdlro;
+ rcdlro = (struct Vmxnet3_RxCompDescExt *)rcd;
+
+ segCnt = rcdlro->segCnt;
+ BUG_ON(segCnt <= 1);
+ mss = rcdlro->mss;
+ if (unlikely(segCnt <= 1))
+ segCnt = 0;
+ } else {
+ segCnt = 0;
+ }
} else {
BUG_ON(ctx->skb == NULL && !skip_page_frags);
@@ -1273,47 +1335,75 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
if (skip_page_frags)
goto rcd_done;
- new_page = alloc_page(GFP_ATOMIC);
- if (unlikely(new_page == NULL)) {
+ if (rcd->len) {
+ new_page = alloc_page(GFP_ATOMIC);
/* Replacement page frag could not be allocated.
* Reuse this page. Drop the pkt and free the
* skb which contained this page as a frag. Skip
* processing all the following non-sop frags.
*/
- rq->stats.rx_buf_alloc_failure++;
- dev_kfree_skb(ctx->skb);
- ctx->skb = NULL;
- skip_page_frags = true;
- goto rcd_done;
- }
+ if (unlikely(!new_page)) {
+ rq->stats.rx_buf_alloc_failure++;
+ dev_kfree_skb(ctx->skb);
+ ctx->skb = NULL;
+ skip_page_frags = true;
+ goto rcd_done;
+ }
- if (rcd->len) {
dma_unmap_page(&adapter->pdev->dev,
rbi->dma_addr, rbi->len,
PCI_DMA_FROMDEVICE);
vmxnet3_append_frag(ctx->skb, rcd, rbi);
- }
- /* Immediate refill */
- rbi->page = new_page;
- rbi->dma_addr = dma_map_page(&adapter->pdev->dev,
- rbi->page,
- 0, PAGE_SIZE,
- PCI_DMA_FROMDEVICE);
- rxd->addr = cpu_to_le64(rbi->dma_addr);
- rxd->len = rbi->len;
+ /* Immediate refill */
+ rbi->page = new_page;
+ rbi->dma_addr = dma_map_page(&adapter->pdev->dev
+ , rbi->page,
+ 0, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ rxd->addr = cpu_to_le64(rbi->dma_addr);
+ rxd->len = rbi->len;
+ }
}
skb = ctx->skb;
if (rcd->eop) {
+ u32 mtu = adapter->netdev->mtu;
skb->len += skb->data_len;
vmxnet3_rx_csum(adapter, skb,
(union Vmxnet3_GenericDesc *)rcd);
skb->protocol = eth_type_trans(skb, adapter->netdev);
-
+ if (!rcd->tcp || !adapter->lro)
+ goto not_lro;
+
+ if (segCnt != 0 && mss != 0) {
+ skb_shinfo(skb)->gso_type = rcd->v4 ?
+ SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
+ skb_shinfo(skb)->gso_size = mss;
+ skb_shinfo(skb)->gso_segs = segCnt;
+ } else if (segCnt != 0 || skb->len > mtu) {
+ u32 hlen;
+
+ hlen = vmxnet3_get_hdr_len(adapter, skb,
+ (union Vmxnet3_GenericDesc *)rcd);
+ if (hlen == 0)
+ goto not_lro;
+
+ skb_shinfo(skb)->gso_type =
+ rcd->v4 ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
+ if (segCnt != 0) {
+ skb_shinfo(skb)->gso_segs = segCnt;
+ skb_shinfo(skb)->gso_size =
+ DIV_ROUND_UP(skb->len -
+ hlen, segCnt);
+ } else {
+ skb_shinfo(skb)->gso_size = mtu - hlen;
+ }
+ }
+not_lro:
if (unlikely(rcd->ts))
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rcd->tci);
@@ -3038,14 +3128,19 @@ vmxnet3_probe_device(struct pci_dev *pdev,
goto err_alloc_pci;
ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_VRRS);
- if (ver & 1) {
+ if (ver & 2) {
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 2);
+ adapter->version = 2;
+ } else if (ver & 1) {
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 1);
+ adapter->version = 1;
} else {
dev_err(&pdev->dev,
"Incompatible h/w version (0x%x) for adapter\n", ver);
err = -EBUSY;
goto err_ver;
}
+ dev_dbg(&pdev->dev, "Using device version %d\n", adapter->version);
ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_UVRS);
if (ver & 1) {
@@ -3184,6 +3279,32 @@ vmxnet3_remove_device(struct pci_dev *pdev)
free_netdev(netdev);
}
+static void vmxnet3_shutdown_device(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ unsigned long flags;
+
+ /* Reset_work may be in the middle of resetting the device, wait for its
+ * completion.
+ */
+ while (test_and_set_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state))
+ msleep(1);
+
+ if (test_and_set_bit(VMXNET3_STATE_BIT_QUIESCED,
+ &adapter->state)) {
+ clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
+ return;
+ }
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_QUIESCE_DEV);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+ vmxnet3_disable_all_intrs(adapter);
+
+ clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
+}
+
#ifdef CONFIG_PM
@@ -3360,6 +3481,7 @@ static struct pci_driver vmxnet3_driver = {
.id_table = vmxnet3_pciid_table,
.probe = vmxnet3_probe_device,
.remove = vmxnet3_remove_device,
+ .shutdown = vmxnet3_shutdown_device,
#ifdef CONFIG_PM
.driver.pm = &vmxnet3_pm_ops,
#endif
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index 6bb769ae7de9..e9f1075f7d4c 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -328,6 +328,10 @@ struct vmxnet3_adapter {
u8 __iomem *hw_addr0; /* for BAR 0 */
u8 __iomem *hw_addr1; /* for BAR 1 */
+ u8 version;
+
+ bool rxcsum;
+ bool lro;
#ifdef VMXNET3_RSS
struct UPT1_RSSConf *rss_conf;
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 21a0fbf1ed94..34c519eb1db5 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -336,7 +336,7 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan,
if (!net_eq(dev_net(vxlan->dev), vxlan->net) &&
nla_put_s32(skb, NDA_LINK_NETNSID,
- peernet2id(dev_net(vxlan->dev), vxlan->net)))
+ peernet2id_alloc(dev_net(vxlan->dev), vxlan->net)))
goto nla_put_failure;
if (send_eth && nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->eth_addr))
@@ -1921,6 +1921,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
memset(&fl4, 0, sizeof(fl4));
fl4.flowi4_oif = rdst->remote_ifindex;
fl4.flowi4_tos = RT_TOS(tos);
+ fl4.flowi4_mark = skb->mark;
+ fl4.flowi4_proto = IPPROTO_UDP;
fl4.daddr = dst->sin.sin_addr.s_addr;
fl4.saddr = vxlan->saddr.sin.sin_addr.s_addr;
@@ -1981,6 +1983,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
fl6.flowi6_oif = rdst->remote_ifindex;
fl6.daddr = dst->sin6.sin6_addr;
fl6.saddr = vxlan->saddr.sin6.sin6_addr;
+ fl6.flowi6_mark = skb->mark;
fl6.flowi6_proto = IPPROTO_UDP;
if (ipv6_stub->ipv6_dst_lookup(sk, &ndst, &fl6)) {
@@ -2128,9 +2131,10 @@ static void vxlan_cleanup(unsigned long arg)
if (!netif_running(vxlan->dev))
return;
- spin_lock_bh(&vxlan->hash_lock);
for (h = 0; h < FDB_HASH_SIZE; ++h) {
struct hlist_node *p, *n;
+
+ spin_lock_bh(&vxlan->hash_lock);
hlist_for_each_safe(p, n, &vxlan->fdb_head[h]) {
struct vxlan_fdb *f
= container_of(p, struct vxlan_fdb, hlist);
@@ -2149,8 +2153,8 @@ static void vxlan_cleanup(unsigned long arg)
} else if (time_before(timeout, next_timer))
next_timer = timeout;
}
+ spin_unlock_bh(&vxlan->hash_lock);
}
- spin_unlock_bh(&vxlan->hash_lock);
mod_timer(&vxlan->age_timer, next_timer);
}
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index bcfa01add7cc..7193b7304fdd 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -517,7 +517,7 @@ static int cosa_probe(int base, int irq, int dma)
*/
set_current_state(TASK_INTERRUPTIBLE);
cosa_putstatus(cosa, SR_TX_INT_ENA);
- schedule_timeout(30);
+ schedule_timeout(msecs_to_jiffies(300));
irq = probe_irq_off(irqs);
/* Disable all IRQs from the card */
cosa_putstatus(cosa, 0);
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 08223569cebd..7a72407208b1 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -551,7 +551,7 @@ static int dscc4_wait_ack_cec(struct dscc4_dev_priv *dpriv,
msg, i);
goto done;
}
- schedule_timeout_uninterruptible(10);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(100));
rmb();
} while (++i > 0);
netdev_err(dev, "%s timeout\n", msg);
@@ -596,7 +596,7 @@ static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv)
(dpriv->iqtx[cur] & cpu_to_le32(Xpr)))
break;
smp_rmb();
- schedule_timeout_uninterruptible(10);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(100));
} while (++i > 0);
return (i >= 0 ) ? i : -EAGAIN;
@@ -1033,7 +1033,7 @@ static void dscc4_pci_reset(struct pci_dev *pdev, void __iomem *ioaddr)
/* Flush posted writes */
readl(ioaddr + GSTAR);
- schedule_timeout_uninterruptible(10);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(100));
for (i = 0; i < 16; i++)
pci_write_config_dword(pdev, i << 2, dscc4_pci_config_store[i]);
@@ -1046,7 +1046,6 @@ static void dscc4_pci_reset(struct pci_dev *pdev, void __iomem *ioaddr)
static int dscc4_open(struct net_device *dev)
{
struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
- struct dscc4_pci_priv *ppriv;
int ret = -EAGAIN;
if ((dscc4_loopback_check(dpriv) < 0))
@@ -1055,8 +1054,6 @@ static int dscc4_open(struct net_device *dev)
if ((ret = hdlc_open(dev)))
goto err;
- ppriv = dpriv->pci_priv;
-
/*
* Due to various bugs, there is no way to reliably reset a
* specific port (manufacturer's dependent special PCI #RST wiring
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index 2f5eda8a7227..6676607164d6 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -40,7 +40,6 @@
#include <linux/interrupt.h>
#include <linux/notifier.h>
#include <linux/stat.h>
-#include <linux/netfilter.h>
#include <linux/module.h>
#include <linux/lapb.h>
#include <linux/init.h>
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 16604bdf5197..a63ab2e83105 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -277,6 +277,7 @@ source "drivers/net/wireless/libertas/Kconfig"
source "drivers/net/wireless/orinoco/Kconfig"
source "drivers/net/wireless/p54/Kconfig"
source "drivers/net/wireless/rt2x00/Kconfig"
+source "drivers/net/wireless/mediatek/Kconfig"
source "drivers/net/wireless/rtlwifi/Kconfig"
source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 0c8891686718..6b9e729dd8ac 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -45,6 +45,8 @@ obj-$(CONFIG_IWLWIFI) += iwlwifi/
obj-$(CONFIG_IWLEGACY) += iwlegacy/
obj-$(CONFIG_RT2X00) += rt2x00/
+obj-$(CONFIG_WL_MEDIATEK) += mediatek/
+
obj-$(CONFIG_P54_COMMON) += p54/
obj-$(CONFIG_ATH_CARDS) += ath/
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index f07a61899545..15f057ed41ad 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -1098,14 +1098,18 @@ static void adm8211_hw_init(struct ieee80211_hw *dev)
pci_read_config_byte(priv->pdev, PCI_CACHE_LINE_SIZE, &cline);
switch (cline) {
- case 0x8: reg |= (0x1 << 14);
- break;
- case 0x16: reg |= (0x2 << 14);
- break;
- case 0x32: reg |= (0x3 << 14);
- break;
- default: reg |= (0x0 << 14);
- break;
+ case 0x8:
+ reg |= (0x1 << 14);
+ break;
+ case 0x10:
+ reg |= (0x2 << 14);
+ break;
+ case 0x20:
+ reg |= (0x3 << 14);
+ break;
+ default:
+ reg |= (0x0 << 14);
+ break;
}
}
@@ -1353,12 +1357,7 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev,
new_flags = 0;
- if (*total_flags & FIF_PROMISC_IN_BSS) {
- new_flags |= FIF_PROMISC_IN_BSS;
- priv->nar |= ADM8211_NAR_PR;
- priv->nar &= ~ADM8211_NAR_MM;
- mc_filter[1] = mc_filter[0] = ~0;
- } else if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) {
+ if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) {
new_flags |= FIF_ALLMULTI;
priv->nar &= ~ADM8211_NAR_PR;
priv->nar |= ADM8211_NAR_MM;
@@ -1374,9 +1373,9 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev,
ADM8211_CSR_READ(NAR);
if (priv->nar & ADM8211_NAR_PR)
- dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
+ ieee80211_hw_set(dev, RX_INCLUDES_FCS);
else
- dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
+ __clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, dev->flags);
if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
adm8211_set_bssid(dev, bcast);
@@ -1862,8 +1861,8 @@ static int adm8211_probe(struct pci_dev *pdev,
SET_IEEE80211_PERM_ADDR(dev, perm_addr);
dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
- /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
- dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
+ /* dev->flags = RX_INCLUDES_FCS in promisc mode */
+ ieee80211_hw_set(dev, SIGNAL_UNSPEC);
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
dev->max_signal = 100; /* FIXME: find better value */
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 49219c508963..dab25136214a 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -2360,8 +2360,8 @@ static int at76_init_new_device(struct at76_priv *priv,
priv->hw->wiphy->max_scan_ie_len = 0;
priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &at76_supported_band;
- priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_UNSPEC;
+ ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(priv->hw, SIGNAL_UNSPEC);
priv->hw->max_signal = 100;
SET_IEEE80211_DEV(priv->hw, &interface->dev);
diff --git a/drivers/net/wireless/at76c50x-usb.h b/drivers/net/wireless/at76c50x-usb.h
index 55090a38ac95..ae03271f878e 100644
--- a/drivers/net/wireless/at76c50x-usb.h
+++ b/drivers/net/wireless/at76c50x-usb.h
@@ -447,7 +447,7 @@ struct at76_priv {
int mac80211_registered;
};
-#define AT76_SUPPORTED_FILTERS FIF_PROMISC_IN_BSS
+#define AT76_SUPPORTED_FILTERS 0
#define SCAN_POLL_INTERVAL (HZ / 4)
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c
index 5147ebe4cd05..3b343c63aa52 100644
--- a/drivers/net/wireless/ath/ar5523/ar5523.c
+++ b/drivers/net/wireless/ath/ar5523/ar5523.c
@@ -1319,8 +1319,7 @@ out_unlock:
}
-#define AR5523_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | \
+#define AR5523_SUPPORTED_FILTERS (FIF_ALLMULTI | \
FIF_FCSFAIL | \
FIF_OTHER_BSS)
@@ -1683,9 +1682,9 @@ static int ar5523_probe(struct usb_interface *intf,
(id->driver_info & AR5523_FLAG_ABG) ? '5' : '2');
ar->vif = NULL;
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_HAS_RATE_CONTROL;
+ ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
hw->extra_tx_headroom = sizeof(struct ar5523_tx_desc) +
sizeof(struct ar5523_chunk);
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index 7e9481099a8e..65ef483ebf50 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -251,6 +251,7 @@ void ath_printk(const char *level, const struct ath_common *common,
* @ATH_DBG_DFS: radar datection
* @ATH_DBG_WOW: Wake on Wireless
* @ATH_DBG_DYNACK: dynack handling
+ * @ATH_DBG_SPECTRAL_SCAN: FFT spectral scan
* @ATH_DBG_ANY: enable all debugging
*
* The debug level is used to control the amount and type of debugging output
@@ -280,6 +281,7 @@ enum ATH_DEBUG {
ATH_DBG_WOW = 0x00020000,
ATH_DBG_CHAN_CTX = 0x00040000,
ATH_DBG_DYNACK = 0x00080000,
+ ATH_DBG_SPECTRAL_SCAN = 0x00100000,
ATH_DBG_ANY = 0xffffffff
};
diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile
index f4dbb3e93bf8..9729e6941635 100644
--- a/drivers/net/wireless/ath/ath10k/Makefile
+++ b/drivers/net/wireless/ath/ath10k/Makefile
@@ -10,13 +10,15 @@ ath10k_core-y += mac.o \
wmi.o \
wmi-tlv.o \
bmi.o \
- hw.o
+ hw.o \
+ p2p.o
ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o
ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o
ath10k_core-$(CONFIG_THERMAL) += thermal.o
ath10k_core-$(CONFIG_MAC80211_DEBUGFS) += debugfs_sta.o
+ath10k_core-$(CONFIG_PM) += wow.o
obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
ath10k_pci-y += pci.o \
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index c0e454bb6a8d..59496a90ad5e 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -48,6 +48,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.name = "qca988x hw2.0",
.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
+ .has_shifted_cc_wraparound = true,
.fw = {
.dir = QCA988X_HW_2_0_FW_DIR,
.fw = QCA988X_HW_2_0_FW_FILE,
@@ -387,7 +388,9 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
- if (!skip_otp && result != 0) {
+ if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
+ ar->fw_features))
+ && result != 0) {
ath10k_err(ar, "otp calibration failed: %d", result);
return -EINVAL;
}
@@ -482,31 +485,79 @@ static int ath10k_fetch_cal_file(struct ath10k *ar)
return 0;
}
-static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
+static int ath10k_core_fetch_spec_board_file(struct ath10k *ar)
{
- int ret = 0;
+ char filename[100];
- if (ar->hw_params.fw.fw == NULL) {
- ath10k_err(ar, "firmware file not defined\n");
- return -EINVAL;
- }
+ scnprintf(filename, sizeof(filename), "board-%s-%s.bin",
+ ath10k_bus_str(ar->hif.bus), ar->spec_board_id);
+
+ ar->board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, filename);
+ if (IS_ERR(ar->board))
+ return PTR_ERR(ar->board);
+
+ ar->board_data = ar->board->data;
+ ar->board_len = ar->board->size;
+ ar->spec_board_loaded = true;
- if (ar->hw_params.fw.board == NULL) {
- ath10k_err(ar, "board data file not defined");
+ return 0;
+}
+
+static int ath10k_core_fetch_generic_board_file(struct ath10k *ar)
+{
+ if (!ar->hw_params.fw.board) {
+ ath10k_err(ar, "failed to find board file fw entry\n");
return -EINVAL;
}
ar->board = ath10k_fetch_fw_file(ar,
ar->hw_params.fw.dir,
ar->hw_params.fw.board);
- if (IS_ERR(ar->board)) {
- ret = PTR_ERR(ar->board);
- ath10k_err(ar, "could not fetch board data (%d)\n", ret);
- goto err;
- }
+ if (IS_ERR(ar->board))
+ return PTR_ERR(ar->board);
ar->board_data = ar->board->data;
ar->board_len = ar->board->size;
+ ar->spec_board_loaded = false;
+
+ return 0;
+}
+
+static int ath10k_core_fetch_board_file(struct ath10k *ar)
+{
+ int ret;
+
+ if (strlen(ar->spec_board_id) > 0) {
+ ret = ath10k_core_fetch_spec_board_file(ar);
+ if (ret) {
+ ath10k_info(ar, "failed to load spec board file, falling back to generic: %d\n",
+ ret);
+ goto generic;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "found specific board file for %s\n",
+ ar->spec_board_id);
+ return 0;
+ }
+
+generic:
+ ret = ath10k_core_fetch_generic_board_file(ar);
+ if (ret) {
+ ath10k_err(ar, "failed to fetch generic board data: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
+{
+ int ret = 0;
+
+ if (ar->hw_params.fw.fw == NULL) {
+ ath10k_err(ar, "firmware file not defined\n");
+ return -EINVAL;
+ }
ar->firmware = ath10k_fetch_fw_file(ar,
ar->hw_params.fw.dir,
@@ -675,6 +726,17 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie wmi op version %d\n",
ar->wmi.op_version);
break;
+ case ATH10K_FW_IE_HTT_OP_VERSION:
+ if (ie_len != sizeof(u32))
+ break;
+
+ version = (__le32 *)data;
+
+ ar->htt.op_version = le32_to_cpup(version);
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie htt op version %d\n",
+ ar->htt.op_version);
+ break;
default:
ath10k_warn(ar, "Unknown FW IE: %u\n",
le32_to_cpu(hdr->id));
@@ -695,27 +757,6 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
goto err;
}
- /* now fetch the board file */
- if (ar->hw_params.fw.board == NULL) {
- ath10k_err(ar, "board data file not defined");
- ret = -EINVAL;
- goto err;
- }
-
- ar->board = ath10k_fetch_fw_file(ar,
- ar->hw_params.fw.dir,
- ar->hw_params.fw.board);
- if (IS_ERR(ar->board)) {
- ret = PTR_ERR(ar->board);
- ath10k_err(ar, "could not fetch board data '%s/%s' (%d)\n",
- ar->hw_params.fw.dir, ar->hw_params.fw.board,
- ret);
- goto err;
- }
-
- ar->board_data = ar->board->data;
- ar->board_len = ar->board->size;
-
return 0;
err:
@@ -730,6 +771,19 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
/* calibration file is optional, don't check for any errors */
ath10k_fetch_cal_file(ar);
+ ret = ath10k_core_fetch_board_file(ar);
+ if (ret) {
+ ath10k_err(ar, "failed to fetch board file: %d\n", ret);
+ return ret;
+ }
+
+ ar->fw_api = 5;
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+
+ ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API5_FILE);
+ if (ret == 0)
+ goto success;
+
ar->fw_api = 4;
ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
@@ -958,6 +1012,8 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
ar->max_num_stations = TARGET_NUM_STATIONS;
ar->max_num_vdevs = TARGET_NUM_VDEVS;
ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC;
+ ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV |
+ WMI_STAT_PEER;
break;
case ATH10K_FW_WMI_OP_VERSION_10_1:
case ATH10K_FW_WMI_OP_VERSION_10_2:
@@ -966,12 +1022,17 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
ar->max_num_stations = TARGET_10X_NUM_STATIONS;
ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;
ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
+ ar->fw_stats_req_mask = WMI_STAT_PEER;
break;
case ATH10K_FW_WMI_OP_VERSION_TLV:
ar->max_num_peers = TARGET_TLV_NUM_PEERS;
ar->max_num_stations = TARGET_TLV_NUM_STATIONS;
ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS;
+ ar->max_num_tdls_vdevs = TARGET_TLV_NUM_TDLS_VDEVS;
ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC;
+ ar->wow.max_num_patterns = TARGET_TLV_NUM_WOW_PATTERNS;
+ ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV |
+ WMI_STAT_PEER;
break;
case ATH10K_FW_WMI_OP_VERSION_UNSET:
case ATH10K_FW_WMI_OP_VERSION_MAX:
@@ -979,6 +1040,29 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
return -EINVAL;
}
+ /* Backwards compatibility for firmwares without
+ * ATH10K_FW_IE_HTT_OP_VERSION.
+ */
+ if (ar->htt.op_version == ATH10K_FW_HTT_OP_VERSION_UNSET) {
+ switch (ar->wmi.op_version) {
+ case ATH10K_FW_WMI_OP_VERSION_MAIN:
+ ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_MAIN;
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_10_1:
+ case ATH10K_FW_WMI_OP_VERSION_10_2:
+ case ATH10K_FW_WMI_OP_VERSION_10_2_4:
+ ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_10_1;
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_TLV:
+ ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_TLV;
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_UNSET:
+ case ATH10K_FW_WMI_OP_VERSION_MAX:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ }
+
return 0;
}
@@ -1001,6 +1085,22 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
if (status)
goto err;
+ /* Some of of qca988x solutions are having global reset issue
+ * during target initialization. Bypassing PLL setting before
+ * downloading firmware and letting the SoC run on REF_CLK is
+ * fixing the problem. Corresponding firmware change is also needed
+ * to set the clock source once the target is initialized.
+ */
+ if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT,
+ ar->fw_features)) {
+ status = ath10k_bmi_write32(ar, hi_skip_clock_init, 1);
+ if (status) {
+ ath10k_err(ar, "could not write to skip_clock_init: %d\n",
+ status);
+ goto err;
+ }
+ }
+
status = ath10k_download_fw(ar, mode);
if (status)
goto err;
@@ -1080,9 +1180,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
status = ath10k_wmi_wait_for_service_ready(ar);
- if (status <= 0) {
+ if (status) {
ath10k_warn(ar, "wmi service ready event not received");
- status = -ETIMEDOUT;
goto err_hif_stop;
}
}
@@ -1098,9 +1197,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
}
status = ath10k_wmi_wait_for_unified_ready(ar);
- if (status <= 0) {
+ if (status) {
ath10k_err(ar, "wmi unified ready event not received\n");
- status = -ETIMEDOUT;
goto err_hif_stop;
}
@@ -1151,6 +1249,7 @@ EXPORT_SYMBOL(ath10k_core_start);
int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)
{
int ret;
+ unsigned long time_left;
reinit_completion(&ar->target_suspend);
@@ -1160,9 +1259,9 @@ int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)
return ret;
}
- ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);
+ time_left = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);
- if (ret == 0) {
+ if (!time_left) {
ath10k_warn(ar, "suspend timed out - target pause event never came\n");
return -ETIMEDOUT;
}
@@ -1386,6 +1485,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
init_completion(&ar->scan.completed);
init_completion(&ar->scan.on_channel);
init_completion(&ar->target_suspend);
+ init_completion(&ar->wow.wakeup_completed);
init_completion(&ar->install_key_done);
init_completion(&ar->vdev_setup_done);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index f65310c3ba5f..78094f23c9dd 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -35,6 +35,7 @@
#include "../dfs_pattern_detector.h"
#include "spectral.h"
#include "thermal.h"
+#include "wow.h"
#define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@@ -43,15 +44,16 @@
#define ATH10K_SCAN_ID 0
#define WMI_READY_TIMEOUT (5 * HZ)
#define ATH10K_FLUSH_TIMEOUT_HZ (5*HZ)
-#define ATH10K_NUM_CHANS 38
+#define ATH10K_CONNECTION_LOSS_HZ (3*HZ)
+#define ATH10K_NUM_CHANS 39
/* Antenna noise floor */
#define ATH10K_DEFAULT_NOISE_FLOOR -95
#define ATH10K_MAX_NUM_MGMT_PENDING 128
-/* number of failed packets */
-#define ATH10K_KICKOUT_THRESHOLD 50
+/* number of failed packets (20 packets with 16 sw reties each) */
+#define ATH10K_KICKOUT_THRESHOLD (20 * 16)
/*
* Use insanely high numbers to make sure that the firmware implementation
@@ -82,6 +84,8 @@ struct ath10k_skb_cb {
dma_addr_t paddr;
u8 eid;
u8 vdev_id;
+ enum ath10k_hw_txrx_mode txmode;
+ bool is_protected;
struct {
u8 tid;
@@ -301,6 +305,7 @@ struct ath10k_vif {
enum ath10k_beacon_state beacon_state;
void *beacon_buf;
dma_addr_t beacon_paddr;
+ unsigned long tx_paused; /* arbitrary values defined by target */
struct ath10k *ar;
struct ieee80211_vif *vif;
@@ -334,13 +339,13 @@ struct ath10k_vif {
} ap;
} u;
- u8 fixed_rate;
- u8 fixed_nss;
- u8 force_sgi;
bool use_cts_prot;
int num_legacy_stations;
int txpower;
struct wmi_wmm_params_all_arg wmm_params;
+ struct work_struct ap_csa_work;
+ struct delayed_work connection_loss_work;
+ struct cfg80211_bitrate_mask bitrate_mask;
};
struct ath10k_vif_iter {
@@ -440,6 +445,23 @@ enum ath10k_fw_features {
*/
ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT = 5,
+ /* Some firmware revisions have an incomplete WoWLAN implementation
+ * despite WMI service bit being advertised. This feature flag is used
+ * to distinguish whether WoWLAN is really supported or not.
+ */
+ ATH10K_FW_FEATURE_WOWLAN_SUPPORT = 6,
+
+ /* Don't trust error code from otp.bin */
+ ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
+
+ /* Some firmware revisions pad 4th hw address to 4 byte boundary making
+ * it 8 bytes long in Native Wifi Rx decap.
+ */
+ ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING,
+
+ /* Firmware supports bypassing PLL setting on init. */
+ ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9,
+
/* keep last */
ATH10K_FW_FEATURE_COUNT,
};
@@ -498,6 +520,11 @@ static inline const char *ath10k_scan_state_str(enum ath10k_scan_state state)
return "unknown";
}
+enum ath10k_tx_pause_reason {
+ ATH10K_TX_PAUSE_Q_FULL,
+ ATH10K_TX_PAUSE_MAX,
+};
+
struct ath10k {
struct ath_common ath_common;
struct ieee80211_hw *hw;
@@ -511,12 +538,15 @@ struct ath10k {
u32 fw_version_minor;
u16 fw_version_release;
u16 fw_version_build;
+ u32 fw_stats_req_mask;
u32 phy_capability;
u32 hw_min_tx_power;
u32 hw_max_tx_power;
u32 ht_cap_info;
u32 vht_cap_info;
u32 num_rf_chains;
+ /* protected by conf_mutex */
+ bool ani_enabled;
DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT);
@@ -541,6 +571,13 @@ struct ath10k {
u32 patch_load_addr;
int uart_pin;
+ /* This is true if given HW chip has a quirky Cycle Counter
+ * wraparound which resets to 0x7fffffff instead of 0. All
+ * other CC related counters (e.g. Rx Clear Count) are divided
+ * by 2 so they never wraparound themselves.
+ */
+ bool has_shifted_cc_wraparound;
+
struct ath10k_hw_params_fw {
const char *dir;
const char *fw;
@@ -565,6 +602,9 @@ struct ath10k {
const struct firmware *cal_file;
+ char spec_board_id[100];
+ bool spec_board_loaded;
+
int fw_api;
enum ath10k_cal_mode cal_mode;
@@ -593,6 +633,7 @@ struct ath10k {
struct cfg80211_chan_def chandef;
unsigned long long free_vdev_map;
+ struct ath10k_vif *monitor_arvif;
bool monitor;
int monitor_vdev_id;
bool monitor_started;
@@ -633,6 +674,7 @@ struct ath10k {
int max_num_peers;
int max_num_stations;
int max_num_vdevs;
+ int max_num_tdls_vdevs;
struct work_struct offchan_tx_work;
struct sk_buff_head offchan_tx_queue;
@@ -653,8 +695,18 @@ struct ath10k {
u32 survey_last_cycle_count;
struct survey_info survey[ATH10K_NUM_CHANS];
+ /* Channel info events are expected to come in pairs without and with
+ * COMPLETE flag set respectively for each channel visit during scan.
+ *
+ * However there are deviations from this rule. This flag is used to
+ * avoid reporting garbage data.
+ */
+ bool ch_info_can_report_survey;
+
struct dfs_pattern_detector *dfs_detector;
+ unsigned long tx_paused; /* see ATH10K_TX_PAUSE_ */
+
#ifdef CONFIG_ATH10K_DEBUGFS
struct ath10k_debug debug;
#endif
@@ -686,6 +738,7 @@ struct ath10k {
} stats;
struct ath10k_thermal thermal;
+ struct ath10k_wow wow;
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 301081db1ef6..8fa606a9c4dd 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -124,10 +124,14 @@ EXPORT_SYMBOL(ath10k_info);
void ath10k_print_driver_info(struct ath10k *ar)
{
- ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n",
+ ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n",
ar->hw_params.name,
ar->target_version,
ar->chip_id,
+ (strlen(ar->spec_board_id) > 0 ? ", " : ""),
+ ar->spec_board_id,
+ (strlen(ar->spec_board_id) > 0 && !ar->spec_board_loaded
+ ? " fallback" : ""),
ar->hw->wiphy->fw_version,
ar->fw_api,
ar->htt.target_version_major,
@@ -380,12 +384,12 @@ unlock:
static int ath10k_debug_fw_stats_request(struct ath10k *ar)
{
- unsigned long timeout;
+ unsigned long timeout, time_left;
int ret;
lockdep_assert_held(&ar->conf_mutex);
- timeout = jiffies + msecs_to_jiffies(1*HZ);
+ timeout = jiffies + msecs_to_jiffies(1 * HZ);
ath10k_debug_fw_stats_reset(ar);
@@ -395,18 +399,16 @@ static int ath10k_debug_fw_stats_request(struct ath10k *ar)
reinit_completion(&ar->debug.fw_stats_complete);
- ret = ath10k_wmi_request_stats(ar,
- WMI_STAT_PDEV |
- WMI_STAT_VDEV |
- WMI_STAT_PEER);
+ ret = ath10k_wmi_request_stats(ar, ar->fw_stats_req_mask);
if (ret) {
ath10k_warn(ar, "could not request stats (%d)\n", ret);
return ret;
}
- ret = wait_for_completion_timeout(&ar->debug.fw_stats_complete,
- 1*HZ);
- if (ret == 0)
+ time_left =
+ wait_for_completion_timeout(&ar->debug.fw_stats_complete,
+ 1 * HZ);
+ if (!time_left)
return -ETIMEDOUT;
spin_lock_bh(&ar->data_lock);
@@ -1708,6 +1710,61 @@ static int ath10k_debug_cal_data_release(struct inode *inode,
return 0;
}
+static ssize_t ath10k_write_ani_enable(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ int ret;
+ u8 enable;
+
+ if (kstrtou8_from_user(user_buf, count, 0, &enable))
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->ani_enabled == enable) {
+ ret = count;
+ goto exit;
+ }
+
+ ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->ani_enable,
+ enable);
+ if (ret) {
+ ath10k_warn(ar, "ani_enable failed from debugfs: %d\n", ret);
+ goto exit;
+ }
+ ar->ani_enabled = enable;
+
+ ret = count;
+
+exit:
+ mutex_unlock(&ar->conf_mutex);
+
+ return ret;
+}
+
+static ssize_t ath10k_read_ani_enable(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ int len = 0;
+ char buf[32];
+
+ len = scnprintf(buf, sizeof(buf) - len, "%d\n",
+ ar->ani_enabled);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_ani_enable = {
+ .read = ath10k_read_ani_enable,
+ .write = ath10k_write_ani_enable,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
static const struct file_operations fops_cal_data = {
.open = ath10k_debug_cal_data_open,
.read = ath10k_debug_cal_data_read,
@@ -1991,6 +2048,50 @@ static const struct file_operations fops_pktlog_filter = {
.open = simple_open
};
+static ssize_t ath10k_write_quiet_period(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ u32 period;
+
+ if (kstrtouint_from_user(ubuf, count, 0, &period))
+ return -EINVAL;
+
+ if (period < ATH10K_QUIET_PERIOD_MIN) {
+ ath10k_warn(ar, "Quiet period %u can not be lesser than 25ms\n",
+ period);
+ return -EINVAL;
+ }
+ mutex_lock(&ar->conf_mutex);
+ ar->thermal.quiet_period = period;
+ ath10k_thermal_set_throttling(ar);
+ mutex_unlock(&ar->conf_mutex);
+
+ return count;
+}
+
+static ssize_t ath10k_read_quiet_period(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char buf[32];
+ struct ath10k *ar = file->private_data;
+ int len = 0;
+
+ mutex_lock(&ar->conf_mutex);
+ len = scnprintf(buf, sizeof(buf) - len, "%d\n",
+ ar->thermal.quiet_period);
+ mutex_unlock(&ar->conf_mutex);
+
+ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_quiet_period = {
+ .read = ath10k_read_quiet_period,
+ .write = ath10k_write_quiet_period,
+ .open = simple_open
+};
+
int ath10k_debug_create(struct ath10k *ar)
{
ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data));
@@ -2068,6 +2169,9 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_cal_data);
+ debugfs_create_file("ani_enable", S_IRUSR | S_IWUSR,
+ ar->debug.debugfs_phy, ar, &fops_ani_enable);
+
debugfs_create_file("nf_cal_period", S_IRUSR | S_IWUSR,
ar->debug.debugfs_phy, ar, &fops_nf_cal_period);
@@ -2088,6 +2192,9 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("pktlog_filter", S_IRUGO | S_IWUSR,
ar->debug.debugfs_phy, ar, &fops_pktlog_filter);
+ debugfs_create_file("quiet_period", S_IRUGO | S_IWUSR,
+ ar->debug.debugfs_phy, ar, &fops_quiet_period);
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index a12b8323f9f1..53bd6a19eab6 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -36,6 +36,7 @@ enum ath10k_debug_mask {
ATH10K_DBG_REGULATORY = 0x00000800,
ATH10K_DBG_TESTMODE = 0x00001000,
ATH10K_DBG_WMI_PRINT = 0x00002000,
+ ATH10K_DBG_PCI_PS = 0x00004000,
ATH10K_DBG_ANY = 0xffffffff,
};
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 2fd9e180272b..85bfa2acb801 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -86,21 +86,6 @@ static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
ep->ep_ops.ep_tx_complete(ep->htc->ar, skb);
}
-/* assumes tx_lock is held */
-static bool ath10k_htc_ep_need_credit_update(struct ath10k_htc_ep *ep)
-{
- struct ath10k *ar = ep->htc->ar;
-
- if (!ep->tx_credit_flow_enabled)
- return false;
- if (ep->tx_credits >= ep->tx_credits_per_max_message)
- return false;
-
- ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n",
- ep->eid);
- return true;
-}
-
static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
struct sk_buff *skb)
{
@@ -111,13 +96,10 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
hdr->eid = ep->eid;
hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr));
hdr->flags = 0;
+ hdr->flags |= ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE;
spin_lock_bh(&ep->htc->tx_lock);
hdr->seq_no = ep->seq_no++;
-
- if (ath10k_htc_ep_need_credit_update(ep))
- hdr->flags |= ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE;
-
spin_unlock_bh(&ep->htc->tx_lock);
}
@@ -414,7 +396,8 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
struct ath10k_htc_msg *msg = (struct ath10k_htc_msg *)skb->data;
switch (__le16_to_cpu(msg->hdr.message_id)) {
- default:
+ case ATH10K_HTC_MSG_READY_ID:
+ case ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID:
/* handle HTC control message */
if (completion_done(&htc->ctl_resp)) {
/*
@@ -438,6 +421,10 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
break;
case ATH10K_HTC_MSG_SEND_SUSPEND_COMPLETE:
htc->htc_ops.target_send_suspend_complete(ar);
+ break;
+ default:
+ ath10k_warn(ar, "ignoring unsolicited htc ep0 event\n");
+ break;
}
goto out;
}
@@ -548,6 +535,7 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
{
struct ath10k *ar = htc->ar;
int i, status = 0;
+ unsigned long time_left;
struct ath10k_htc_svc_conn_req conn_req;
struct ath10k_htc_svc_conn_resp conn_resp;
struct ath10k_htc_msg *msg;
@@ -555,9 +543,9 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
u16 credit_count;
u16 credit_size;
- status = wait_for_completion_timeout(&htc->ctl_resp,
- ATH10K_HTC_WAIT_TIMEOUT_HZ);
- if (status == 0) {
+ time_left = wait_for_completion_timeout(&htc->ctl_resp,
+ ATH10K_HTC_WAIT_TIMEOUT_HZ);
+ if (!time_left) {
/* Workaround: In some cases the PCI HIF doesn't
* receive interrupt for the control response message
* even if the buffer was completed. It is suspected
@@ -569,10 +557,11 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
for (i = 0; i < CE_COUNT; i++)
ath10k_hif_send_complete_check(htc->ar, i, 1);
- status = wait_for_completion_timeout(&htc->ctl_resp,
- ATH10K_HTC_WAIT_TIMEOUT_HZ);
+ time_left =
+ wait_for_completion_timeout(&htc->ctl_resp,
+ ATH10K_HTC_WAIT_TIMEOUT_HZ);
- if (status == 0)
+ if (!time_left)
status = -ETIMEDOUT;
}
@@ -646,6 +635,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
struct sk_buff *skb;
unsigned int max_msg_size = 0;
int length, status;
+ unsigned long time_left;
bool disable_credit_flow_ctrl = false;
u16 message_id, service_id, flags = 0;
u8 tx_alloc = 0;
@@ -701,10 +691,10 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
}
/* wait for response */
- status = wait_for_completion_timeout(&htc->ctl_resp,
- ATH10K_HTC_CONN_SVC_TIMEOUT_HZ);
- if (status == 0) {
- ath10k_err(ar, "Service connect timeout: %d\n", status);
+ time_left = wait_for_completion_timeout(&htc->ctl_resp,
+ ATH10K_HTC_CONN_SVC_TIMEOUT_HZ);
+ if (!time_left) {
+ ath10k_err(ar, "Service connect timeout\n");
return -ETIMEDOUT;
}
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index 4f59ab923e48..6da6ef26143a 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -22,6 +22,86 @@
#include "core.h"
#include "debug.h"
+static const enum htt_t2h_msg_type htt_main_t2h_msg_types[] = {
+ [HTT_MAIN_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
+ [HTT_MAIN_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH,
+ [HTT_MAIN_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP,
+ [HTT_MAIN_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP,
+ [HTT_MAIN_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA,
+ [HTT_MAIN_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA,
+ [HTT_MAIN_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG,
+ [HTT_MAIN_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF,
+ [HTT_MAIN_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_TX_INSPECT_IND] =
+ HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] =
+ HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
+ [HTT_MAIN_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND] =
+ HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_RX_PN_IND] = HTT_T2H_MSG_TYPE_RX_PN_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND] =
+ HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST,
+};
+
+static const enum htt_t2h_msg_type htt_10x_t2h_msg_types[] = {
+ [HTT_10X_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
+ [HTT_10X_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND,
+ [HTT_10X_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH,
+ [HTT_10X_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP,
+ [HTT_10X_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP,
+ [HTT_10X_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA,
+ [HTT_10X_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA,
+ [HTT_10X_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND,
+ [HTT_10X_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG,
+ [HTT_10X_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF,
+ [HTT_10X_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND,
+ [HTT_10X_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND,
+ [HTT_10X_T2H_MSG_TYPE_RC_UPDATE_IND] = HTT_T2H_MSG_TYPE_RC_UPDATE_IND,
+ [HTT_10X_T2H_MSG_TYPE_TX_INSPECT_IND] = HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
+ [HTT_10X_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST,
+ [HTT_10X_T2H_MSG_TYPE_CHAN_CHANGE] = HTT_T2H_MSG_TYPE_CHAN_CHANGE,
+ [HTT_10X_T2H_MSG_TYPE_AGGR_CONF] = HTT_T2H_MSG_TYPE_AGGR_CONF,
+ [HTT_10X_T2H_MSG_TYPE_STATS_NOUPLOAD] = HTT_T2H_MSG_TYPE_STATS_NOUPLOAD,
+ [HTT_10X_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] =
+ HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
+};
+
+static const enum htt_t2h_msg_type htt_tlv_t2h_msg_types[] = {
+ [HTT_TLV_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
+ [HTT_TLV_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND,
+ [HTT_TLV_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH,
+ [HTT_TLV_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP,
+ [HTT_TLV_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP,
+ [HTT_TLV_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA,
+ [HTT_TLV_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA,
+ [HTT_TLV_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND,
+ [HTT_TLV_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG,
+ [HTT_TLV_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF,
+ [HTT_TLV_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND,
+ [HTT_TLV_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND,
+ [HTT_TLV_T2H_MSG_TYPE_RC_UPDATE_IND] = HTT_T2H_MSG_TYPE_RC_UPDATE_IND,
+ [HTT_TLV_T2H_MSG_TYPE_TX_INSPECT_IND] = HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
+ [HTT_TLV_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] =
+ HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
+ [HTT_TLV_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND] =
+ HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
+ [HTT_TLV_T2H_MSG_TYPE_RX_PN_IND] = HTT_T2H_MSG_TYPE_RX_PN_IND,
+ [HTT_TLV_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND] =
+ HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND,
+ [HTT_TLV_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND] =
+ HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND,
+ [HTT_TLV_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE] =
+ HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE,
+ [HTT_TLV_T2H_MSG_TYPE_CHAN_CHANGE] = HTT_T2H_MSG_TYPE_CHAN_CHANGE,
+ [HTT_TLV_T2H_MSG_TYPE_RX_OFLD_PKT_ERR] =
+ HTT_T2H_MSG_TYPE_RX_OFLD_PKT_ERR,
+ [HTT_TLV_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST,
+};
+
int ath10k_htt_connect(struct ath10k_htt *htt)
{
struct ath10k_htc_svc_conn_req conn_req;
@@ -66,6 +146,24 @@ int ath10k_htt_init(struct ath10k *ar)
8 + /* llc snap */
2; /* ip4 dscp or ip6 priority */
+ switch (ar->htt.op_version) {
+ case ATH10K_FW_HTT_OP_VERSION_10_1:
+ ar->htt.t2h_msg_types = htt_10x_t2h_msg_types;
+ ar->htt.t2h_msg_types_max = HTT_10X_T2H_NUM_MSGS;
+ break;
+ case ATH10K_FW_HTT_OP_VERSION_TLV:
+ ar->htt.t2h_msg_types = htt_tlv_t2h_msg_types;
+ ar->htt.t2h_msg_types_max = HTT_TLV_T2H_NUM_MSGS;
+ break;
+ case ATH10K_FW_HTT_OP_VERSION_MAIN:
+ ar->htt.t2h_msg_types = htt_main_t2h_msg_types;
+ ar->htt.t2h_msg_types_max = HTT_MAIN_T2H_NUM_MSGS;
+ break;
+ case ATH10K_FW_HTT_OP_VERSION_MAX:
+ case ATH10K_FW_HTT_OP_VERSION_UNSET:
+ WARN_ON(1);
+ return -EINVAL;
+ }
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 874bf44ff7a2..7e8a0d835663 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -25,7 +25,9 @@
#include <net/mac80211.h>
#include "htc.h"
+#include "hw.h"
#include "rx_desc.h"
+#include "hw.h"
enum htt_dbg_stats_type {
HTT_DBG_STATS_WAL_PDEV_TXRX = 1 << 0,
@@ -271,35 +273,108 @@ enum htt_mgmt_tx_status {
/*=== target -> host messages ===============================================*/
-enum htt_t2h_msg_type {
- HTT_T2H_MSG_TYPE_VERSION_CONF = 0x0,
- HTT_T2H_MSG_TYPE_RX_IND = 0x1,
- HTT_T2H_MSG_TYPE_RX_FLUSH = 0x2,
- HTT_T2H_MSG_TYPE_PEER_MAP = 0x3,
- HTT_T2H_MSG_TYPE_PEER_UNMAP = 0x4,
- HTT_T2H_MSG_TYPE_RX_ADDBA = 0x5,
- HTT_T2H_MSG_TYPE_RX_DELBA = 0x6,
- HTT_T2H_MSG_TYPE_TX_COMPL_IND = 0x7,
- HTT_T2H_MSG_TYPE_PKTLOG = 0x8,
- HTT_T2H_MSG_TYPE_STATS_CONF = 0x9,
- HTT_T2H_MSG_TYPE_RX_FRAG_IND = 0xa,
- HTT_T2H_MSG_TYPE_SEC_IND = 0xb,
- HTT_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc,
- HTT_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd,
- HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION = 0xe,
- HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf,
- HTT_T2H_MSG_TYPE_RX_PN_IND = 0x10,
- HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11,
- HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND = 0x12,
+enum htt_main_t2h_msg_type {
+ HTT_MAIN_T2H_MSG_TYPE_VERSION_CONF = 0x0,
+ HTT_MAIN_T2H_MSG_TYPE_RX_IND = 0x1,
+ HTT_MAIN_T2H_MSG_TYPE_RX_FLUSH = 0x2,
+ HTT_MAIN_T2H_MSG_TYPE_PEER_MAP = 0x3,
+ HTT_MAIN_T2H_MSG_TYPE_PEER_UNMAP = 0x4,
+ HTT_MAIN_T2H_MSG_TYPE_RX_ADDBA = 0x5,
+ HTT_MAIN_T2H_MSG_TYPE_RX_DELBA = 0x6,
+ HTT_MAIN_T2H_MSG_TYPE_TX_COMPL_IND = 0x7,
+ HTT_MAIN_T2H_MSG_TYPE_PKTLOG = 0x8,
+ HTT_MAIN_T2H_MSG_TYPE_STATS_CONF = 0x9,
+ HTT_MAIN_T2H_MSG_TYPE_RX_FRAG_IND = 0xa,
+ HTT_MAIN_T2H_MSG_TYPE_SEC_IND = 0xb,
+ HTT_MAIN_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd,
+ HTT_MAIN_T2H_MSG_TYPE_MGMT_TX_COMPL_IND = 0xe,
+ HTT_MAIN_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf,
+ HTT_MAIN_T2H_MSG_TYPE_RX_PN_IND = 0x10,
+ HTT_MAIN_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11,
+ HTT_MAIN_T2H_MSG_TYPE_TEST,
+ /* keep this last */
+ HTT_MAIN_T2H_NUM_MSGS
+};
+
+enum htt_10x_t2h_msg_type {
+ HTT_10X_T2H_MSG_TYPE_VERSION_CONF = 0x0,
+ HTT_10X_T2H_MSG_TYPE_RX_IND = 0x1,
+ HTT_10X_T2H_MSG_TYPE_RX_FLUSH = 0x2,
+ HTT_10X_T2H_MSG_TYPE_PEER_MAP = 0x3,
+ HTT_10X_T2H_MSG_TYPE_PEER_UNMAP = 0x4,
+ HTT_10X_T2H_MSG_TYPE_RX_ADDBA = 0x5,
+ HTT_10X_T2H_MSG_TYPE_RX_DELBA = 0x6,
+ HTT_10X_T2H_MSG_TYPE_TX_COMPL_IND = 0x7,
+ HTT_10X_T2H_MSG_TYPE_PKTLOG = 0x8,
+ HTT_10X_T2H_MSG_TYPE_STATS_CONF = 0x9,
+ HTT_10X_T2H_MSG_TYPE_RX_FRAG_IND = 0xa,
+ HTT_10X_T2H_MSG_TYPE_SEC_IND = 0xb,
+ HTT_10X_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc,
+ HTT_10X_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd,
+ HTT_10X_T2H_MSG_TYPE_TEST = 0xe,
+ HTT_10X_T2H_MSG_TYPE_CHAN_CHANGE = 0xf,
+ HTT_10X_T2H_MSG_TYPE_AGGR_CONF = 0x11,
+ HTT_10X_T2H_MSG_TYPE_STATS_NOUPLOAD = 0x12,
+ HTT_10X_T2H_MSG_TYPE_MGMT_TX_COMPL_IND = 0x13,
+ /* keep this last */
+ HTT_10X_T2H_NUM_MSGS
+};
+
+enum htt_tlv_t2h_msg_type {
+ HTT_TLV_T2H_MSG_TYPE_VERSION_CONF = 0x0,
+ HTT_TLV_T2H_MSG_TYPE_RX_IND = 0x1,
+ HTT_TLV_T2H_MSG_TYPE_RX_FLUSH = 0x2,
+ HTT_TLV_T2H_MSG_TYPE_PEER_MAP = 0x3,
+ HTT_TLV_T2H_MSG_TYPE_PEER_UNMAP = 0x4,
+ HTT_TLV_T2H_MSG_TYPE_RX_ADDBA = 0x5,
+ HTT_TLV_T2H_MSG_TYPE_RX_DELBA = 0x6,
+ HTT_TLV_T2H_MSG_TYPE_TX_COMPL_IND = 0x7,
+ HTT_TLV_T2H_MSG_TYPE_PKTLOG = 0x8,
+ HTT_TLV_T2H_MSG_TYPE_STATS_CONF = 0x9,
+ HTT_TLV_T2H_MSG_TYPE_RX_FRAG_IND = 0xa,
+ HTT_TLV_T2H_MSG_TYPE_SEC_IND = 0xb,
+ HTT_TLV_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc, /* deprecated */
+ HTT_TLV_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd,
+ HTT_TLV_T2H_MSG_TYPE_MGMT_TX_COMPL_IND = 0xe,
+ HTT_TLV_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf,
+ HTT_TLV_T2H_MSG_TYPE_RX_PN_IND = 0x10,
+ HTT_TLV_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11,
+ HTT_TLV_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND = 0x12,
/* 0x13 reservd */
- HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE = 0x14,
+ HTT_TLV_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE = 0x14,
+ HTT_TLV_T2H_MSG_TYPE_CHAN_CHANGE = 0x15,
+ HTT_TLV_T2H_MSG_TYPE_RX_OFLD_PKT_ERR = 0x16,
+ HTT_TLV_T2H_MSG_TYPE_TEST,
+ /* keep this last */
+ HTT_TLV_T2H_NUM_MSGS
+};
- /* FIXME: Do not depend on this event id. Numbering of this event id is
- * broken across different firmware revisions and HTT version fails to
- * indicate this.
- */
+enum htt_t2h_msg_type {
+ HTT_T2H_MSG_TYPE_VERSION_CONF,
+ HTT_T2H_MSG_TYPE_RX_IND,
+ HTT_T2H_MSG_TYPE_RX_FLUSH,
+ HTT_T2H_MSG_TYPE_PEER_MAP,
+ HTT_T2H_MSG_TYPE_PEER_UNMAP,
+ HTT_T2H_MSG_TYPE_RX_ADDBA,
+ HTT_T2H_MSG_TYPE_RX_DELBA,
+ HTT_T2H_MSG_TYPE_TX_COMPL_IND,
+ HTT_T2H_MSG_TYPE_PKTLOG,
+ HTT_T2H_MSG_TYPE_STATS_CONF,
+ HTT_T2H_MSG_TYPE_RX_FRAG_IND,
+ HTT_T2H_MSG_TYPE_SEC_IND,
+ HTT_T2H_MSG_TYPE_RC_UPDATE_IND,
+ HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
+ HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
+ HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
+ HTT_T2H_MSG_TYPE_RX_PN_IND,
+ HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND,
+ HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND,
+ HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE,
+ HTT_T2H_MSG_TYPE_CHAN_CHANGE,
+ HTT_T2H_MSG_TYPE_RX_OFLD_PKT_ERR,
+ HTT_T2H_MSG_TYPE_AGGR_CONF,
+ HTT_T2H_MSG_TYPE_STATS_NOUPLOAD,
HTT_T2H_MSG_TYPE_TEST,
-
/* keep this last */
HTT_T2H_NUM_MSGS
};
@@ -1222,6 +1297,7 @@ struct htt_tx_done {
u32 msdu_id;
bool discard;
bool no_ack;
+ bool success;
};
struct htt_peer_map_event {
@@ -1248,6 +1324,10 @@ struct ath10k_htt {
u8 target_version_major;
u8 target_version_minor;
struct completion target_version_received;
+ enum ath10k_fw_htt_op_version op_version;
+
+ const enum htt_t2h_msg_type *t2h_msg_types;
+ u32 t2h_msg_types_max;
struct {
/*
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 01a2b384f358..89eb16b30fc4 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -637,58 +637,21 @@ static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar,
return 0;
}
-struct rfc1042_hdr {
- u8 llc_dsap;
- u8 llc_ssap;
- u8 llc_ctrl;
- u8 snap_oui[3];
- __be16 snap_type;
-} __packed;
-
struct amsdu_subframe_hdr {
u8 dst[ETH_ALEN];
u8 src[ETH_ALEN];
__be16 len;
} __packed;
-static const u8 rx_legacy_rate_idx[] = {
- 3, /* 0x00 - 11Mbps */
- 2, /* 0x01 - 5.5Mbps */
- 1, /* 0x02 - 2Mbps */
- 0, /* 0x03 - 1Mbps */
- 3, /* 0x04 - 11Mbps */
- 2, /* 0x05 - 5.5Mbps */
- 1, /* 0x06 - 2Mbps */
- 0, /* 0x07 - 1Mbps */
- 10, /* 0x08 - 48Mbps */
- 8, /* 0x09 - 24Mbps */
- 6, /* 0x0A - 12Mbps */
- 4, /* 0x0B - 6Mbps */
- 11, /* 0x0C - 54Mbps */
- 9, /* 0x0D - 36Mbps */
- 7, /* 0x0E - 18Mbps */
- 5, /* 0x0F - 9Mbps */
-};
-
static void ath10k_htt_rx_h_rates(struct ath10k *ar,
struct ieee80211_rx_status *status,
struct htt_rx_desc *rxd)
{
- enum ieee80211_band band;
- u8 cck, rate, rate_idx, bw, sgi, mcs, nss;
+ struct ieee80211_supported_band *sband;
+ u8 cck, rate, bw, sgi, mcs, nss;
u8 preamble = 0;
u32 info1, info2, info3;
- /* Band value can't be set as undefined but freq can be 0 - use that to
- * determine whether band is provided.
- *
- * FIXME: Perhaps this can go away if CCK rate reporting is a little
- * reworked?
- */
- if (!status->freq)
- return;
-
- band = status->band;
info1 = __le32_to_cpu(rxd->ppdu_start.info1);
info2 = __le32_to_cpu(rxd->ppdu_start.info2);
info3 = __le32_to_cpu(rxd->ppdu_start.info3);
@@ -697,31 +660,18 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
switch (preamble) {
case HTT_RX_LEGACY:
+ /* To get legacy rate index band is required. Since band can't
+ * be undefined check if freq is non-zero.
+ */
+ if (!status->freq)
+ return;
+
cck = info1 & RX_PPDU_START_INFO1_L_SIG_RATE_SELECT;
rate = MS(info1, RX_PPDU_START_INFO1_L_SIG_RATE);
- rate_idx = 0;
-
- if (rate < 0x08 || rate > 0x0F)
- break;
-
- switch (band) {
- case IEEE80211_BAND_2GHZ:
- if (cck)
- rate &= ~BIT(3);
- rate_idx = rx_legacy_rate_idx[rate];
- break;
- case IEEE80211_BAND_5GHZ:
- rate_idx = rx_legacy_rate_idx[rate];
- /* We are using same rate table registering
- HW - ath10k_rates[]. In case of 5GHz skip
- CCK rates, so -4 here */
- rate_idx -= 4;
- break;
- default:
- break;
- }
+ rate &= ~RX_PPDU_START_RATE_FLAG;
- status->rate_idx = rate_idx;
+ sband = &ar->mac.sbands[status->band];
+ status->rate_idx = ath10k_mac_hw_rate_to_idx(sband, rate);
break;
case HTT_RX_HT:
case HTT_RX_HT_WITH_TXBF:
@@ -773,8 +723,87 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
}
}
+static struct ieee80211_channel *
+ath10k_htt_rx_h_peer_channel(struct ath10k *ar, struct htt_rx_desc *rxd)
+{
+ struct ath10k_peer *peer;
+ struct ath10k_vif *arvif;
+ struct cfg80211_chan_def def;
+ u16 peer_id;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ if (!rxd)
+ return NULL;
+
+ if (rxd->attention.flags &
+ __cpu_to_le32(RX_ATTENTION_FLAGS_PEER_IDX_INVALID))
+ return NULL;
+
+ if (!(rxd->msdu_end.info0 &
+ __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)))
+ return NULL;
+
+ peer_id = MS(__le32_to_cpu(rxd->mpdu_start.info0),
+ RX_MPDU_START_INFO0_PEER_IDX);
+
+ peer = ath10k_peer_find_by_id(ar, peer_id);
+ if (!peer)
+ return NULL;
+
+ arvif = ath10k_get_arvif(ar, peer->vdev_id);
+ if (WARN_ON_ONCE(!arvif))
+ return NULL;
+
+ if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def)))
+ return NULL;
+
+ return def.chan;
+}
+
+static struct ieee80211_channel *
+ath10k_htt_rx_h_vdev_channel(struct ath10k *ar, u32 vdev_id)
+{
+ struct ath10k_vif *arvif;
+ struct cfg80211_chan_def def;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ if (arvif->vdev_id == vdev_id &&
+ ath10k_mac_vif_chan(arvif->vif, &def) == 0)
+ return def.chan;
+ }
+
+ return NULL;
+}
+
+static void
+ath10k_htt_rx_h_any_chan_iter(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *conf,
+ void *data)
+{
+ struct cfg80211_chan_def *def = data;
+
+ *def = conf->def;
+}
+
+static struct ieee80211_channel *
+ath10k_htt_rx_h_any_channel(struct ath10k *ar)
+{
+ struct cfg80211_chan_def def = {};
+
+ ieee80211_iter_chan_contexts_atomic(ar->hw,
+ ath10k_htt_rx_h_any_chan_iter,
+ &def);
+
+ return def.chan;
+}
+
static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
- struct ieee80211_rx_status *status)
+ struct ieee80211_rx_status *status,
+ struct htt_rx_desc *rxd,
+ u32 vdev_id)
{
struct ieee80211_channel *ch;
@@ -782,6 +811,12 @@ static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
ch = ar->scan_channel;
if (!ch)
ch = ar->rx_channel;
+ if (!ch)
+ ch = ath10k_htt_rx_h_peer_channel(ar, rxd);
+ if (!ch)
+ ch = ath10k_htt_rx_h_vdev_channel(ar, vdev_id);
+ if (!ch)
+ ch = ath10k_htt_rx_h_any_channel(ar);
spin_unlock_bh(&ar->data_lock);
if (!ch)
@@ -819,7 +854,8 @@ static void ath10k_htt_rx_h_mactime(struct ath10k *ar,
static void ath10k_htt_rx_h_ppdu(struct ath10k *ar,
struct sk_buff_head *amsdu,
- struct ieee80211_rx_status *status)
+ struct ieee80211_rx_status *status,
+ u32 vdev_id)
{
struct sk_buff *first;
struct htt_rx_desc *rxd;
@@ -851,7 +887,7 @@ static void ath10k_htt_rx_h_ppdu(struct ath10k *ar,
status->flag |= RX_FLAG_NO_SIGNAL_VAL;
ath10k_htt_rx_h_signal(ar, status, rxd);
- ath10k_htt_rx_h_channel(ar, status);
+ ath10k_htt_rx_h_channel(ar, status, rxd, vdev_id);
ath10k_htt_rx_h_rates(ar, status, rxd);
}
@@ -929,10 +965,16 @@ static void ath10k_process_rx(struct ath10k *ar,
ieee80211_rx(ar->hw, skb);
}
-static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr)
+static int ath10k_htt_rx_nwifi_hdrlen(struct ath10k *ar,
+ struct ieee80211_hdr *hdr)
{
- /* nwifi header is padded to 4 bytes. this fixes 4addr rx */
- return round_up(ieee80211_hdrlen(hdr->frame_control), 4);
+ int len = ieee80211_hdrlen(hdr->frame_control);
+
+ if (!test_bit(ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING,
+ ar->fw_features))
+ len = round_up(len, 4);
+
+ return len;
}
static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar,
@@ -1031,7 +1073,7 @@ static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar,
/* pull decapped header and copy SA & DA */
hdr = (struct ieee80211_hdr *)msdu->data;
- hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr);
+ hdr_len = ath10k_htt_rx_nwifi_hdrlen(ar, hdr);
ether_addr_copy(da, ieee80211_get_DA(hdr));
ether_addr_copy(sa, ieee80211_get_SA(hdr));
skb_pull(msdu, hdr_len);
@@ -1522,7 +1564,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
break;
}
- ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status);
+ ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
@@ -1569,7 +1611,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
return;
}
- ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status);
+ ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
@@ -1598,6 +1640,7 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,
tx_done.no_ack = true;
break;
case HTT_DATA_TX_STATUS_OK:
+ tx_done.success = true;
break;
case HTT_DATA_TX_STATUS_DISCARD:
case HTT_DATA_TX_STATUS_POSTPONE:
@@ -1796,7 +1839,7 @@ static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
status->flag |= RX_FLAG_NO_SIGNAL_VAL;
ath10k_htt_rx_h_rx_offload_prot(status, msdu);
- ath10k_htt_rx_h_channel(ar, status);
+ ath10k_htt_rx_h_channel(ar, status, NULL, rx->vdev_id);
ath10k_process_rx(ar, status, msdu);
}
}
@@ -1869,7 +1912,7 @@ static void ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
* better to report something than nothing though. This
* should still give an idea about rx rate to the user.
*/
- ath10k_htt_rx_h_ppdu(ar, &amsdu, status);
+ ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
ath10k_htt_rx_h_filter(ar, &amsdu, status);
ath10k_htt_rx_h_mpdu(ar, &amsdu, status);
ath10k_htt_rx_h_deliver(ar, &amsdu, status);
@@ -1892,6 +1935,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
{
struct ath10k_htt *htt = &ar->htt;
struct htt_resp *resp = (struct htt_resp *)skb->data;
+ enum htt_t2h_msg_type type;
/* confirm alignment */
if (!IS_ALIGNED((unsigned long)skb->data, 4))
@@ -1899,7 +1943,16 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
resp->hdr.msg_type);
- switch (resp->hdr.msg_type) {
+
+ if (resp->hdr.msg_type >= ar->htt.t2h_msg_types_max) {
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx, unsupported msg_type: 0x%0X\n max: 0x%0X",
+ resp->hdr.msg_type, ar->htt.t2h_msg_types_max);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+ type = ar->htt.t2h_msg_types[resp->hdr.msg_type];
+
+ switch (type) {
case HTT_T2H_MSG_TYPE_VERSION_CONF: {
htt->target_version_major = resp->ver_resp.major;
htt->target_version_minor = resp->ver_resp.minor;
@@ -1937,6 +1990,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
switch (status) {
case HTT_MGMT_TX_STATUS_OK:
+ tx_done.success = true;
break;
case HTT_MGMT_TX_STATUS_RETRY:
tx_done.no_ack = true;
@@ -1976,7 +2030,6 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
case HTT_T2H_MSG_TYPE_TEST:
- /* FIX THIS */
break;
case HTT_T2H_MSG_TYPE_STATS_CONF:
trace_ath10k_htt_stats(ar, skb->data, skb->len);
@@ -2018,11 +2071,8 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
return;
}
case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:
- /* FIXME: This WMI-TLV event is overlapping with 10.2
- * CHAN_CHANGE - both being 0xF. Neither is being used in
- * practice so no immediate action is necessary. Nevertheless
- * HTT may need an abstraction layer like WMI has one day.
- */
+ break;
+ case HTT_T2H_MSG_TYPE_CHAN_CHANGE:
break;
default:
ath10k_warn(ar, "htt event (%d) not handled\n",
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index cbd2bc9e6202..a60ef7d1d5fc 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -26,7 +26,7 @@ void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
{
htt->num_pending_tx--;
if (htt->num_pending_tx == htt->max_num_pending_tx - 1)
- ieee80211_wake_queues(htt->ar->hw);
+ ath10k_mac_tx_unlock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
}
static void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
@@ -49,7 +49,7 @@ static int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt)
htt->num_pending_tx++;
if (htt->num_pending_tx == htt->max_num_pending_tx)
- ieee80211_stop_queues(htt->ar->hw);
+ ath10k_mac_tx_lock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
exit:
spin_unlock_bh(&htt->tx_lock);
@@ -420,9 +420,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
int res;
u8 flags0 = 0;
u16 msdu_id, flags1 = 0;
- dma_addr_t paddr;
- u32 frags_paddr;
- bool use_frags;
+ dma_addr_t paddr = 0;
+ u32 frags_paddr = 0;
res = ath10k_htt_tx_inc_pending(htt);
if (res)
@@ -440,12 +439,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
prefetch_len = min(htt->prefetch_len, msdu->len);
prefetch_len = roundup(prefetch_len, 4);
- /* Since HTT 3.0 there is no separate mgmt tx command. However in case
- * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
- * fragment list host driver specifies directly frame pointer. */
- use_frags = htt->target_version_major < 3 ||
- !ieee80211_is_mgmt(hdr->frame_control);
-
skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC,
&paddr);
if (!skb_cb->htt.txbuf) {
@@ -466,7 +459,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
if (res)
goto err_free_txbuf;
- if (likely(use_frags)) {
+ switch (skb_cb->txmode) {
+ case ATH10K_HW_TXRX_RAW:
+ case ATH10K_HW_TXRX_NATIVE_WIFI:
+ flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
+ /* pass through */
+ case ATH10K_HW_TXRX_ETHERNET:
frags = skb_cb->htt.txbuf->frags;
frags[0].paddr = __cpu_to_le32(skb_cb->paddr);
@@ -474,15 +472,17 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
frags[1].paddr = 0;
frags[1].len = 0;
- flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
- HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+ flags0 |= SM(skb_cb->txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
frags_paddr = skb_cb->htt.txbuf_paddr;
- } else {
+ break;
+ case ATH10K_HW_TXRX_MGMT:
flags0 |= SM(ATH10K_HW_TXRX_MGMT,
HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+ flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
frags_paddr = skb_cb->paddr;
+ break;
}
/* Normally all commands go through HTC which manages tx credits for
@@ -508,11 +508,9 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
prefetch_len);
skb_cb->htt.txbuf->htc_hdr.flags = 0;
- if (!ieee80211_has_protected(hdr->frame_control))
+ if (!skb_cb->is_protected)
flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
- flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
-
flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID);
flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID);
if (msdu->ip_summed == CHECKSUM_PARTIAL) {
diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
index 839a8791fb9e..5997f00afe3b 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -15,6 +15,7 @@
*/
#include <linux/types.h>
+#include "core.h"
#include "hw.h"
const struct ath10k_hw_regs qca988x_regs = {
@@ -56,3 +57,23 @@ const struct ath10k_hw_regs qca6174_regs = {
.soc_chip_id_address = 0x000f0,
.scratch_3_address = 0x0028,
};
+
+void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
+ u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev)
+{
+ u32 cc_fix = 0;
+
+ survey->filled |= SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY;
+
+ if (ar->hw_params.has_shifted_cc_wraparound && cc < cc_prev) {
+ cc_fix = 0x7fffffff;
+ survey->filled &= ~SURVEY_INFO_TIME_BUSY;
+ }
+
+ cc -= cc_prev - cc_fix;
+ rcc -= rcc_prev;
+
+ survey->time = CCNT_TO_MSEC(cc);
+ survey->time_busy = CCNT_TO_MSEC(rcc);
+}
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 460771fcfe9e..85cca29375fe 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -78,6 +78,9 @@ enum qca6174_chip_id_rev {
/* added support for ATH10K_FW_IE_WMI_OP_VERSION */
#define ATH10K_FW_API4_FILE "firmware-4.bin"
+/* HTT id conflict fix for management frames over HTT */
+#define ATH10K_FW_API5_FILE "firmware-5.bin"
+
#define ATH10K_FW_UTF_FILE "utf.bin"
/* includes also the null byte */
@@ -104,6 +107,11 @@ enum ath10k_fw_ie_type {
* FW API 4 and above.
*/
ATH10K_FW_IE_WMI_OP_VERSION = 5,
+
+ /* HTT "operations" interface version, 32 bit value. Supported from
+ * FW API 5 and above.
+ */
+ ATH10K_FW_IE_HTT_OP_VERSION = 6,
};
enum ath10k_fw_wmi_op_version {
@@ -119,6 +127,20 @@ enum ath10k_fw_wmi_op_version {
ATH10K_FW_WMI_OP_VERSION_MAX,
};
+enum ath10k_fw_htt_op_version {
+ ATH10K_FW_HTT_OP_VERSION_UNSET = 0,
+
+ ATH10K_FW_HTT_OP_VERSION_MAIN = 1,
+
+ /* also used in 10.2 and 10.2.4 branches */
+ ATH10K_FW_HTT_OP_VERSION_10_1 = 2,
+
+ ATH10K_FW_HTT_OP_VERSION_TLV = 3,
+
+ /* keep last */
+ ATH10K_FW_HTT_OP_VERSION_MAX,
+};
+
enum ath10k_hw_rev {
ATH10K_HW_QCA988X,
ATH10K_HW_QCA6174,
@@ -147,6 +169,9 @@ struct ath10k_hw_regs {
extern const struct ath10k_hw_regs qca988x_regs;
extern const struct ath10k_hw_regs qca6174_regs;
+void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
+ u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev);
+
#define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X)
#define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174)
@@ -180,6 +205,27 @@ struct ath10k_pktlog_hdr {
u8 payload[0];
} __packed;
+enum ath10k_hw_rate_ofdm {
+ ATH10K_HW_RATE_OFDM_48M = 0,
+ ATH10K_HW_RATE_OFDM_24M,
+ ATH10K_HW_RATE_OFDM_12M,
+ ATH10K_HW_RATE_OFDM_6M,
+ ATH10K_HW_RATE_OFDM_54M,
+ ATH10K_HW_RATE_OFDM_36M,
+ ATH10K_HW_RATE_OFDM_18M,
+ ATH10K_HW_RATE_OFDM_9M,
+};
+
+enum ath10k_hw_rate_cck {
+ ATH10K_HW_RATE_CCK_LP_11M = 0,
+ ATH10K_HW_RATE_CCK_LP_5_5M,
+ ATH10K_HW_RATE_CCK_LP_2M,
+ ATH10K_HW_RATE_CCK_LP_1M,
+ ATH10K_HW_RATE_CCK_SP_11M,
+ ATH10K_HW_RATE_CCK_SP_5_5M,
+ ATH10K_HW_RATE_CCK_SP_2M,
+};
+
/* Target specific defines for MAIN firmware */
#define TARGET_NUM_VDEVS 8
#define TARGET_NUM_PEER_AST 2
@@ -223,7 +269,7 @@ struct ath10k_pktlog_hdr {
#define TARGET_10X_NUM_WDS_ENTRIES 32
#define TARGET_10X_DMA_BURST_SIZE 0
#define TARGET_10X_MAC_AGGR_DELIM 0
-#define TARGET_10X_AST_SKID_LIMIT 16
+#define TARGET_10X_AST_SKID_LIMIT 128
#define TARGET_10X_NUM_STATIONS 128
#define TARGET_10X_NUM_PEERS ((TARGET_10X_NUM_STATIONS) + \
(TARGET_10X_NUM_VDEVS))
@@ -256,13 +302,13 @@ struct ath10k_pktlog_hdr {
#define TARGET_10_2_DMA_BURST_SIZE 1
/* Target specific defines for WMI-TLV firmware */
-#define TARGET_TLV_NUM_VDEVS 3
+#define TARGET_TLV_NUM_VDEVS 4
#define TARGET_TLV_NUM_STATIONS 32
-#define TARGET_TLV_NUM_PEERS ((TARGET_TLV_NUM_STATIONS) + \
- (TARGET_TLV_NUM_VDEVS) + \
- 2)
+#define TARGET_TLV_NUM_PEERS 35
+#define TARGET_TLV_NUM_TDLS_VDEVS 1
#define TARGET_TLV_NUM_TIDS ((TARGET_TLV_NUM_PEERS) * 2)
#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32)
+#define TARGET_TLV_NUM_WOW_PATTERNS 22
/* Number of Copy Engines supported */
#define CE_COUNT 8
@@ -406,6 +452,9 @@ struct ath10k_pktlog_hdr {
#define SCRATCH_3_ADDRESS ar->regs->scratch_3_address
#define CPU_INTR_ADDRESS 0x0010
+/* Cycle counters are running at 88MHz */
+#define CCNT_TO_MSEC(x) ((x) / 88000)
+
/* Firmware indications to the Host via SCRATCH_3 register. */
#define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS)
#define FW_IND_EVENT_PENDING 1
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 973485bd4121..218b6af63447 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -28,7 +28,131 @@
#include "txrx.h"
#include "testmode.h"
#include "wmi.h"
+#include "wmi-tlv.h"
#include "wmi-ops.h"
+#include "wow.h"
+
+/*********/
+/* Rates */
+/*********/
+
+static struct ieee80211_rate ath10k_rates[] = {
+ { .bitrate = 10,
+ .hw_value = ATH10K_HW_RATE_CCK_LP_1M },
+ { .bitrate = 20,
+ .hw_value = ATH10K_HW_RATE_CCK_LP_2M,
+ .hw_value_short = ATH10K_HW_RATE_CCK_SP_2M,
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 55,
+ .hw_value = ATH10K_HW_RATE_CCK_LP_5_5M,
+ .hw_value_short = ATH10K_HW_RATE_CCK_SP_5_5M,
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 110,
+ .hw_value = ATH10K_HW_RATE_CCK_LP_11M,
+ .hw_value_short = ATH10K_HW_RATE_CCK_SP_11M,
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+
+ { .bitrate = 60, .hw_value = ATH10K_HW_RATE_OFDM_6M },
+ { .bitrate = 90, .hw_value = ATH10K_HW_RATE_OFDM_9M },
+ { .bitrate = 120, .hw_value = ATH10K_HW_RATE_OFDM_12M },
+ { .bitrate = 180, .hw_value = ATH10K_HW_RATE_OFDM_18M },
+ { .bitrate = 240, .hw_value = ATH10K_HW_RATE_OFDM_24M },
+ { .bitrate = 360, .hw_value = ATH10K_HW_RATE_OFDM_36M },
+ { .bitrate = 480, .hw_value = ATH10K_HW_RATE_OFDM_48M },
+ { .bitrate = 540, .hw_value = ATH10K_HW_RATE_OFDM_54M },
+};
+
+#define ATH10K_MAC_FIRST_OFDM_RATE_IDX 4
+
+#define ath10k_a_rates (ath10k_rates + ATH10K_MAC_FIRST_OFDM_RATE_IDX)
+#define ath10k_a_rates_size (ARRAY_SIZE(ath10k_rates) - \
+ ATH10K_MAC_FIRST_OFDM_RATE_IDX)
+#define ath10k_g_rates (ath10k_rates + 0)
+#define ath10k_g_rates_size (ARRAY_SIZE(ath10k_rates))
+
+static bool ath10k_mac_bitrate_is_cck(int bitrate)
+{
+ switch (bitrate) {
+ case 10:
+ case 20:
+ case 55:
+ case 110:
+ return true;
+ }
+
+ return false;
+}
+
+static u8 ath10k_mac_bitrate_to_rate(int bitrate)
+{
+ return DIV_ROUND_UP(bitrate, 5) |
+ (ath10k_mac_bitrate_is_cck(bitrate) ? BIT(7) : 0);
+}
+
+u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
+ u8 hw_rate)
+{
+ const struct ieee80211_rate *rate;
+ int i;
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ rate = &sband->bitrates[i];
+
+ if (rate->hw_value == hw_rate)
+ return i;
+ else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE &&
+ rate->hw_value_short == hw_rate)
+ return i;
+ }
+
+ return 0;
+}
+
+u8 ath10k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
+ u32 bitrate)
+{
+ int i;
+
+ for (i = 0; i < sband->n_bitrates; i++)
+ if (sband->bitrates[i].bitrate == bitrate)
+ return i;
+
+ return 0;
+}
+
+static int ath10k_mac_get_max_vht_mcs_map(u16 mcs_map, int nss)
+{
+ switch ((mcs_map >> (2 * nss)) & 0x3) {
+ case IEEE80211_VHT_MCS_SUPPORT_0_7: return BIT(8) - 1;
+ case IEEE80211_VHT_MCS_SUPPORT_0_8: return BIT(9) - 1;
+ case IEEE80211_VHT_MCS_SUPPORT_0_9: return BIT(10) - 1;
+ }
+ return 0;
+}
+
+static u32
+ath10k_mac_max_ht_nss(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
+{
+ int nss;
+
+ for (nss = IEEE80211_HT_MCS_MASK_LEN - 1; nss >= 0; nss--)
+ if (ht_mcs_mask[nss])
+ return nss + 1;
+
+ return 1;
+}
+
+static u32
+ath10k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
+{
+ int nss;
+
+ for (nss = NL80211_VHT_NSS_MAX - 1; nss >= 0; nss--)
+ if (vht_mcs_mask[nss])
+ return nss + 1;
+
+ return 1;
+}
/**********/
/* Crypto */
@@ -37,7 +161,7 @@
static int ath10k_send_key(struct ath10k_vif *arvif,
struct ieee80211_key_conf *key,
enum set_key_cmd cmd,
- const u8 *macaddr, bool def_idx)
+ const u8 *macaddr, u32 flags)
{
struct ath10k *ar = arvif->ar;
struct wmi_vdev_install_key_arg arg = {
@@ -45,16 +169,12 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
.key_idx = key->keyidx,
.key_len = key->keylen,
.key_data = key->key,
+ .key_flags = flags,
.macaddr = macaddr,
};
lockdep_assert_held(&arvif->ar->conf_mutex);
- if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
- arg.key_flags = WMI_KEY_PAIRWISE;
- else
- arg.key_flags = WMI_KEY_GROUP;
-
switch (key->cipher) {
case WLAN_CIPHER_SUITE_CCMP:
arg.key_cipher = WMI_CIPHER_AES_CCM;
@@ -68,17 +188,10 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
arg.key_cipher = WMI_CIPHER_WEP;
- /* AP/IBSS mode requires self-key to be groupwise
- * Otherwise pairwise key must be set */
- if (memcmp(macaddr, arvif->vif->addr, ETH_ALEN))
- arg.key_flags = WMI_KEY_PAIRWISE;
-
- if (def_idx)
- arg.key_flags |= WMI_KEY_TX_USAGE;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
- /* this one needs to be done in software */
- return 1;
+ WARN_ON(1);
+ return -EINVAL;
default:
ath10k_warn(ar, "cipher %d is not supported\n", key->cipher);
return -EOPNOTSUPP;
@@ -95,21 +208,22 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
static int ath10k_install_key(struct ath10k_vif *arvif,
struct ieee80211_key_conf *key,
enum set_key_cmd cmd,
- const u8 *macaddr, bool def_idx)
+ const u8 *macaddr, u32 flags)
{
struct ath10k *ar = arvif->ar;
int ret;
+ unsigned long time_left;
lockdep_assert_held(&ar->conf_mutex);
reinit_completion(&ar->install_key_done);
- ret = ath10k_send_key(arvif, key, cmd, macaddr, def_idx);
+ ret = ath10k_send_key(arvif, key, cmd, macaddr, flags);
if (ret)
return ret;
- ret = wait_for_completion_timeout(&ar->install_key_done, 3*HZ);
- if (ret == 0)
+ time_left = wait_for_completion_timeout(&ar->install_key_done, 3 * HZ);
+ if (time_left == 0)
return -ETIMEDOUT;
return 0;
@@ -122,7 +236,7 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
struct ath10k_peer *peer;
int ret;
int i;
- bool def_idx;
+ u32 flags;
lockdep_assert_held(&ar->conf_mutex);
@@ -136,14 +250,20 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
for (i = 0; i < ARRAY_SIZE(arvif->wep_keys); i++) {
if (arvif->wep_keys[i] == NULL)
continue;
- /* set TX_USAGE flag for default key id */
- if (arvif->def_wep_key_idx == i)
- def_idx = true;
- else
- def_idx = false;
+
+ flags = 0;
+ flags |= WMI_KEY_PAIRWISE;
+
+ ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY,
+ addr, flags);
+ if (ret)
+ return ret;
+
+ flags = 0;
+ flags |= WMI_KEY_GROUP;
ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY,
- addr, def_idx);
+ addr, flags);
if (ret)
return ret;
@@ -152,6 +272,27 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
spin_unlock_bh(&ar->data_lock);
}
+ /* In some cases (notably with static WEP IBSS with multiple keys)
+ * multicast Tx becomes broken. Both pairwise and groupwise keys are
+ * installed already. Using WMI_KEY_TX_USAGE in different combinations
+ * didn't seem help. Using def_keyid vdev parameter seems to be
+ * effective so use that.
+ *
+ * FIXME: Revisit. Perhaps this can be done in a less hacky way.
+ */
+ if (arvif->def_wep_key_idx == -1)
+ return 0;
+
+ ret = ath10k_wmi_vdev_set_param(arvif->ar,
+ arvif->vdev_id,
+ arvif->ar->wmi.vdev_param->def_keyid,
+ arvif->def_wep_key_idx);
+ if (ret) {
+ ath10k_warn(ar, "failed to re-set def wpa key idxon vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
return 0;
}
@@ -163,6 +304,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
int first_errno = 0;
int ret;
int i;
+ u32 flags = 0;
lockdep_assert_held(&ar->conf_mutex);
@@ -179,7 +321,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
/* key flags are not required to delete the key */
ret = ath10k_install_key(arvif, peer->keys[i],
- DISABLE_KEY, addr, false);
+ DISABLE_KEY, addr, flags);
if (ret && first_errno == 0)
first_errno = ret;
@@ -229,6 +371,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
int first_errno = 0;
int ret;
int i;
+ u32 flags = 0;
lockdep_assert_held(&ar->conf_mutex);
@@ -254,7 +397,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
if (i == ARRAY_SIZE(peer->keys))
break;
/* key flags are not required to delete the key */
- ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, false);
+ ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, flags);
if (ret && first_errno == 0)
first_errno = ret;
@@ -266,6 +409,39 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
return first_errno;
}
+static int ath10k_mac_vif_update_wep_key(struct ath10k_vif *arvif,
+ struct ieee80211_key_conf *key)
+{
+ struct ath10k *ar = arvif->ar;
+ struct ath10k_peer *peer;
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ list_for_each_entry(peer, &ar->peers, list) {
+ if (!memcmp(peer->addr, arvif->vif->addr, ETH_ALEN))
+ continue;
+
+ if (!memcmp(peer->addr, arvif->bssid, ETH_ALEN))
+ continue;
+
+ if (peer->keys[key->keyidx] == key)
+ continue;
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vif vdev %i update key %i needs update\n",
+ arvif->vdev_id, key->keyidx);
+
+ ret = ath10k_install_peer_wep_keys(arvif, peer->addr);
+ if (ret) {
+ ath10k_warn(ar, "failed to update wep keys on vdev %i for peer %pM: %d\n",
+ arvif->vdev_id, peer->addr, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
/*********************/
/* General utilities */
/*********************/
@@ -364,7 +540,56 @@ static u8 ath10k_parse_mpdudensity(u8 mpdudensity)
}
}
-static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
+int ath10k_mac_vif_chan(struct ieee80211_vif *vif,
+ struct cfg80211_chan_def *def)
+{
+ struct ieee80211_chanctx_conf *conf;
+
+ rcu_read_lock();
+ conf = rcu_dereference(vif->chanctx_conf);
+ if (!conf) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+
+ *def = conf->def;
+ rcu_read_unlock();
+
+ return 0;
+}
+
+static void ath10k_mac_num_chanctxs_iter(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *conf,
+ void *data)
+{
+ int *num = data;
+
+ (*num)++;
+}
+
+static int ath10k_mac_num_chanctxs(struct ath10k *ar)
+{
+ int num = 0;
+
+ ieee80211_iter_chan_contexts_atomic(ar->hw,
+ ath10k_mac_num_chanctxs_iter,
+ &num);
+
+ return num;
+}
+
+static void
+ath10k_mac_get_any_chandef_iter(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *conf,
+ void *data)
+{
+ struct cfg80211_chan_def **def = data;
+
+ *def = &conf->def;
+}
+
+static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr,
+ enum wmi_peer_type peer_type)
{
int ret;
@@ -373,7 +598,7 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
if (ar->num_peers >= ar->max_num_peers)
return -ENOBUFS;
- ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
+ ret = ath10k_wmi_peer_create(ar, vdev_id, addr, peer_type);
if (ret) {
ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n",
addr, vdev_id, ret);
@@ -517,6 +742,38 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
ar->num_stations = 0;
}
+static int ath10k_mac_tdls_peer_update(struct ath10k *ar, u32 vdev_id,
+ struct ieee80211_sta *sta,
+ enum wmi_tdls_peer_state state)
+{
+ int ret;
+ struct wmi_tdls_peer_update_cmd_arg arg = {};
+ struct wmi_tdls_peer_capab_arg cap = {};
+ struct wmi_channel_arg chan_arg = {};
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ arg.vdev_id = vdev_id;
+ arg.peer_state = state;
+ ether_addr_copy(arg.addr, sta->addr);
+
+ cap.peer_max_sp = sta->max_sp;
+ cap.peer_uapsd_queues = sta->uapsd_queues;
+
+ if (state == WMI_TDLS_PEER_STATE_CONNECTED &&
+ !sta->tdls_initiator)
+ cap.is_peer_responder = 1;
+
+ ret = ath10k_wmi_tdls_peer_update(ar, &arg, &cap, &chan_arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to update tdls peer %pM on vdev %i: %i\n",
+ arg.addr, vdev_id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/************************/
/* Interface management */
/************************/
@@ -561,16 +818,16 @@ static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif)
static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
{
- int ret;
+ unsigned long time_left;
lockdep_assert_held(&ar->conf_mutex);
if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
return -ESHUTDOWN;
- ret = wait_for_completion_timeout(&ar->vdev_setup_done,
- ATH10K_VDEV_SETUP_TIMEOUT_HZ);
- if (ret == 0)
+ time_left = wait_for_completion_timeout(&ar->vdev_setup_done,
+ ATH10K_VDEV_SETUP_TIMEOUT_HZ);
+ if (time_left == 0)
return -ETIMEDOUT;
return 0;
@@ -578,13 +835,21 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
{
- struct cfg80211_chan_def *chandef = &ar->chandef;
+ struct cfg80211_chan_def *chandef = NULL;
struct ieee80211_channel *channel = chandef->chan;
struct wmi_vdev_start_request_arg arg = {};
int ret = 0;
lockdep_assert_held(&ar->conf_mutex);
+ ieee80211_iter_chan_contexts_atomic(ar->hw,
+ ath10k_mac_get_any_chandef_iter,
+ &chandef);
+ if (WARN_ON_ONCE(!chandef))
+ return -ENOENT;
+
+ channel = chandef->chan;
+
arg.vdev_id = vdev_id;
arg.channel.freq = channel->center_freq;
arg.channel.band_center_freq1 = chandef->center_freq1;
@@ -766,27 +1031,78 @@ static int ath10k_monitor_stop(struct ath10k *ar)
return 0;
}
+static bool ath10k_mac_monitor_vdev_is_needed(struct ath10k *ar)
+{
+ int num_ctx;
+
+ /* At least one chanctx is required to derive a channel to start
+ * monitor vdev on.
+ */
+ num_ctx = ath10k_mac_num_chanctxs(ar);
+ if (num_ctx == 0)
+ return false;
+
+ /* If there's already an existing special monitor interface then don't
+ * bother creating another monitor vdev.
+ */
+ if (ar->monitor_arvif)
+ return false;
+
+ return ar->monitor ||
+ test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+}
+
+static bool ath10k_mac_monitor_vdev_is_allowed(struct ath10k *ar)
+{
+ int num_ctx;
+
+ num_ctx = ath10k_mac_num_chanctxs(ar);
+
+ /* FIXME: Current interface combinations and cfg80211/mac80211 code
+ * shouldn't allow this but make sure to prevent handling the following
+ * case anyway since multi-channel DFS hasn't been tested at all.
+ */
+ if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags) && num_ctx > 1)
+ return false;
+
+ return true;
+}
+
static int ath10k_monitor_recalc(struct ath10k *ar)
{
- bool should_start;
+ bool needed;
+ bool allowed;
+ int ret;
lockdep_assert_held(&ar->conf_mutex);
- should_start = ar->monitor ||
- ar->filter_flags & FIF_PROMISC_IN_BSS ||
- test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+ needed = ath10k_mac_monitor_vdev_is_needed(ar);
+ allowed = ath10k_mac_monitor_vdev_is_allowed(ar);
ath10k_dbg(ar, ATH10K_DBG_MAC,
- "mac monitor recalc started? %d should? %d\n",
- ar->monitor_started, should_start);
+ "mac monitor recalc started? %d needed? %d allowed? %d\n",
+ ar->monitor_started, needed, allowed);
+
+ if (WARN_ON(needed && !allowed)) {
+ if (ar->monitor_started) {
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor stopping disallowed monitor\n");
- if (should_start == ar->monitor_started)
+ ret = ath10k_monitor_stop(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to stop disallowed monitor: %d\n", ret);
+ /* not serious */
+ }
+
+ return -EPERM;
+ }
+
+ if (needed == ar->monitor_started)
return 0;
- if (should_start)
+ if (needed)
return ath10k_monitor_start(ar);
-
- return ath10k_monitor_stop(ar);
+ else
+ return ath10k_monitor_stop(ar);
}
static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif)
@@ -798,12 +1114,14 @@ static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif)
vdev_param = ar->wmi.vdev_param->enable_rtscts;
- if (arvif->use_cts_prot || arvif->num_legacy_stations > 0)
- rts_cts |= SM(WMI_RTSCTS_ENABLED, WMI_RTSCTS_SET);
+ rts_cts |= SM(WMI_RTSCTS_ENABLED, WMI_RTSCTS_SET);
if (arvif->num_legacy_stations > 0)
rts_cts |= SM(WMI_RTSCTS_ACROSS_SW_RETRIES,
WMI_RTSCTS_PROFILE);
+ else
+ rts_cts |= SM(WMI_RTSCTS_FOR_SECOND_RATESERIES,
+ WMI_RTSCTS_PROFILE);
return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
rts_cts);
@@ -846,6 +1164,27 @@ static int ath10k_stop_cac(struct ath10k *ar)
return 0;
}
+static void ath10k_mac_has_radar_iter(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *conf,
+ void *data)
+{
+ bool *ret = data;
+
+ if (!*ret && conf->radar_enabled)
+ *ret = true;
+}
+
+static bool ath10k_mac_has_radar_enabled(struct ath10k *ar)
+{
+ bool has_radar = false;
+
+ ieee80211_iter_chan_contexts_atomic(ar->hw,
+ ath10k_mac_has_radar_iter,
+ &has_radar);
+
+ return has_radar;
+}
+
static void ath10k_recalc_radar_detection(struct ath10k *ar)
{
int ret;
@@ -854,7 +1193,7 @@ static void ath10k_recalc_radar_detection(struct ath10k *ar)
ath10k_stop_cac(ar);
- if (!ar->radar_enabled)
+ if (!ath10k_mac_has_radar_enabled(ar))
return;
if (ar->num_started_vdevs > 0)
@@ -872,10 +1211,44 @@ static void ath10k_recalc_radar_detection(struct ath10k *ar)
}
}
-static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart)
+static int ath10k_vdev_stop(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ reinit_completion(&ar->vdev_setup_done);
+
+ ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
+ if (ret) {
+ ath10k_warn(ar, "failed to stop WMI vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ ret = ath10k_vdev_setup_sync(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to syncronise setup for vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ WARN_ON(ar->num_started_vdevs == 0);
+
+ if (ar->num_started_vdevs != 0) {
+ ar->num_started_vdevs--;
+ ath10k_recalc_radar_detection(ar);
+ }
+
+ return ret;
+}
+
+static int ath10k_vdev_start_restart(struct ath10k_vif *arvif,
+ const struct cfg80211_chan_def *chandef,
+ bool restart)
{
struct ath10k *ar = arvif->ar;
- struct cfg80211_chan_def *chandef = &ar->chandef;
struct wmi_vdev_start_request_arg arg = {};
int ret = 0;
@@ -939,47 +1312,16 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart)
return ret;
}
-static int ath10k_vdev_start(struct ath10k_vif *arvif)
+static int ath10k_vdev_start(struct ath10k_vif *arvif,
+ const struct cfg80211_chan_def *def)
{
- return ath10k_vdev_start_restart(arvif, false);
+ return ath10k_vdev_start_restart(arvif, def, false);
}
-static int ath10k_vdev_restart(struct ath10k_vif *arvif)
-{
- return ath10k_vdev_start_restart(arvif, true);
-}
-
-static int ath10k_vdev_stop(struct ath10k_vif *arvif)
+static int ath10k_vdev_restart(struct ath10k_vif *arvif,
+ const struct cfg80211_chan_def *def)
{
- struct ath10k *ar = arvif->ar;
- int ret;
-
- lockdep_assert_held(&ar->conf_mutex);
-
- reinit_completion(&ar->vdev_setup_done);
-
- ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
- if (ret) {
- ath10k_warn(ar, "failed to stop WMI vdev %i: %d\n",
- arvif->vdev_id, ret);
- return ret;
- }
-
- ret = ath10k_vdev_setup_sync(ar);
- if (ret) {
- ath10k_warn(ar, "failed to synchronize setup for vdev %i stop: %d\n",
- arvif->vdev_id, ret);
- return ret;
- }
-
- WARN_ON(ar->num_started_vdevs == 0);
-
- if (ar->num_started_vdevs != 0) {
- ar->num_started_vdevs--;
- ath10k_recalc_radar_detection(ar);
- }
-
- return ret;
+ return ath10k_vdev_start_restart(arvif, def, true);
}
static int ath10k_mac_setup_bcn_p2p_ie(struct ath10k_vif *arvif,
@@ -1056,6 +1398,10 @@ static int ath10k_mac_setup_bcn_tmpl(struct ath10k_vif *arvif)
if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map))
return 0;
+ if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
+ arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
+ return 0;
+
bcn = ieee80211_beacon_get_template(hw, vif, &offs);
if (!bcn) {
ath10k_warn(ar, "failed to get beacon template from mac80211\n");
@@ -1101,6 +1447,9 @@ static int ath10k_mac_setup_prb_tmpl(struct ath10k_vif *arvif)
if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map))
return 0;
+ if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
+ return 0;
+
prb = ieee80211_proberesp_get(hw, vif);
if (!prb) {
ath10k_warn(ar, "failed to get probe resp template from mac80211\n");
@@ -1119,6 +1468,80 @@ static int ath10k_mac_setup_prb_tmpl(struct ath10k_vif *arvif)
return 0;
}
+static int ath10k_mac_vif_fix_hidden_ssid(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+ struct cfg80211_chan_def def;
+ int ret;
+
+ /* When originally vdev is started during assign_vif_chanctx() some
+ * information is missing, notably SSID. Firmware revisions with beacon
+ * offloading require the SSID to be provided during vdev (re)start to
+ * handle hidden SSID properly.
+ *
+ * Vdev restart must be done after vdev has been both started and
+ * upped. Otherwise some firmware revisions (at least 10.2) fail to
+ * deliver vdev restart response event causing timeouts during vdev
+ * syncing in ath10k.
+ *
+ * Note: The vdev down/up and template reinstallation could be skipped
+ * since only wmi-tlv firmware are known to have beacon offload and
+ * wmi-tlv doesn't seem to misbehave like 10.2 wrt vdev restart
+ * response delivery. It's probably more robust to keep it as is.
+ */
+ if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map))
+ return 0;
+
+ if (WARN_ON(!arvif->is_started))
+ return -EINVAL;
+
+ if (WARN_ON(!arvif->is_up))
+ return -EINVAL;
+
+ if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def)))
+ return -EINVAL;
+
+ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
+ if (ret) {
+ ath10k_warn(ar, "failed to bring down ap vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ /* Vdev down reset beacon & presp templates. Reinstall them. Otherwise
+ * firmware will crash upon vdev up.
+ */
+
+ ret = ath10k_mac_setup_bcn_tmpl(arvif);
+ if (ret) {
+ ath10k_warn(ar, "failed to update beacon template: %d\n", ret);
+ return ret;
+ }
+
+ ret = ath10k_mac_setup_prb_tmpl(arvif);
+ if (ret) {
+ ath10k_warn(ar, "failed to update presp template: %d\n", ret);
+ return ret;
+ }
+
+ ret = ath10k_vdev_restart(arvif, &def);
+ if (ret) {
+ ath10k_warn(ar, "failed to restart ap vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
+ arvif->bssid);
+ if (ret) {
+ ath10k_warn(ar, "failed to bring up ap vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static void ath10k_control_beaconing(struct ath10k_vif *arvif,
struct ieee80211_bss_conf *info)
{
@@ -1128,9 +1551,11 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
lockdep_assert_held(&arvif->ar->conf_mutex);
if (!info->enable_beacon) {
- ath10k_vdev_stop(arvif);
+ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
+ if (ret)
+ ath10k_warn(ar, "failed to down vdev_id %i: %d\n",
+ arvif->vdev_id, ret);
- arvif->is_started = false;
arvif->is_up = false;
spin_lock_bh(&arvif->ar->data_lock);
@@ -1142,10 +1567,6 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
arvif->tx_seq_no = 0x1000;
- ret = ath10k_vdev_start(arvif);
- if (ret)
- return;
-
arvif->aid = 0;
ether_addr_copy(arvif->bssid, info->bssid);
@@ -1154,13 +1575,18 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
if (ret) {
ath10k_warn(ar, "failed to bring up vdev %d: %i\n",
arvif->vdev_id, ret);
- ath10k_vdev_stop(arvif);
return;
}
- arvif->is_started = true;
arvif->is_up = true;
+ ret = ath10k_mac_vif_fix_hidden_ssid(arvif);
+ if (ret) {
+ ath10k_warn(ar, "failed to fix hidden ssid for vdev %i, expect trouble: %d\n",
+ arvif->vdev_id, ret);
+ return;
+ }
+
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
}
@@ -1175,11 +1601,6 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
lockdep_assert_held(&arvif->ar->conf_mutex);
if (!info->ibss_joined) {
- ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, self_peer);
- if (ret)
- ath10k_warn(ar, "failed to delete IBSS self peer %pM for vdev %d: %d\n",
- self_peer, arvif->vdev_id, ret);
-
if (is_zero_ether_addr(arvif->bssid))
return;
@@ -1188,13 +1609,6 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
return;
}
- ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer);
- if (ret) {
- ath10k_warn(ar, "failed to create IBSS self peer %pM for vdev %d: %d\n",
- self_peer, arvif->vdev_id, ret);
- return;
- }
-
vdev_param = arvif->ar->wmi.vdev_param->atim_window;
ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param,
ATH10K_DEFAULT_ATIM);
@@ -1294,7 +1708,14 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
enable_ps = false;
}
- if (enable_ps) {
+ if (!arvif->is_started) {
+ /* mac80211 can update vif powersave state while disconnected.
+ * Firmware doesn't behave nicely and consumes more power than
+ * necessary if PS is disabled on a non-started vdev. Hence
+ * force-enable PS for non-running vdevs.
+ */
+ psmode = WMI_STA_PS_MODE_ENABLED;
+ } else if (enable_ps) {
psmode = WMI_STA_PS_MODE_ENABLED;
param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
@@ -1361,6 +1782,123 @@ static int ath10k_mac_vif_disable_keepalive(struct ath10k_vif *arvif)
return 0;
}
+static void ath10k_mac_vif_ap_csa_count_down(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+ struct ieee80211_vif *vif = arvif->vif;
+ int ret;
+
+ lockdep_assert_held(&arvif->ar->conf_mutex);
+
+ if (WARN_ON(!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)))
+ return;
+
+ if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
+ return;
+
+ if (!vif->csa_active)
+ return;
+
+ if (!arvif->is_up)
+ return;
+
+ if (!ieee80211_csa_is_complete(vif)) {
+ ieee80211_csa_update_counter(vif);
+
+ ret = ath10k_mac_setup_bcn_tmpl(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n",
+ ret);
+
+ ret = ath10k_mac_setup_prb_tmpl(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n",
+ ret);
+ } else {
+ ieee80211_csa_finish(vif);
+ }
+}
+
+static void ath10k_mac_vif_ap_csa_work(struct work_struct *work)
+{
+ struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
+ ap_csa_work);
+ struct ath10k *ar = arvif->ar;
+
+ mutex_lock(&ar->conf_mutex);
+ ath10k_mac_vif_ap_csa_count_down(arvif);
+ mutex_unlock(&ar->conf_mutex);
+}
+
+static void ath10k_mac_handle_beacon_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct sk_buff *skb = data;
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+
+ if (vif->type != NL80211_IFTYPE_STATION)
+ return;
+
+ if (!ether_addr_equal(mgmt->bssid, vif->bss_conf.bssid))
+ return;
+
+ cancel_delayed_work(&arvif->connection_loss_work);
+}
+
+void ath10k_mac_handle_beacon(struct ath10k *ar, struct sk_buff *skb)
+{
+ ieee80211_iterate_active_interfaces_atomic(ar->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ ath10k_mac_handle_beacon_iter,
+ skb);
+}
+
+static void ath10k_mac_handle_beacon_miss_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ u32 *vdev_id = data;
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct ath10k *ar = arvif->ar;
+ struct ieee80211_hw *hw = ar->hw;
+
+ if (arvif->vdev_id != *vdev_id)
+ return;
+
+ if (!arvif->is_up)
+ return;
+
+ ieee80211_beacon_loss(vif);
+
+ /* Firmware doesn't report beacon loss events repeatedly. If AP probe
+ * (done by mac80211) succeeds but beacons do not resume then it
+ * doesn't make sense to continue operation. Queue connection loss work
+ * which can be cancelled when beacon is received.
+ */
+ ieee80211_queue_delayed_work(hw, &arvif->connection_loss_work,
+ ATH10K_CONNECTION_LOSS_HZ);
+}
+
+void ath10k_mac_handle_beacon_miss(struct ath10k *ar, u32 vdev_id)
+{
+ ieee80211_iterate_active_interfaces_atomic(ar->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ ath10k_mac_handle_beacon_miss_iter,
+ &vdev_id);
+}
+
+static void ath10k_mac_vif_sta_connection_loss_work(struct work_struct *work)
+{
+ struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
+ connection_loss_work.work);
+ struct ieee80211_vif *vif = arvif->vif;
+
+ if (!arvif->is_up)
+ return;
+
+ ieee80211_connection_loss(vif);
+}
+
/**********************/
/* Station management */
/**********************/
@@ -1388,12 +1926,18 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
struct wmi_peer_assoc_complete_arg *arg)
{
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ u32 aid;
lockdep_assert_held(&ar->conf_mutex);
+ if (vif->type == NL80211_IFTYPE_STATION)
+ aid = vif->bss_conf.aid;
+ else
+ aid = sta->aid;
+
ether_addr_copy(arg->addr, sta->addr);
arg->vdev_id = arvif->vdev_id;
- arg->peer_aid = sta->aid;
+ arg->peer_aid = aid;
arg->peer_flags |= WMI_PEER_AUTH;
arg->peer_listen_intval = ath10k_peer_assoc_h_listen_intval(ar, vif);
arg->peer_num_spatial_streams = 1;
@@ -1405,15 +1949,18 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
struct wmi_peer_assoc_complete_arg *arg)
{
struct ieee80211_bss_conf *info = &vif->bss_conf;
+ struct cfg80211_chan_def def;
struct cfg80211_bss *bss;
const u8 *rsnie = NULL;
const u8 *wpaie = NULL;
lockdep_assert_held(&ar->conf_mutex);
- bss = cfg80211_get_bss(ar->hw->wiphy, ar->hw->conf.chandef.chan,
- info->bssid, NULL, 0, IEEE80211_BSS_TYPE_ANY,
- IEEE80211_PRIVACY_ANY);
+ if (WARN_ON(ath10k_mac_vif_chan(vif, &def)))
+ return;
+
+ bss = cfg80211_get_bss(ar->hw->wiphy, def.chan, info->bssid, NULL, 0,
+ IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
if (bss) {
const struct cfg80211_bss_ies *ies;
@@ -1443,19 +1990,29 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
}
static void ath10k_peer_assoc_h_rates(struct ath10k *ar,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct wmi_peer_assoc_complete_arg *arg)
{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct wmi_rate_set_arg *rateset = &arg->peer_legacy_rates;
+ struct cfg80211_chan_def def;
const struct ieee80211_supported_band *sband;
const struct ieee80211_rate *rates;
+ enum ieee80211_band band;
u32 ratemask;
+ u8 rate;
int i;
lockdep_assert_held(&ar->conf_mutex);
- sband = ar->hw->wiphy->bands[ar->hw->conf.chandef.chan->band];
- ratemask = sta->supp_rates[ar->hw->conf.chandef.chan->band];
+ if (WARN_ON(ath10k_mac_vif_chan(vif, &def)))
+ return;
+
+ band = def.chan->band;
+ sband = ar->hw->wiphy->bands[band];
+ ratemask = sta->supp_rates[band];
+ ratemask &= arvif->bitrate_mask.control[band].legacy;
rates = sband->bitrates;
rateset->num_rates = 0;
@@ -1464,24 +2021,66 @@ static void ath10k_peer_assoc_h_rates(struct ath10k *ar,
if (!(ratemask & 1))
continue;
- rateset->rates[rateset->num_rates] = rates->hw_value;
+ rate = ath10k_mac_bitrate_to_rate(rates->bitrate);
+ rateset->rates[rateset->num_rates] = rate;
rateset->num_rates++;
}
}
+static bool
+ath10k_peer_assoc_h_ht_masked(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
+{
+ int nss;
+
+ for (nss = 0; nss < IEEE80211_HT_MCS_MASK_LEN; nss++)
+ if (ht_mcs_mask[nss])
+ return false;
+
+ return true;
+}
+
+static bool
+ath10k_peer_assoc_h_vht_masked(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
+{
+ int nss;
+
+ for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++)
+ if (vht_mcs_mask[nss])
+ return false;
+
+ return true;
+}
+
static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct wmi_peer_assoc_complete_arg *arg)
{
const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
- int i, n;
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct cfg80211_chan_def def;
+ enum ieee80211_band band;
+ const u8 *ht_mcs_mask;
+ const u16 *vht_mcs_mask;
+ int i, n, max_nss;
u32 stbc;
lockdep_assert_held(&ar->conf_mutex);
+ if (WARN_ON(ath10k_mac_vif_chan(vif, &def)))
+ return;
+
if (!ht_cap->ht_supported)
return;
+ band = def.chan->band;
+ ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs;
+ vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
+
+ if (ath10k_peer_assoc_h_ht_masked(ht_mcs_mask) &&
+ ath10k_peer_assoc_h_vht_masked(vht_mcs_mask))
+ return;
+
arg->peer_flags |= WMI_PEER_HT;
arg->peer_max_mpdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
ht_cap->ampdu_factor)) - 1;
@@ -1500,11 +2099,13 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
arg->peer_rate_caps |= WMI_RC_CW40_FLAG;
}
- if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
- arg->peer_rate_caps |= WMI_RC_SGI_FLAG;
+ if (arvif->bitrate_mask.control[band].gi != NL80211_TXRATE_FORCE_LGI) {
+ if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
+ arg->peer_rate_caps |= WMI_RC_SGI_FLAG;
- if (ht_cap->cap & IEEE80211_HT_CAP_SGI_40)
- arg->peer_rate_caps |= WMI_RC_SGI_FLAG;
+ if (ht_cap->cap & IEEE80211_HT_CAP_SGI_40)
+ arg->peer_rate_caps |= WMI_RC_SGI_FLAG;
+ }
if (ht_cap->cap & IEEE80211_HT_CAP_TX_STBC) {
arg->peer_rate_caps |= WMI_RC_TX_STBC_FLAG;
@@ -1524,9 +2125,12 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
else if (ht_cap->mcs.rx_mask[1])
arg->peer_rate_caps |= WMI_RC_DS_FLAG;
- for (i = 0, n = 0; i < IEEE80211_HT_MCS_MASK_LEN*8; i++)
- if (ht_cap->mcs.rx_mask[i/8] & (1 << i%8))
+ for (i = 0, n = 0, max_nss = 0; i < IEEE80211_HT_MCS_MASK_LEN * 8; i++)
+ if ((ht_cap->mcs.rx_mask[i / 8] & BIT(i % 8)) &&
+ (ht_mcs_mask[i / 8] & BIT(i % 8))) {
+ max_nss = (i / 8) + 1;
arg->peer_ht_rates.rates[n++] = i;
+ }
/*
* This is a workaround for HT-enabled STAs which break the spec
@@ -1543,7 +2147,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
arg->peer_ht_rates.rates[i] = i;
} else {
arg->peer_ht_rates.num_rates = n;
- arg->peer_num_spatial_streams = sta->rx_nss;
+ arg->peer_num_spatial_streams = max_nss;
}
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
@@ -1619,19 +2223,84 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
return 0;
}
+static u16
+ath10k_peer_assoc_h_vht_limit(u16 tx_mcs_set,
+ const u16 vht_mcs_limit[NL80211_VHT_NSS_MAX])
+{
+ int idx_limit;
+ int nss;
+ u16 mcs_map;
+ u16 mcs;
+
+ for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
+ mcs_map = ath10k_mac_get_max_vht_mcs_map(tx_mcs_set, nss) &
+ vht_mcs_limit[nss];
+
+ if (mcs_map)
+ idx_limit = fls(mcs_map) - 1;
+ else
+ idx_limit = -1;
+
+ switch (idx_limit) {
+ case 0: /* fall through */
+ case 1: /* fall through */
+ case 2: /* fall through */
+ case 3: /* fall through */
+ case 4: /* fall through */
+ case 5: /* fall through */
+ case 6: /* fall through */
+ default:
+ /* see ath10k_mac_can_set_bitrate_mask() */
+ WARN_ON(1);
+ /* fall through */
+ case -1:
+ mcs = IEEE80211_VHT_MCS_NOT_SUPPORTED;
+ break;
+ case 7:
+ mcs = IEEE80211_VHT_MCS_SUPPORT_0_7;
+ break;
+ case 8:
+ mcs = IEEE80211_VHT_MCS_SUPPORT_0_8;
+ break;
+ case 9:
+ mcs = IEEE80211_VHT_MCS_SUPPORT_0_9;
+ break;
+ }
+
+ tx_mcs_set &= ~(0x3 << (nss * 2));
+ tx_mcs_set |= mcs << (nss * 2);
+ }
+
+ return tx_mcs_set;
+}
+
static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct wmi_peer_assoc_complete_arg *arg)
{
const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct cfg80211_chan_def def;
+ enum ieee80211_band band;
+ const u16 *vht_mcs_mask;
u8 ampdu_factor;
+ if (WARN_ON(ath10k_mac_vif_chan(vif, &def)))
+ return;
+
if (!vht_cap->vht_supported)
return;
+ band = def.chan->band;
+ vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
+
+ if (ath10k_peer_assoc_h_vht_masked(vht_mcs_mask))
+ return;
+
arg->peer_flags |= WMI_PEER_VHT;
- if (ar->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ)
+ if (def.chan->band == IEEE80211_BAND_2GHZ)
arg->peer_flags |= WMI_PEER_VHT_2G;
arg->peer_vht_caps = vht_cap->cap;
@@ -1657,8 +2326,8 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
__le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map);
arg->peer_vht_rates.tx_max_rate =
__le16_to_cpu(vht_cap->vht_mcs.tx_highest);
- arg->peer_vht_rates.tx_mcs_set =
- __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
+ arg->peer_vht_rates.tx_mcs_set = ath10k_peer_assoc_h_vht_limit(
+ __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map), vht_mcs_mask);
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
sta->addr, arg->peer_max_mpdu, arg->peer_flags);
@@ -1697,10 +2366,10 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
sta->addr, !!(arg->peer_flags & WMI_PEER_QOS));
}
-static bool ath10k_mac_sta_has_11g_rates(struct ieee80211_sta *sta)
+static bool ath10k_mac_sta_has_ofdm_only(struct ieee80211_sta *sta)
{
- /* First 4 rates in ath10k_rates are CCK (11b) rates. */
- return sta->supp_rates[IEEE80211_BAND_2GHZ] >> 4;
+ return sta->supp_rates[IEEE80211_BAND_2GHZ] >>
+ ATH10K_MAC_FIRST_OFDM_RATE_IDX;
}
static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
@@ -1708,21 +2377,35 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
struct ieee80211_sta *sta,
struct wmi_peer_assoc_complete_arg *arg)
{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct cfg80211_chan_def def;
+ enum ieee80211_band band;
+ const u8 *ht_mcs_mask;
+ const u16 *vht_mcs_mask;
enum wmi_phy_mode phymode = MODE_UNKNOWN;
- switch (ar->hw->conf.chandef.chan->band) {
+ if (WARN_ON(ath10k_mac_vif_chan(vif, &def)))
+ return;
+
+ band = def.chan->band;
+ ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs;
+ vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
+
+ switch (band) {
case IEEE80211_BAND_2GHZ:
- if (sta->vht_cap.vht_supported) {
+ if (sta->vht_cap.vht_supported &&
+ !ath10k_peer_assoc_h_vht_masked(vht_mcs_mask)) {
if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
phymode = MODE_11AC_VHT40;
else
phymode = MODE_11AC_VHT20;
- } else if (sta->ht_cap.ht_supported) {
+ } else if (sta->ht_cap.ht_supported &&
+ !ath10k_peer_assoc_h_ht_masked(ht_mcs_mask)) {
if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
phymode = MODE_11NG_HT40;
else
phymode = MODE_11NG_HT20;
- } else if (ath10k_mac_sta_has_11g_rates(sta)) {
+ } else if (ath10k_mac_sta_has_ofdm_only(sta)) {
phymode = MODE_11G;
} else {
phymode = MODE_11B;
@@ -1733,15 +2416,17 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
/*
* Check VHT first.
*/
- if (sta->vht_cap.vht_supported) {
+ if (sta->vht_cap.vht_supported &&
+ !ath10k_peer_assoc_h_vht_masked(vht_mcs_mask)) {
if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
phymode = MODE_11AC_VHT80;
else if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
phymode = MODE_11AC_VHT40;
else if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
phymode = MODE_11AC_VHT20;
- } else if (sta->ht_cap.ht_supported) {
- if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
+ } else if (sta->ht_cap.ht_supported &&
+ !ath10k_peer_assoc_h_ht_masked(ht_mcs_mask)) {
+ if (sta->bandwidth >= IEEE80211_STA_RX_BW_40)
phymode = MODE_11NA_HT40;
else
phymode = MODE_11NA_HT20;
@@ -1772,9 +2457,9 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar,
ath10k_peer_assoc_h_basic(ar, vif, sta, arg);
ath10k_peer_assoc_h_crypto(ar, vif, arg);
- ath10k_peer_assoc_h_rates(ar, sta, arg);
- ath10k_peer_assoc_h_ht(ar, sta, arg);
- ath10k_peer_assoc_h_vht(ar, sta, arg);
+ ath10k_peer_assoc_h_rates(ar, vif, sta, arg);
+ ath10k_peer_assoc_h_ht(ar, vif, sta, arg);
+ ath10k_peer_assoc_h_vht(ar, vif, sta, arg);
ath10k_peer_assoc_h_qos(ar, vif, sta, arg);
ath10k_peer_assoc_h_phymode(ar, vif, sta, arg);
@@ -1993,6 +2678,8 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
}
arvif->is_up = false;
+
+ cancel_delayed_work_sync(&arvif->connection_loss_work);
}
static int ath10k_station_assoc(struct ath10k *ar,
@@ -2013,7 +2700,6 @@ static int ath10k_station_assoc(struct ath10k *ar,
return ret;
}
- peer_arg.peer_reassoc = reassoc;
ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
if (ret) {
ath10k_warn(ar, "failed to run peer assoc for STA %pM vdev %i: %d\n",
@@ -2274,6 +2960,149 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
/* TX handlers */
/***************/
+void ath10k_mac_tx_lock(struct ath10k *ar, int reason)
+{
+ lockdep_assert_held(&ar->htt.tx_lock);
+
+ WARN_ON(reason >= ATH10K_TX_PAUSE_MAX);
+ ar->tx_paused |= BIT(reason);
+ ieee80211_stop_queues(ar->hw);
+}
+
+static void ath10k_mac_tx_unlock_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct ath10k *ar = data;
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+
+ if (arvif->tx_paused)
+ return;
+
+ ieee80211_wake_queue(ar->hw, arvif->vdev_id);
+}
+
+void ath10k_mac_tx_unlock(struct ath10k *ar, int reason)
+{
+ lockdep_assert_held(&ar->htt.tx_lock);
+
+ WARN_ON(reason >= ATH10K_TX_PAUSE_MAX);
+ ar->tx_paused &= ~BIT(reason);
+
+ if (ar->tx_paused)
+ return;
+
+ ieee80211_iterate_active_interfaces_atomic(ar->hw,
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ ath10k_mac_tx_unlock_iter,
+ ar);
+}
+
+void ath10k_mac_vif_tx_lock(struct ath10k_vif *arvif, int reason)
+{
+ struct ath10k *ar = arvif->ar;
+
+ lockdep_assert_held(&ar->htt.tx_lock);
+
+ WARN_ON(reason >= BITS_PER_LONG);
+ arvif->tx_paused |= BIT(reason);
+ ieee80211_stop_queue(ar->hw, arvif->vdev_id);
+}
+
+void ath10k_mac_vif_tx_unlock(struct ath10k_vif *arvif, int reason)
+{
+ struct ath10k *ar = arvif->ar;
+
+ lockdep_assert_held(&ar->htt.tx_lock);
+
+ WARN_ON(reason >= BITS_PER_LONG);
+ arvif->tx_paused &= ~BIT(reason);
+
+ if (ar->tx_paused)
+ return;
+
+ if (arvif->tx_paused)
+ return;
+
+ ieee80211_wake_queue(ar->hw, arvif->vdev_id);
+}
+
+static void ath10k_mac_vif_handle_tx_pause(struct ath10k_vif *arvif,
+ enum wmi_tlv_tx_pause_id pause_id,
+ enum wmi_tlv_tx_pause_action action)
+{
+ struct ath10k *ar = arvif->ar;
+
+ lockdep_assert_held(&ar->htt.tx_lock);
+
+ switch (pause_id) {
+ case WMI_TLV_TX_PAUSE_ID_MCC:
+ case WMI_TLV_TX_PAUSE_ID_P2P_CLI_NOA:
+ case WMI_TLV_TX_PAUSE_ID_P2P_GO_PS:
+ case WMI_TLV_TX_PAUSE_ID_AP_PS:
+ case WMI_TLV_TX_PAUSE_ID_IBSS_PS:
+ switch (action) {
+ case WMI_TLV_TX_PAUSE_ACTION_STOP:
+ ath10k_mac_vif_tx_lock(arvif, pause_id);
+ break;
+ case WMI_TLV_TX_PAUSE_ACTION_WAKE:
+ ath10k_mac_vif_tx_unlock(arvif, pause_id);
+ break;
+ default:
+ ath10k_warn(ar, "received unknown tx pause action %d on vdev %i, ignoring\n",
+ action, arvif->vdev_id);
+ break;
+ }
+ break;
+ case WMI_TLV_TX_PAUSE_ID_AP_PEER_PS:
+ case WMI_TLV_TX_PAUSE_ID_AP_PEER_UAPSD:
+ case WMI_TLV_TX_PAUSE_ID_STA_ADD_BA:
+ case WMI_TLV_TX_PAUSE_ID_HOST:
+ default:
+ /* FIXME: Some pause_ids aren't vdev specific. Instead they
+ * target peer_id and tid. Implementing these could improve
+ * traffic scheduling fairness across multiple connected
+ * stations in AP/IBSS modes.
+ */
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac ignoring unsupported tx pause vdev %i id %d\n",
+ arvif->vdev_id, pause_id);
+ break;
+ }
+}
+
+struct ath10k_mac_tx_pause {
+ u32 vdev_id;
+ enum wmi_tlv_tx_pause_id pause_id;
+ enum wmi_tlv_tx_pause_action action;
+};
+
+static void ath10k_mac_handle_tx_pause_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct ath10k_mac_tx_pause *arg = data;
+
+ ath10k_mac_vif_handle_tx_pause(arvif, arg->pause_id, arg->action);
+}
+
+void ath10k_mac_handle_tx_pause(struct ath10k *ar, u32 vdev_id,
+ enum wmi_tlv_tx_pause_id pause_id,
+ enum wmi_tlv_tx_pause_action action)
+{
+ struct ath10k_mac_tx_pause arg = {
+ .vdev_id = vdev_id,
+ .pause_id = pause_id,
+ .action = action,
+ };
+
+ spin_lock_bh(&ar->htt.tx_lock);
+ ieee80211_iterate_active_interfaces_atomic(ar->hw,
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ ath10k_mac_handle_tx_pause_iter,
+ &arg);
+ spin_unlock_bh(&ar->htt.tx_lock);
+}
+
static u8 ath10k_tx_h_get_tid(struct ieee80211_hdr *hdr)
{
if (ieee80211_is_mgmt(hdr->frame_control))
@@ -2300,6 +3129,52 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, struct ieee80211_vif *vif)
return 0;
}
+static enum ath10k_hw_txrx_mode
+ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, struct sk_buff *skb)
+{
+ const struct ieee80211_hdr *hdr = (void *)skb->data;
+ __le16 fc = hdr->frame_control;
+
+ if (!vif || vif->type == NL80211_IFTYPE_MONITOR)
+ return ATH10K_HW_TXRX_RAW;
+
+ if (ieee80211_is_mgmt(fc))
+ return ATH10K_HW_TXRX_MGMT;
+
+ /* Workaround:
+ *
+ * NullFunc frames are mostly used to ping if a client or AP are still
+ * reachable and responsive. This implies tx status reports must be
+ * accurate - otherwise either mac80211 or userspace (e.g. hostapd) can
+ * come to a conclusion that the other end disappeared and tear down
+ * BSS connection or it can never disconnect from BSS/client (which is
+ * the case).
+ *
+ * Firmware with HTT older than 3.0 delivers incorrect tx status for
+ * NullFunc frames to driver. However there's a HTT Mgmt Tx command
+ * which seems to deliver correct tx reports for NullFunc frames. The
+ * downside of using it is it ignores client powersave state so it can
+ * end up disconnecting sleeping clients in AP mode. It should fix STA
+ * mode though because AP don't sleep.
+ */
+ if (ar->htt.target_version_major < 3 &&
+ (ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) &&
+ !test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, ar->fw_features))
+ return ATH10K_HW_TXRX_MGMT;
+
+ /* Workaround:
+ *
+ * Some wmi-tlv firmwares for qca6174 have broken Tx key selection for
+ * NativeWifi txmode - it selects AP key instead of peer key. It seems
+ * to work with Ethernet txmode so use it.
+ */
+ if (ieee80211_is_data_present(fc) && sta && sta->tdls)
+ return ATH10K_HW_TXRX_ETHERNET;
+
+ return ATH10K_HW_TXRX_NATIVE_WIFI;
+}
+
/* HTT Tx uses Native Wifi tx mode which expects 802.11 frames without QoS
* Control in the header.
*/
@@ -2317,16 +3192,42 @@ static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb)
skb->data, (void *)qos_ctl - (void *)skb->data);
skb_pull(skb, IEEE80211_QOS_CTL_LEN);
- /* Fw/Hw generates a corrupted QoS Control Field for QoS NullFunc
- * frames. Powersave is handled by the fw/hw so QoS NyllFunc frames are
- * used only for CQM purposes (e.g. hostapd station keepalive ping) so
- * it is safe to downgrade to NullFunc.
+ /* Some firmware revisions don't handle sending QoS NullFunc well.
+ * These frames are mainly used for CQM purposes so it doesn't really
+ * matter whether QoS NullFunc or NullFunc are sent.
*/
hdr = (void *)skb->data;
- if (ieee80211_is_qos_nullfunc(hdr->frame_control)) {
- hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
+ if (ieee80211_is_qos_nullfunc(hdr->frame_control))
cb->htt.tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
- }
+
+ hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
+}
+
+static void ath10k_tx_h_8023(struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr;
+ struct rfc1042_hdr *rfc1042;
+ struct ethhdr *eth;
+ size_t hdrlen;
+ u8 da[ETH_ALEN];
+ u8 sa[ETH_ALEN];
+ __be16 type;
+
+ hdr = (void *)skb->data;
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
+ rfc1042 = (void *)skb->data + hdrlen;
+
+ ether_addr_copy(da, ieee80211_get_DA(hdr));
+ ether_addr_copy(sa, ieee80211_get_SA(hdr));
+ type = rfc1042->snap_type;
+
+ skb_pull(skb, hdrlen + sizeof(*rfc1042));
+ skb_push(skb, sizeof(*eth));
+
+ eth = (void *)skb->data;
+ ether_addr_copy(eth->h_dest, da);
+ ether_addr_copy(eth->h_source, sa);
+ eth->h_proto = type;
}
static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
@@ -2365,45 +3266,51 @@ static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar)
ar->htt.target_version_minor >= 4);
}
-static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb)
{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct sk_buff_head *q = &ar->wmi_mgmt_tx_queue;
int ret = 0;
- if (ar->htt.target_version_major >= 3) {
- /* Since HTT 3.0 there is no separate mgmt tx command */
- ret = ath10k_htt_tx(&ar->htt, skb);
- goto exit;
+ spin_lock_bh(&ar->data_lock);
+
+ if (skb_queue_len(q) == ATH10K_MAX_NUM_MGMT_PENDING) {
+ ath10k_warn(ar, "wmi mgmt tx queue is full\n");
+ ret = -ENOSPC;
+ goto unlock;
}
- if (ieee80211_is_mgmt(hdr->frame_control)) {
- if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
- ar->fw_features)) {
- if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >=
- ATH10K_MAX_NUM_MGMT_PENDING) {
- ath10k_warn(ar, "reached WMI management transmit queue limit\n");
- ret = -EBUSY;
- goto exit;
- }
+ __skb_queue_tail(q, skb);
+ ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
- skb_queue_tail(&ar->wmi_mgmt_tx_queue, skb);
- ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
- } else {
- ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
- }
- } else if (!test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
- ar->fw_features) &&
- ieee80211_is_nullfunc(hdr->frame_control)) {
- /* FW does not report tx status properly for NullFunc frames
- * unless they are sent through mgmt tx path. mac80211 sends
- * those frames when it detects link/beacon loss and depends
- * on the tx status to be correct. */
- ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
- } else {
- ret = ath10k_htt_tx(&ar->htt, skb);
+unlock:
+ spin_unlock_bh(&ar->data_lock);
+
+ return ret;
+}
+
+static void ath10k_mac_tx(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
+ struct ath10k_htt *htt = &ar->htt;
+ int ret = 0;
+
+ switch (cb->txmode) {
+ case ATH10K_HW_TXRX_RAW:
+ case ATH10K_HW_TXRX_NATIVE_WIFI:
+ case ATH10K_HW_TXRX_ETHERNET:
+ ret = ath10k_htt_tx(htt, skb);
+ break;
+ case ATH10K_HW_TXRX_MGMT:
+ if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
+ ar->fw_features))
+ ret = ath10k_mac_tx_wmi_mgmt(ar, skb);
+ else if (ar->htt.target_version_major >= 3)
+ ret = ath10k_htt_tx(htt, skb);
+ else
+ ret = ath10k_htt_mgmt_tx(htt, skb);
+ break;
}
-exit:
if (ret) {
ath10k_warn(ar, "failed to transmit packet, dropping: %d\n",
ret);
@@ -2433,6 +3340,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
const u8 *peer_addr;
int vdev_id;
int ret;
+ unsigned long time_left;
/* FW requirement: We must create a peer before FW will send out
* an offchannel frame. Otherwise the frame will be stuck and
@@ -2465,7 +3373,8 @@ void ath10k_offchan_tx_work(struct work_struct *work)
peer_addr, vdev_id);
if (!peer) {
- ret = ath10k_peer_create(ar, vdev_id, peer_addr);
+ ret = ath10k_peer_create(ar, vdev_id, peer_addr,
+ WMI_PEER_TYPE_DEFAULT);
if (ret)
ath10k_warn(ar, "failed to create peer %pM on vdev %d: %d\n",
peer_addr, vdev_id, ret);
@@ -2476,11 +3385,11 @@ void ath10k_offchan_tx_work(struct work_struct *work)
ar->offchan_tx_skb = skb;
spin_unlock_bh(&ar->data_lock);
- ath10k_tx_htt(ar, skb);
+ ath10k_mac_tx(ar, skb);
- ret = wait_for_completion_timeout(&ar->offchan_tx_completed,
- 3 * HZ);
- if (ret == 0)
+ time_left =
+ wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ);
+ if (time_left == 0)
ath10k_warn(ar, "timed out waiting for offchannel skb %p\n",
skb);
@@ -2700,21 +3609,38 @@ static void ath10k_tx(struct ieee80211_hw *hw,
struct ath10k *ar = hw->priv;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
+ struct ieee80211_sta *sta = control->sta;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ __le16 fc = hdr->frame_control;
/* We should disable CCK RATE due to P2P */
if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
ATH10K_SKB_CB(skb)->htt.is_offchan = false;
+ ATH10K_SKB_CB(skb)->htt.freq = 0;
ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr);
ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif);
+ ATH10K_SKB_CB(skb)->txmode = ath10k_tx_h_get_txmode(ar, vif, sta, skb);
+ ATH10K_SKB_CB(skb)->is_protected = ieee80211_has_protected(fc);
- /* it makes no sense to process injected frames like that */
- if (vif && vif->type != NL80211_IFTYPE_MONITOR) {
+ switch (ATH10K_SKB_CB(skb)->txmode) {
+ case ATH10K_HW_TXRX_MGMT:
+ case ATH10K_HW_TXRX_NATIVE_WIFI:
ath10k_tx_h_nwifi(hw, skb);
ath10k_tx_h_add_p2p_noa_ie(ar, vif, skb);
ath10k_tx_h_seq_no(vif, skb);
+ break;
+ case ATH10K_HW_TXRX_ETHERNET:
+ ath10k_tx_h_8023(skb);
+ break;
+ case ATH10K_HW_TXRX_RAW:
+ /* FIXME: Packet injection isn't implemented. It should be
+ * doable with firmware 10.2 on qca988x.
+ */
+ WARN_ON_ONCE(1);
+ ieee80211_free_txskb(hw, skb);
+ return;
}
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
@@ -2736,7 +3662,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
}
}
- ath10k_tx_htt(ar, skb);
+ ath10k_mac_tx(ar, skb);
}
/* Must not be called with conf_mutex held as workers can use that also. */
@@ -2761,11 +3687,13 @@ void ath10k_halt(struct ath10k *ar)
clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
ar->filter_flags = 0;
ar->monitor = false;
+ ar->monitor_arvif = NULL;
if (ar->monitor_started)
ath10k_monitor_stop(ar);
ar->monitor_started = false;
+ ar->tx_paused = 0;
ath10k_scan_finish(ar);
ath10k_peer_cleanup_all(ar);
@@ -2859,6 +3787,7 @@ static int ath10k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
static int ath10k_start(struct ieee80211_hw *hw)
{
struct ath10k *ar = hw->priv;
+ u32 burst_enable;
int ret = 0;
/*
@@ -2913,6 +3842,24 @@ static int ath10k_start(struct ieee80211_hw *hw)
goto err_core_stop;
}
+ if (test_bit(WMI_SERVICE_ADAPTIVE_OCS, ar->wmi.svc_map)) {
+ ret = ath10k_wmi_adaptive_qcs(ar, true);
+ if (ret) {
+ ath10k_warn(ar, "failed to enable adaptive qcs: %d\n",
+ ret);
+ goto err_core_stop;
+ }
+ }
+
+ if (test_bit(WMI_SERVICE_BURST, ar->wmi.svc_map)) {
+ burst_enable = ar->wmi.pdev_param->burst_enable;
+ ret = ath10k_wmi_pdev_set_param(ar, burst_enable, 0);
+ if (ret) {
+ ath10k_warn(ar, "failed to disable burst: %d\n", ret);
+ goto err_core_stop;
+ }
+ }
+
if (ar->cfg_tx_chainmask)
__ath10k_set_antenna(ar, ar->cfg_tx_chainmask,
ar->cfg_rx_chainmask);
@@ -2934,10 +3881,21 @@ static int ath10k_start(struct ieee80211_hw *hw)
goto err_core_stop;
}
+ ret = ath10k_wmi_pdev_set_param(ar,
+ ar->wmi.pdev_param->ani_enable, 1);
+ if (ret) {
+ ath10k_warn(ar, "failed to enable ani by default: %d\n",
+ ret);
+ goto err_core_stop;
+ }
+
+ ar->ani_enabled = true;
+
ar->num_started_vdevs = 0;
ath10k_regd_update(ar);
ath10k_spectral_start(ar);
+ ath10k_thermal_set_throttling(ar);
mutex_unlock(&ar->conf_mutex);
return 0;
@@ -2991,97 +3949,6 @@ static int ath10k_config_ps(struct ath10k *ar)
return ret;
}
-static const char *chandef_get_width(enum nl80211_chan_width width)
-{
- switch (width) {
- case NL80211_CHAN_WIDTH_20_NOHT:
- return "20 (noht)";
- case NL80211_CHAN_WIDTH_20:
- return "20";
- case NL80211_CHAN_WIDTH_40:
- return "40";
- case NL80211_CHAN_WIDTH_80:
- return "80";
- case NL80211_CHAN_WIDTH_80P80:
- return "80+80";
- case NL80211_CHAN_WIDTH_160:
- return "160";
- case NL80211_CHAN_WIDTH_5:
- return "5";
- case NL80211_CHAN_WIDTH_10:
- return "10";
- }
- return "?";
-}
-
-static void ath10k_config_chan(struct ath10k *ar)
-{
- struct ath10k_vif *arvif;
- int ret;
-
- lockdep_assert_held(&ar->conf_mutex);
-
- ath10k_dbg(ar, ATH10K_DBG_MAC,
- "mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n",
- ar->chandef.chan->center_freq,
- ar->chandef.center_freq1,
- ar->chandef.center_freq2,
- chandef_get_width(ar->chandef.width));
-
- /* First stop monitor interface. Some FW versions crash if there's a
- * lone monitor interface. */
- if (ar->monitor_started)
- ath10k_monitor_stop(ar);
-
- list_for_each_entry(arvif, &ar->arvifs, list) {
- if (!arvif->is_started)
- continue;
-
- if (!arvif->is_up)
- continue;
-
- if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
- continue;
-
- ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
- if (ret) {
- ath10k_warn(ar, "failed to down vdev %d: %d\n",
- arvif->vdev_id, ret);
- continue;
- }
- }
-
- /* all vdevs are downed now - attempt to restart and re-up them */
-
- list_for_each_entry(arvif, &ar->arvifs, list) {
- if (!arvif->is_started)
- continue;
-
- if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
- continue;
-
- ret = ath10k_vdev_restart(arvif);
- if (ret) {
- ath10k_warn(ar, "failed to restart vdev %d: %d\n",
- arvif->vdev_id, ret);
- continue;
- }
-
- if (!arvif->is_up)
- continue;
-
- ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
- arvif->bssid);
- if (ret) {
- ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
- arvif->vdev_id, ret);
- continue;
- }
- }
-
- ath10k_monitor_recalc(ar);
-}
-
static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower)
{
int ret;
@@ -3147,26 +4014,6 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&ar->conf_mutex);
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- ath10k_dbg(ar, ATH10K_DBG_MAC,
- "mac config channel %dMHz flags 0x%x radar %d\n",
- conf->chandef.chan->center_freq,
- conf->chandef.chan->flags,
- conf->radar_enabled);
-
- spin_lock_bh(&ar->data_lock);
- ar->rx_channel = conf->chandef.chan;
- spin_unlock_bh(&ar->data_lock);
-
- ar->radar_enabled = conf->radar_enabled;
- ath10k_recalc_radar_detection(ar);
-
- if (!cfg80211_chandef_identical(&ar->chandef, &conf->chandef)) {
- ar->chandef = conf->chandef;
- ath10k_config_chan(ar);
- }
- }
-
if (changed & IEEE80211_CONF_CHANGE_PS)
ath10k_config_ps(ar);
@@ -3208,6 +4055,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
int ret = 0;
u32 value;
int bit;
+ int i;
u32 vdev_param;
vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
@@ -3220,6 +4068,17 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
arvif->vif = vif;
INIT_LIST_HEAD(&arvif->list);
+ INIT_WORK(&arvif->ap_csa_work, ath10k_mac_vif_ap_csa_work);
+ INIT_DELAYED_WORK(&arvif->connection_loss_work,
+ ath10k_mac_vif_sta_connection_loss_work);
+
+ for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) {
+ arvif->bitrate_mask.control[i].legacy = 0xffffffff;
+ memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff,
+ sizeof(arvif->bitrate_mask.control[i].ht_mcs));
+ memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff,
+ sizeof(arvif->bitrate_mask.control[i].vht_mcs));
+ }
if (ar->free_vdev_map == 0) {
ath10k_warn(ar, "Free vdev map is empty, no more interfaces allowed.\n");
@@ -3262,6 +4121,15 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
break;
}
+ /* Using vdev_id as queue number will make it very easy to do per-vif
+ * tx queue locking. This shouldn't wrap due to interface combinations
+ * but do a modulo for correctness sake and prevent using offchannel tx
+ * queues for regular vif tx.
+ */
+ vif->cab_queue = arvif->vdev_id % (IEEE80211_MAX_QUEUES - 1);
+ for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++)
+ vif->hw_queue[i] = arvif->vdev_id % (IEEE80211_MAX_QUEUES - 1);
+
/* Some firmware revisions don't wait for beacon tx completion before
* sending another SWBA event. This could lead to hardware using old
* (freed) beacon data in some cases, e.g. tx credit starvation
@@ -3343,14 +4211,18 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
}
}
- if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
- ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
+ if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
+ arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
+ ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr,
+ WMI_PEER_TYPE_DEFAULT);
if (ret) {
- ath10k_warn(ar, "failed to create vdev %i peer for AP: %d\n",
+ ath10k_warn(ar, "failed to create vdev %i peer for AP/IBSS: %d\n",
arvif->vdev_id, ret);
goto err_vdev_delete;
}
+ }
+ if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
ret = ath10k_mac_set_kickout(arvif);
if (ret) {
ath10k_warn(ar, "failed to set vdev %i kickout parameters: %d\n",
@@ -3406,11 +4278,21 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
goto err_peer_delete;
}
+ if (vif->type == NL80211_IFTYPE_MONITOR) {
+ ar->monitor_arvif = arvif;
+ ret = ath10k_monitor_recalc(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to recalc monitor: %d\n", ret);
+ goto err_peer_delete;
+ }
+ }
+
mutex_unlock(&ar->conf_mutex);
return 0;
err_peer_delete:
- if (arvif->vdev_type == WMI_VDEV_TYPE_AP)
+ if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
+ arvif->vdev_type == WMI_VDEV_TYPE_IBSS)
ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr);
err_vdev_delete:
@@ -3430,6 +4312,14 @@ err:
return ret;
}
+static void ath10k_mac_vif_tx_unlock_all(struct ath10k_vif *arvif)
+{
+ int i;
+
+ for (i = 0; i < BITS_PER_LONG; i++)
+ ath10k_mac_vif_tx_unlock(arvif, i);
+}
+
static void ath10k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -3437,6 +4327,9 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
int ret;
+ cancel_work_sync(&arvif->ap_csa_work);
+ cancel_delayed_work_sync(&arvif->connection_loss_work);
+
mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock);
@@ -3451,11 +4344,12 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
ar->free_vdev_map |= 1LL << arvif->vdev_id;
list_del(&arvif->list);
- if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
+ if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
+ arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
ret = ath10k_wmi_peer_delete(arvif->ar, arvif->vdev_id,
vif->addr);
if (ret)
- ath10k_warn(ar, "failed to submit AP self-peer removal on vdev %i: %d\n",
+ ath10k_warn(ar, "failed to submit AP/IBSS self-peer removal on vdev %i: %d\n",
arvif->vdev_id, ret);
kfree(arvif->u.ap.noa_data);
@@ -3472,7 +4366,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
/* Some firmware revisions don't notify host about self-peer removal
* until after associated vdev is deleted.
*/
- if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
+ if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
+ arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
ret = ath10k_wait_for_peer_deleted(ar, arvif->vdev_id,
vif->addr);
if (ret)
@@ -3486,6 +4381,17 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
ath10k_peer_cleanup(ar, arvif->vdev_id);
+ if (vif->type == NL80211_IFTYPE_MONITOR) {
+ ar->monitor_arvif = NULL;
+ ret = ath10k_monitor_recalc(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to recalc monitor: %d\n", ret);
+ }
+
+ spin_lock_bh(&ar->htt.tx_lock);
+ ath10k_mac_vif_tx_unlock_all(arvif);
+ spin_unlock_bh(&ar->htt.tx_lock);
+
mutex_unlock(&ar->conf_mutex);
}
@@ -3493,8 +4399,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
* FIXME: Has to be verified.
*/
#define SUPPORTED_FILTERS \
- (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | \
+ (FIF_ALLMULTI | \
FIF_CONTROL | \
FIF_PSPOLL | \
FIF_OTHER_BSS | \
@@ -3615,6 +4520,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
if (ret)
ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
arvif->vdev_id, ret);
+
+ vdev_param = ar->wmi.vdev_param->protection_mode;
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
+ info->use_cts_prot ? 1 : 0);
+ if (ret)
+ ath10k_warn(ar, "failed to set protection mode %d on vdev %i: %d\n",
+ info->use_cts_prot, arvif->vdev_id, ret);
}
if (changed & BSS_CHANGED_ERP_SLOT) {
@@ -3791,10 +4703,14 @@ static void ath10k_set_key_h_def_keyidx(struct ath10k *ar,
* frames with multi-vif APs. This is not required for main firmware
* branch (e.g. 636).
*
- * FIXME: This has been tested only in AP. It remains unknown if this
- * is required for multi-vif STA interfaces on 10.1 */
+ * This is also needed for 636 fw for IBSS-RSN to work more reliably.
+ *
+ * FIXME: It remains unknown if this is required for multi-vif STA
+ * interfaces on 10.1.
+ */
- if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
+ if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
+ arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
return;
if (key->cipher == WLAN_CIPHER_SUITE_WEP40)
@@ -3826,8 +4742,14 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
const u8 *peer_addr;
bool is_wep = key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
key->cipher == WLAN_CIPHER_SUITE_WEP104;
- bool def_idx = false;
int ret = 0;
+ int ret2;
+ u32 flags = 0;
+ u32 flags2;
+
+ /* this one needs to be done in software */
+ if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
+ return 1;
if (key->keyidx > WMI_MAX_KEY_INDEX)
return -ENOSPC;
@@ -3843,6 +4765,13 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key->hw_key_idx = key->keyidx;
+ if (is_wep) {
+ if (cmd == SET_KEY)
+ arvif->wep_keys[key->keyidx] = key;
+ else
+ arvif->wep_keys[key->keyidx] = NULL;
+ }
+
/* the peer should not disappear in mid-way (unless FW goes awry) since
* we already hold conf_mutex. we just make sure its there now. */
spin_lock_bh(&ar->data_lock);
@@ -3862,30 +4791,61 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
}
}
- if (is_wep) {
- if (cmd == SET_KEY)
- arvif->wep_keys[key->keyidx] = key;
- else
- arvif->wep_keys[key->keyidx] = NULL;
+ if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+ flags |= WMI_KEY_PAIRWISE;
+ else
+ flags |= WMI_KEY_GROUP;
+ if (is_wep) {
if (cmd == DISABLE_KEY)
ath10k_clear_vdev_key(arvif, key);
- }
- /* set TX_USAGE flag for all the keys incase of dot1x-WEP. For
- * static WEP, do not set this flag for the keys whose key id
- * is greater than default key id.
- */
- if (arvif->def_wep_key_idx == -1)
- def_idx = true;
+ /* When WEP keys are uploaded it's possible that there are
+ * stations associated already (e.g. when merging) without any
+ * keys. Static WEP needs an explicit per-peer key upload.
+ */
+ if (vif->type == NL80211_IFTYPE_ADHOC &&
+ cmd == SET_KEY)
+ ath10k_mac_vif_update_wep_key(arvif, key);
+
+ /* 802.1x never sets the def_wep_key_idx so each set_key()
+ * call changes default tx key.
+ *
+ * Static WEP sets def_wep_key_idx via .set_default_unicast_key
+ * after first set_key().
+ */
+ if (cmd == SET_KEY && arvif->def_wep_key_idx == -1)
+ flags |= WMI_KEY_TX_USAGE;
+ }
- ret = ath10k_install_key(arvif, key, cmd, peer_addr, def_idx);
+ ret = ath10k_install_key(arvif, key, cmd, peer_addr, flags);
if (ret) {
ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n",
arvif->vdev_id, peer_addr, ret);
goto exit;
}
+ /* mac80211 sets static WEP keys as groupwise while firmware requires
+ * them to be installed twice as both pairwise and groupwise.
+ */
+ if (is_wep && !sta && vif->type == NL80211_IFTYPE_STATION) {
+ flags2 = flags;
+ flags2 &= ~WMI_KEY_GROUP;
+ flags2 |= WMI_KEY_PAIRWISE;
+
+ ret = ath10k_install_key(arvif, key, cmd, peer_addr, flags2);
+ if (ret) {
+ ath10k_warn(ar, "failed to install (ucast) key for vdev %i peer %pM: %d\n",
+ arvif->vdev_id, peer_addr, ret);
+ ret2 = ath10k_install_key(arvif, key, DISABLE_KEY,
+ peer_addr, flags);
+ if (ret2)
+ ath10k_warn(ar, "failed to disable (mcast) key for vdev %i peer %pM: %d\n",
+ arvif->vdev_id, peer_addr, ret2);
+ goto exit;
+ }
+ }
+
ath10k_set_key_h_def_keyidx(ar, arvif, cmd, key);
spin_lock_bh(&ar->data_lock);
@@ -3933,6 +4893,7 @@ static void ath10k_set_default_unicast_key(struct ieee80211_hw *hw,
}
arvif->def_wep_key_idx = keyidx;
+
unlock:
mutex_unlock(&arvif->ar->conf_mutex);
}
@@ -3943,6 +4904,10 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
struct ath10k_vif *arvif;
struct ath10k_sta *arsta;
struct ieee80211_sta *sta;
+ struct cfg80211_chan_def def;
+ enum ieee80211_band band;
+ const u8 *ht_mcs_mask;
+ const u16 *vht_mcs_mask;
u32 changed, bw, nss, smps;
int err;
@@ -3951,6 +4916,13 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
arvif = arsta->arvif;
ar = arvif->ar;
+ if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def)))
+ return;
+
+ band = def.chan->band;
+ ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs;
+ vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
+
spin_lock_bh(&ar->data_lock);
changed = arsta->changed;
@@ -3964,6 +4936,10 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
mutex_lock(&ar->conf_mutex);
+ nss = max_t(u32, 1, nss);
+ nss = min(nss, max(ath10k_mac_max_ht_nss(ht_mcs_mask),
+ ath10k_mac_max_vht_nss(vht_mcs_mask)));
+
if (changed & IEEE80211_RC_BW_CHANGED) {
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
sta->addr, bw);
@@ -4011,14 +4987,14 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
mutex_unlock(&ar->conf_mutex);
}
-static int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif)
+static int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif,
+ struct ieee80211_sta *sta)
{
struct ath10k *ar = arvif->ar;
lockdep_assert_held(&ar->conf_mutex);
- if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
- arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
+ if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
return 0;
if (ar->num_stations >= ar->max_num_stations)
@@ -4029,19 +5005,72 @@ static int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif)
return 0;
}
-static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif)
+static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif,
+ struct ieee80211_sta *sta)
{
struct ath10k *ar = arvif->ar;
lockdep_assert_held(&ar->conf_mutex);
- if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
- arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
+ if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
return;
ar->num_stations--;
}
+struct ath10k_mac_tdls_iter_data {
+ u32 num_tdls_stations;
+ struct ieee80211_vif *curr_vif;
+};
+
+static void ath10k_mac_tdls_vif_stations_count_iter(void *data,
+ struct ieee80211_sta *sta)
+{
+ struct ath10k_mac_tdls_iter_data *iter_data = data;
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ieee80211_vif *sta_vif = arsta->arvif->vif;
+
+ if (sta->tdls && sta_vif == iter_data->curr_vif)
+ iter_data->num_tdls_stations++;
+}
+
+static int ath10k_mac_tdls_vif_stations_count(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct ath10k_mac_tdls_iter_data data = {};
+
+ data.curr_vif = vif;
+
+ ieee80211_iterate_stations_atomic(hw,
+ ath10k_mac_tdls_vif_stations_count_iter,
+ &data);
+ return data.num_tdls_stations;
+}
+
+static void ath10k_mac_tdls_vifs_count_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ int *num_tdls_vifs = data;
+
+ if (vif->type != NL80211_IFTYPE_STATION)
+ return;
+
+ if (ath10k_mac_tdls_vif_stations_count(arvif->ar->hw, vif) > 0)
+ (*num_tdls_vifs)++;
+}
+
+static int ath10k_mac_tdls_vifs_count(struct ieee80211_hw *hw)
+{
+ int num_tdls_vifs = 0;
+
+ ieee80211_iterate_active_interfaces_atomic(hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ ath10k_mac_tdls_vifs_count_iter,
+ &num_tdls_vifs);
+ return num_tdls_vifs;
+}
+
static int ath10k_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -4072,41 +5101,80 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
/*
* New station addition.
*/
+ enum wmi_peer_type peer_type = WMI_PEER_TYPE_DEFAULT;
+ u32 num_tdls_stations;
+ u32 num_tdls_vifs;
+
ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d\n",
arvif->vdev_id, sta->addr,
ar->num_stations + 1, ar->max_num_stations,
ar->num_peers + 1, ar->max_num_peers);
- ret = ath10k_mac_inc_num_stations(arvif);
+ ret = ath10k_mac_inc_num_stations(arvif, sta);
if (ret) {
ath10k_warn(ar, "refusing to associate station: too many connected already (%d)\n",
ar->max_num_stations);
goto exit;
}
- ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
+ if (sta->tdls)
+ peer_type = WMI_PEER_TYPE_TDLS;
+
+ ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr,
+ peer_type);
if (ret) {
ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
sta->addr, arvif->vdev_id, ret);
- ath10k_mac_dec_num_stations(arvif);
+ ath10k_mac_dec_num_stations(arvif, sta);
+ goto exit;
+ }
+
+ if (!sta->tdls)
+ goto exit;
+
+ num_tdls_stations = ath10k_mac_tdls_vif_stations_count(hw, vif);
+ num_tdls_vifs = ath10k_mac_tdls_vifs_count(hw);
+
+ if (num_tdls_vifs >= ar->max_num_tdls_vdevs &&
+ num_tdls_stations == 0) {
+ ath10k_warn(ar, "vdev %i exceeded maximum number of tdls vdevs %i\n",
+ arvif->vdev_id, ar->max_num_tdls_vdevs);
+ ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
+ ath10k_mac_dec_num_stations(arvif, sta);
+ ret = -ENOBUFS;
goto exit;
}
- if (vif->type == NL80211_IFTYPE_STATION) {
- WARN_ON(arvif->is_started);
+ if (num_tdls_stations == 0) {
+ /* This is the first tdls peer in current vif */
+ enum wmi_tdls_state state = WMI_TDLS_ENABLE_ACTIVE;
- ret = ath10k_vdev_start(arvif);
+ ret = ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id,
+ state);
if (ret) {
- ath10k_warn(ar, "failed to start vdev %i: %d\n",
+ ath10k_warn(ar, "failed to update fw tdls state on vdev %i: %i\n",
arvif->vdev_id, ret);
- WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id,
- sta->addr));
- ath10k_mac_dec_num_stations(arvif);
+ ath10k_peer_delete(ar, arvif->vdev_id,
+ sta->addr);
+ ath10k_mac_dec_num_stations(arvif, sta);
goto exit;
}
+ }
- arvif->is_started = true;
+ ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, sta,
+ WMI_TDLS_PEER_STATE_PEERING);
+ if (ret) {
+ ath10k_warn(ar,
+ "failed to update tdls peer %pM for vdev %d when adding a new sta: %i\n",
+ sta->addr, arvif->vdev_id, ret);
+ ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
+ ath10k_mac_dec_num_stations(arvif, sta);
+
+ if (num_tdls_stations != 0)
+ goto exit;
+ ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id,
+ WMI_TDLS_DISABLE);
}
} else if ((old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_NOTEXIST)) {
@@ -4117,23 +5185,26 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
"mac vdev %d peer delete %pM (sta gone)\n",
arvif->vdev_id, sta->addr);
- if (vif->type == NL80211_IFTYPE_STATION) {
- WARN_ON(!arvif->is_started);
-
- ret = ath10k_vdev_stop(arvif);
- if (ret)
- ath10k_warn(ar, "failed to stop vdev %i: %d\n",
- arvif->vdev_id, ret);
-
- arvif->is_started = false;
- }
-
ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
if (ret)
ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
sta->addr, arvif->vdev_id, ret);
- ath10k_mac_dec_num_stations(arvif);
+ ath10k_mac_dec_num_stations(arvif, sta);
+
+ if (!sta->tdls)
+ goto exit;
+
+ if (ath10k_mac_tdls_vif_stations_count(hw, vif))
+ goto exit;
+
+ /* This was the last tdls peer in current vif */
+ ret = ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id,
+ WMI_TDLS_DISABLE);
+ if (ret) {
+ ath10k_warn(ar, "failed to update fw tdls state on vdev %i: %i\n",
+ arvif->vdev_id, ret);
+ }
} else if (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_ASSOC &&
(vif->type == NL80211_IFTYPE_AP ||
@@ -4149,9 +5220,30 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
} else if (old_state == IEEE80211_STA_ASSOC &&
- new_state == IEEE80211_STA_AUTH &&
- (vif->type == NL80211_IFTYPE_AP ||
- vif->type == NL80211_IFTYPE_ADHOC)) {
+ new_state == IEEE80211_STA_AUTHORIZED &&
+ sta->tdls) {
+ /*
+ * Tdls station authorized.
+ */
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac tdls sta %pM authorized\n",
+ sta->addr);
+
+ ret = ath10k_station_assoc(ar, vif, sta, false);
+ if (ret) {
+ ath10k_warn(ar, "failed to associate tdls station %pM for vdev %i: %i\n",
+ sta->addr, arvif->vdev_id, ret);
+ goto exit;
+ }
+
+ ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, sta,
+ WMI_TDLS_PEER_STATE_CONNECTED);
+ if (ret)
+ ath10k_warn(ar, "failed to update tdls peer %pM for vdev %i: %i\n",
+ sta->addr, arvif->vdev_id, ret);
+ } else if (old_state == IEEE80211_STA_ASSOC &&
+ new_state == IEEE80211_STA_AUTH &&
+ (vif->type == NL80211_IFTYPE_AP ||
+ vif->type == NL80211_IFTYPE_ADHOC)) {
/*
* Disassociation.
*/
@@ -4356,6 +5448,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct wmi_start_scan_arg arg;
int ret = 0;
+ u32 scan_time_msec;
mutex_lock(&ar->conf_mutex);
@@ -4382,7 +5475,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
if (ret)
goto exit;
- duration = max(duration, WMI_SCAN_CHAN_MIN_TIME_MSEC);
+ scan_time_msec = ar->hw->wiphy->max_remain_on_channel_duration * 2;
memset(&arg, 0, sizeof(arg));
ath10k_wmi_start_scan_init(ar, &arg);
@@ -4390,11 +5483,12 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
arg.scan_id = ATH10K_SCAN_ID;
arg.n_channels = 1;
arg.channels[0] = chan->center_freq;
- arg.dwell_time_active = duration;
- arg.dwell_time_passive = duration;
- arg.max_scan_time = 2 * duration;
+ arg.dwell_time_active = scan_time_msec;
+ arg.dwell_time_passive = scan_time_msec;
+ arg.max_scan_time = scan_time_msec;
arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE;
arg.scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ;
+ arg.burst_duration_ms = duration;
ret = ath10k_start_scan(ar, &arg);
if (ret) {
@@ -4417,6 +5511,9 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
goto exit;
}
+ ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
+ msecs_to_jiffies(duration));
+
ret = 0;
exit:
mutex_unlock(&ar->conf_mutex);
@@ -4512,70 +5609,6 @@ static int ath10k_tx_last_beacon(struct ieee80211_hw *hw)
return 1;
}
-#ifdef CONFIG_PM
-static int ath10k_suspend(struct ieee80211_hw *hw,
- struct cfg80211_wowlan *wowlan)
-{
- struct ath10k *ar = hw->priv;
- int ret;
-
- mutex_lock(&ar->conf_mutex);
-
- ret = ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND);
- if (ret) {
- if (ret == -ETIMEDOUT)
- goto resume;
- ret = 1;
- goto exit;
- }
-
- ret = ath10k_hif_suspend(ar);
- if (ret) {
- ath10k_warn(ar, "failed to suspend hif: %d\n", ret);
- goto resume;
- }
-
- ret = 0;
- goto exit;
-resume:
- ret = ath10k_wmi_pdev_resume_target(ar);
- if (ret)
- ath10k_warn(ar, "failed to resume target: %d\n", ret);
-
- ret = 1;
-exit:
- mutex_unlock(&ar->conf_mutex);
- return ret;
-}
-
-static int ath10k_resume(struct ieee80211_hw *hw)
-{
- struct ath10k *ar = hw->priv;
- int ret;
-
- mutex_lock(&ar->conf_mutex);
-
- ret = ath10k_hif_resume(ar);
- if (ret) {
- ath10k_warn(ar, "failed to resume hif: %d\n", ret);
- ret = 1;
- goto exit;
- }
-
- ret = ath10k_wmi_pdev_resume_target(ar);
- if (ret) {
- ath10k_warn(ar, "failed to resume target: %d\n", ret);
- ret = 1;
- goto exit;
- }
-
- ret = 0;
-exit:
- mutex_unlock(&ar->conf_mutex);
- return ret;
-}
-#endif
-
static void ath10k_reconfig_complete(struct ieee80211_hw *hw,
enum ieee80211_reconfig_type reconfig_type)
{
@@ -4635,343 +5668,286 @@ exit:
return ret;
}
-/* Helper table for legacy fixed_rate/bitrate_mask */
-static const u8 cck_ofdm_rate[] = {
- /* CCK */
- 3, /* 1Mbps */
- 2, /* 2Mbps */
- 1, /* 5.5Mbps */
- 0, /* 11Mbps */
- /* OFDM */
- 3, /* 6Mbps */
- 7, /* 9Mbps */
- 2, /* 12Mbps */
- 6, /* 18Mbps */
- 1, /* 24Mbps */
- 5, /* 36Mbps */
- 0, /* 48Mbps */
- 4, /* 54Mbps */
-};
-
-/* Check if only one bit set */
-static int ath10k_check_single_mask(u32 mask)
-{
- int bit;
-
- bit = ffs(mask);
- if (!bit)
- return 0;
-
- mask &= ~BIT(bit - 1);
- if (mask)
- return 2;
-
- return 1;
-}
-
static bool
-ath10k_default_bitrate_mask(struct ath10k *ar,
- enum ieee80211_band band,
- const struct cfg80211_bitrate_mask *mask)
+ath10k_mac_bitrate_mask_has_single_rate(struct ath10k *ar,
+ enum ieee80211_band band,
+ const struct cfg80211_bitrate_mask *mask)
{
- u32 legacy = 0x00ff;
- u8 ht = 0xff, i;
- u16 vht = 0x3ff;
- u16 nrf = ar->num_rf_chains;
-
- if (ar->cfg_tx_chainmask)
- nrf = get_nss_from_chainmask(ar->cfg_tx_chainmask);
-
- switch (band) {
- case IEEE80211_BAND_2GHZ:
- legacy = 0x00fff;
- vht = 0;
- break;
- case IEEE80211_BAND_5GHZ:
- break;
- default:
- return false;
- }
+ int num_rates = 0;
+ int i;
- if (mask->control[band].legacy != legacy)
- return false;
+ num_rates += hweight32(mask->control[band].legacy);
- for (i = 0; i < nrf; i++)
- if (mask->control[band].ht_mcs[i] != ht)
- return false;
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++)
+ num_rates += hweight8(mask->control[band].ht_mcs[i]);
- for (i = 0; i < nrf; i++)
- if (mask->control[band].vht_mcs[i] != vht)
- return false;
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++)
+ num_rates += hweight16(mask->control[band].vht_mcs[i]);
- return true;
+ return num_rates == 1;
}
static bool
-ath10k_bitrate_mask_nss(const struct cfg80211_bitrate_mask *mask,
- enum ieee80211_band band,
- u8 *fixed_nss)
-{
- int ht_nss = 0, vht_nss = 0, i;
+ath10k_mac_bitrate_mask_get_single_nss(struct ath10k *ar,
+ enum ieee80211_band band,
+ const struct cfg80211_bitrate_mask *mask,
+ int *nss)
+{
+ struct ieee80211_supported_band *sband = &ar->mac.sbands[band];
+ u16 vht_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
+ u8 ht_nss_mask = 0;
+ u8 vht_nss_mask = 0;
+ int i;
- /* check legacy */
- if (ath10k_check_single_mask(mask->control[band].legacy))
+ if (mask->control[band].legacy)
return false;
- /* check HT */
- for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
- if (mask->control[band].ht_mcs[i] == 0xff)
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) {
+ if (mask->control[band].ht_mcs[i] == 0)
continue;
- else if (mask->control[band].ht_mcs[i] == 0x00)
- break;
-
- return false;
+ else if (mask->control[band].ht_mcs[i] ==
+ sband->ht_cap.mcs.rx_mask[i])
+ ht_nss_mask |= BIT(i);
+ else
+ return false;
}
- ht_nss = i;
-
- /* check VHT */
- for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
- if (mask->control[band].vht_mcs[i] == 0x03ff)
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
+ if (mask->control[band].vht_mcs[i] == 0)
continue;
- else if (mask->control[band].vht_mcs[i] == 0x0000)
- break;
-
- return false;
+ else if (mask->control[band].vht_mcs[i] ==
+ ath10k_mac_get_max_vht_mcs_map(vht_mcs_map, i))
+ vht_nss_mask |= BIT(i);
+ else
+ return false;
}
- vht_nss = i;
-
- if (ht_nss > 0 && vht_nss > 0)
- return false;
-
- if (ht_nss)
- *fixed_nss = ht_nss;
- else if (vht_nss)
- *fixed_nss = vht_nss;
- else
- return false;
-
- return true;
-}
-
-static bool
-ath10k_bitrate_mask_correct(const struct cfg80211_bitrate_mask *mask,
- enum ieee80211_band band,
- enum wmi_rate_preamble *preamble)
-{
- int legacy = 0, ht = 0, vht = 0, i;
-
- *preamble = WMI_RATE_PREAMBLE_OFDM;
-
- /* check legacy */
- legacy = ath10k_check_single_mask(mask->control[band].legacy);
- if (legacy > 1)
- return false;
-
- /* check HT */
- for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
- ht += ath10k_check_single_mask(mask->control[band].ht_mcs[i]);
- if (ht > 1)
+ if (ht_nss_mask != vht_nss_mask)
return false;
- /* check VHT */
- for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
- vht += ath10k_check_single_mask(mask->control[band].vht_mcs[i]);
- if (vht > 1)
+ if (ht_nss_mask == 0)
return false;
- /* Currently we support only one fixed_rate */
- if ((legacy + ht + vht) != 1)
+ if (BIT(fls(ht_nss_mask)) - 1 != ht_nss_mask)
return false;
- if (ht)
- *preamble = WMI_RATE_PREAMBLE_HT;
- else if (vht)
- *preamble = WMI_RATE_PREAMBLE_VHT;
+ *nss = fls(ht_nss_mask);
return true;
}
-static bool
-ath10k_bitrate_mask_rate(struct ath10k *ar,
- const struct cfg80211_bitrate_mask *mask,
- enum ieee80211_band band,
- u8 *fixed_rate,
- u8 *fixed_nss)
+static int
+ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar,
+ enum ieee80211_band band,
+ const struct cfg80211_bitrate_mask *mask,
+ u8 *rate, u8 *nss)
{
- u8 rate = 0, pream = 0, nss = 0, i;
- enum wmi_rate_preamble preamble;
-
- /* Check if single rate correct */
- if (!ath10k_bitrate_mask_correct(mask, band, &preamble))
- return false;
-
- pream = preamble;
-
- switch (preamble) {
- case WMI_RATE_PREAMBLE_CCK:
- case WMI_RATE_PREAMBLE_OFDM:
- i = ffs(mask->control[band].legacy) - 1;
-
- if (band == IEEE80211_BAND_2GHZ && i < 4)
- pream = WMI_RATE_PREAMBLE_CCK;
-
- if (band == IEEE80211_BAND_5GHZ)
- i += 4;
-
- if (i >= ARRAY_SIZE(cck_ofdm_rate))
- return false;
+ struct ieee80211_supported_band *sband = &ar->mac.sbands[band];
+ int rate_idx;
+ int i;
+ u16 bitrate;
+ u8 preamble;
+ u8 hw_rate;
- rate = cck_ofdm_rate[i];
- break;
- case WMI_RATE_PREAMBLE_HT:
- for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
- if (mask->control[band].ht_mcs[i])
- break;
+ if (hweight32(mask->control[band].legacy) == 1) {
+ rate_idx = ffs(mask->control[band].legacy) - 1;
- if (i == IEEE80211_HT_MCS_MASK_LEN)
- return false;
+ hw_rate = sband->bitrates[rate_idx].hw_value;
+ bitrate = sband->bitrates[rate_idx].bitrate;
- rate = ffs(mask->control[band].ht_mcs[i]) - 1;
- nss = i;
- break;
- case WMI_RATE_PREAMBLE_VHT:
- for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
- if (mask->control[band].vht_mcs[i])
- break;
+ if (ath10k_mac_bitrate_is_cck(bitrate))
+ preamble = WMI_RATE_PREAMBLE_CCK;
+ else
+ preamble = WMI_RATE_PREAMBLE_OFDM;
- if (i == NL80211_VHT_NSS_MAX)
- return false;
+ *nss = 1;
+ *rate = preamble << 6 |
+ (*nss - 1) << 4 |
+ hw_rate << 0;
- rate = ffs(mask->control[band].vht_mcs[i]) - 1;
- nss = i;
- break;
+ return 0;
}
- *fixed_nss = nss + 1;
- nss <<= 4;
- pream <<= 6;
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) {
+ if (hweight8(mask->control[band].ht_mcs[i]) == 1) {
+ *nss = i + 1;
+ *rate = WMI_RATE_PREAMBLE_HT << 6 |
+ (*nss - 1) << 4 |
+ (ffs(mask->control[band].ht_mcs[i]) - 1);
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n",
- pream, nss, rate);
+ return 0;
+ }
+ }
- *fixed_rate = pream | nss | rate;
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
+ if (hweight16(mask->control[band].vht_mcs[i]) == 1) {
+ *nss = i + 1;
+ *rate = WMI_RATE_PREAMBLE_VHT << 6 |
+ (*nss - 1) << 4 |
+ (ffs(mask->control[band].vht_mcs[i]) - 1);
- return true;
-}
-
-static bool ath10k_get_fixed_rate_nss(struct ath10k *ar,
- const struct cfg80211_bitrate_mask *mask,
- enum ieee80211_band band,
- u8 *fixed_rate,
- u8 *fixed_nss)
-{
- /* First check full NSS mask, if we can simply limit NSS */
- if (ath10k_bitrate_mask_nss(mask, band, fixed_nss))
- return true;
+ return 0;
+ }
+ }
- /* Next Check single rate is set */
- return ath10k_bitrate_mask_rate(ar, mask, band, fixed_rate, fixed_nss);
+ return -EINVAL;
}
-static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
- u8 fixed_rate,
- u8 fixed_nss,
- u8 force_sgi)
+static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
+ u8 rate, u8 nss, u8 sgi)
{
struct ath10k *ar = arvif->ar;
u32 vdev_param;
- int ret = 0;
-
- mutex_lock(&ar->conf_mutex);
-
- if (arvif->fixed_rate == fixed_rate &&
- arvif->fixed_nss == fixed_nss &&
- arvif->force_sgi == force_sgi)
- goto exit;
+ int ret;
- if (fixed_rate == WMI_FIXED_RATE_NONE)
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
+ lockdep_assert_held(&ar->conf_mutex);
- if (force_sgi)
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac force sgi\n");
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02hhx nss %hhu sgi %hhu\n",
+ arvif->vdev_id, rate, nss, sgi);
vdev_param = ar->wmi.vdev_param->fixed_rate;
- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
- vdev_param, fixed_rate);
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, rate);
if (ret) {
ath10k_warn(ar, "failed to set fixed rate param 0x%02x: %d\n",
- fixed_rate, ret);
- ret = -EINVAL;
- goto exit;
+ rate, ret);
+ return ret;
}
- arvif->fixed_rate = fixed_rate;
-
vdev_param = ar->wmi.vdev_param->nss;
- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
- vdev_param, fixed_nss);
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, nss);
+ if (ret) {
+ ath10k_warn(ar, "failed to set nss param %d: %d\n", nss, ret);
+ return ret;
+ }
+ vdev_param = ar->wmi.vdev_param->sgi;
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, sgi);
if (ret) {
- ath10k_warn(ar, "failed to set fixed nss param %d: %d\n",
- fixed_nss, ret);
- ret = -EINVAL;
- goto exit;
+ ath10k_warn(ar, "failed to set sgi param %d: %d\n", sgi, ret);
+ return ret;
}
- arvif->fixed_nss = fixed_nss;
+ return 0;
+}
- vdev_param = ar->wmi.vdev_param->sgi;
- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
- force_sgi);
+static bool
+ath10k_mac_can_set_bitrate_mask(struct ath10k *ar,
+ enum ieee80211_band band,
+ const struct cfg80211_bitrate_mask *mask)
+{
+ int i;
+ u16 vht_mcs;
- if (ret) {
- ath10k_warn(ar, "failed to set sgi param %d: %d\n",
- force_sgi, ret);
- ret = -EINVAL;
- goto exit;
+ /* Due to firmware limitation in WMI_PEER_ASSOC_CMDID it is impossible
+ * to express all VHT MCS rate masks. Effectively only the following
+ * ranges can be used: none, 0-7, 0-8 and 0-9.
+ */
+ for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
+ vht_mcs = mask->control[band].vht_mcs[i];
+
+ switch (vht_mcs) {
+ case 0:
+ case BIT(8) - 1:
+ case BIT(9) - 1:
+ case BIT(10) - 1:
+ break;
+ default:
+ ath10k_warn(ar, "refusing bitrate mask with missing 0-7 VHT MCS rates\n");
+ return false;
+ }
}
- arvif->force_sgi = force_sgi;
+ return true;
+}
-exit:
- mutex_unlock(&ar->conf_mutex);
- return ret;
+static void ath10k_mac_set_bitrate_mask_iter(void *data,
+ struct ieee80211_sta *sta)
+{
+ struct ath10k_vif *arvif = data;
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ath10k *ar = arvif->ar;
+
+ if (arsta->arvif != arvif)
+ return;
+
+ spin_lock_bh(&ar->data_lock);
+ arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED;
+ spin_unlock_bh(&ar->data_lock);
+
+ ieee80211_queue_work(ar->hw, &arsta->update_wk);
}
-static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- const struct cfg80211_bitrate_mask *mask)
+static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ const struct cfg80211_bitrate_mask *mask)
{
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct cfg80211_chan_def def;
struct ath10k *ar = arvif->ar;
- enum ieee80211_band band = ar->hw->conf.chandef.chan->band;
- u8 fixed_rate = WMI_FIXED_RATE_NONE;
- u8 fixed_nss = ar->num_rf_chains;
- u8 force_sgi;
+ enum ieee80211_band band;
+ const u8 *ht_mcs_mask;
+ const u16 *vht_mcs_mask;
+ u8 rate;
+ u8 nss;
+ u8 sgi;
+ int single_nss;
+ int ret;
- if (ar->cfg_tx_chainmask)
- fixed_nss = get_nss_from_chainmask(ar->cfg_tx_chainmask);
+ if (ath10k_mac_vif_chan(vif, &def))
+ return -EPERM;
+
+ band = def.chan->band;
+ ht_mcs_mask = mask->control[band].ht_mcs;
+ vht_mcs_mask = mask->control[band].vht_mcs;
- force_sgi = mask->control[band].gi;
- if (force_sgi == NL80211_TXRATE_FORCE_LGI)
+ sgi = mask->control[band].gi;
+ if (sgi == NL80211_TXRATE_FORCE_LGI)
return -EINVAL;
- if (!ath10k_default_bitrate_mask(ar, band, mask)) {
- if (!ath10k_get_fixed_rate_nss(ar, mask, band,
- &fixed_rate,
- &fixed_nss))
+ if (ath10k_mac_bitrate_mask_has_single_rate(ar, band, mask)) {
+ ret = ath10k_mac_bitrate_mask_get_single_rate(ar, band, mask,
+ &rate, &nss);
+ if (ret) {
+ ath10k_warn(ar, "failed to get single rate for vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+ } else if (ath10k_mac_bitrate_mask_get_single_nss(ar, band, mask,
+ &single_nss)) {
+ rate = WMI_FIXED_RATE_NONE;
+ nss = single_nss;
+ } else {
+ rate = WMI_FIXED_RATE_NONE;
+ nss = min(ar->num_rf_chains,
+ max(ath10k_mac_max_ht_nss(ht_mcs_mask),
+ ath10k_mac_max_vht_nss(vht_mcs_mask)));
+
+ if (!ath10k_mac_can_set_bitrate_mask(ar, band, mask))
return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+
+ arvif->bitrate_mask = *mask;
+ ieee80211_iterate_stations_atomic(ar->hw,
+ ath10k_mac_set_bitrate_mask_iter,
+ arvif);
+
+ mutex_unlock(&ar->conf_mutex);
}
- if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) {
- ath10k_warn(ar, "failed to force SGI usage for default rate settings\n");
- return -EINVAL;
+ mutex_lock(&ar->conf_mutex);
+
+ ret = ath10k_mac_set_fixed_rate_params(arvif, rate, nss, sgi);
+ if (ret) {
+ ath10k_warn(ar, "failed to set fixed rate params on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ goto exit;
}
- return ath10k_set_fixed_rate_param(arvif, fixed_rate,
- fixed_nss, force_sgi);
+exit:
+ mutex_unlock(&ar->conf_mutex);
+
+ return ret;
}
static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
@@ -5090,6 +6066,317 @@ static int ath10k_ampdu_action(struct ieee80211_hw *hw,
return -EINVAL;
}
+static void
+ath10k_mac_update_rx_channel(struct ath10k *ar,
+ struct ieee80211_chanctx_conf *ctx,
+ struct ieee80211_vif_chanctx_switch *vifs,
+ int n_vifs)
+{
+ struct cfg80211_chan_def *def = NULL;
+
+ /* Both locks are required because ar->rx_channel is modified. This
+ * allows readers to hold either lock.
+ */
+ lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_held(&ar->data_lock);
+
+ WARN_ON(ctx && vifs);
+ WARN_ON(vifs && n_vifs != 1);
+
+ /* FIXME: Sort of an optimization and a workaround. Peers and vifs are
+ * on a linked list now. Doing a lookup peer -> vif -> chanctx for each
+ * ppdu on Rx may reduce performance on low-end systems. It should be
+ * possible to make tables/hashmaps to speed the lookup up (be vary of
+ * cpu data cache lines though regarding sizes) but to keep the initial
+ * implementation simple and less intrusive fallback to the slow lookup
+ * only for multi-channel cases. Single-channel cases will remain to
+ * use the old channel derival and thus performance should not be
+ * affected much.
+ */
+ rcu_read_lock();
+ if (!ctx && ath10k_mac_num_chanctxs(ar) == 1) {
+ ieee80211_iter_chan_contexts_atomic(ar->hw,
+ ath10k_mac_get_any_chandef_iter,
+ &def);
+
+ if (vifs)
+ def = &vifs[0].new_ctx->def;
+
+ ar->rx_channel = def->chan;
+ } else if (ctx && ath10k_mac_num_chanctxs(ar) == 0) {
+ ar->rx_channel = ctx->def.chan;
+ } else {
+ ar->rx_channel = NULL;
+ }
+ rcu_read_unlock();
+}
+
+static int
+ath10k_mac_op_add_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct ath10k *ar = hw->priv;
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac chanctx add freq %hu width %d ptr %p\n",
+ ctx->def.chan->center_freq, ctx->def.width, ctx);
+
+ mutex_lock(&ar->conf_mutex);
+
+ spin_lock_bh(&ar->data_lock);
+ ath10k_mac_update_rx_channel(ar, ctx, NULL, 0);
+ spin_unlock_bh(&ar->data_lock);
+
+ ath10k_recalc_radar_detection(ar);
+ ath10k_monitor_recalc(ar);
+
+ mutex_unlock(&ar->conf_mutex);
+
+ return 0;
+}
+
+static void
+ath10k_mac_op_remove_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct ath10k *ar = hw->priv;
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac chanctx remove freq %hu width %d ptr %p\n",
+ ctx->def.chan->center_freq, ctx->def.width, ctx);
+
+ mutex_lock(&ar->conf_mutex);
+
+ spin_lock_bh(&ar->data_lock);
+ ath10k_mac_update_rx_channel(ar, NULL, NULL, 0);
+ spin_unlock_bh(&ar->data_lock);
+
+ ath10k_recalc_radar_detection(ar);
+ ath10k_monitor_recalc(ar);
+
+ mutex_unlock(&ar->conf_mutex);
+}
+
+static void
+ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx,
+ u32 changed)
+{
+ struct ath10k *ar = hw->priv;
+
+ mutex_lock(&ar->conf_mutex);
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac chanctx change freq %hu width %d ptr %p changed %x\n",
+ ctx->def.chan->center_freq, ctx->def.width, ctx, changed);
+
+ /* This shouldn't really happen because channel switching should use
+ * switch_vif_chanctx().
+ */
+ if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL))
+ goto unlock;
+
+ ath10k_recalc_radar_detection(ar);
+
+ /* FIXME: How to configure Rx chains properly? */
+
+ /* No other actions are actually necessary. Firmware maintains channel
+ * definitions per vdev internally and there's no host-side channel
+ * context abstraction to configure, e.g. channel width.
+ */
+
+unlock:
+ mutex_unlock(&ar->conf_mutex);
+}
+
+static int
+ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct ath10k *ar = hw->priv;
+ struct ath10k_vif *arvif = (void *)vif->drv_priv;
+ int ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac chanctx assign ptr %p vdev_id %i\n",
+ ctx, arvif->vdev_id);
+
+ if (WARN_ON(arvif->is_started)) {
+ mutex_unlock(&ar->conf_mutex);
+ return -EBUSY;
+ }
+
+ ret = ath10k_vdev_start(arvif, &ctx->def);
+ if (ret) {
+ ath10k_warn(ar, "failed to start vdev %i addr %pM on freq %d: %d\n",
+ arvif->vdev_id, vif->addr,
+ ctx->def.chan->center_freq, ret);
+ goto err;
+ }
+
+ arvif->is_started = true;
+
+ if (vif->type == NL80211_IFTYPE_MONITOR) {
+ ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, 0, vif->addr);
+ if (ret) {
+ ath10k_warn(ar, "failed to up monitor vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ goto err_stop;
+ }
+
+ arvif->is_up = true;
+ }
+
+ mutex_unlock(&ar->conf_mutex);
+ return 0;
+
+err_stop:
+ ath10k_vdev_stop(arvif);
+ arvif->is_started = false;
+
+err:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static void
+ath10k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct ath10k *ar = hw->priv;
+ struct ath10k_vif *arvif = (void *)vif->drv_priv;
+ int ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac chanctx unassign ptr %p vdev_id %i\n",
+ ctx, arvif->vdev_id);
+
+ WARN_ON(!arvif->is_started);
+
+ if (vif->type == NL80211_IFTYPE_MONITOR) {
+ WARN_ON(!arvif->is_up);
+
+ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
+ if (ret)
+ ath10k_warn(ar, "failed to down monitor vdev %i: %d\n",
+ arvif->vdev_id, ret);
+
+ arvif->is_up = false;
+ }
+
+ ret = ath10k_vdev_stop(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to stop vdev %i: %d\n",
+ arvif->vdev_id, ret);
+
+ arvif->is_started = false;
+
+ mutex_unlock(&ar->conf_mutex);
+}
+
+static int
+ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif_chanctx_switch *vifs,
+ int n_vifs,
+ enum ieee80211_chanctx_switch_mode mode)
+{
+ struct ath10k *ar = hw->priv;
+ struct ath10k_vif *arvif;
+ int ret;
+ int i;
+
+ mutex_lock(&ar->conf_mutex);
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac chanctx switch n_vifs %d mode %d\n",
+ n_vifs, mode);
+
+ /* First stop monitor interface. Some FW versions crash if there's a
+ * lone monitor interface.
+ */
+ if (ar->monitor_started)
+ ath10k_monitor_stop(ar);
+
+ for (i = 0; i < n_vifs; i++) {
+ arvif = ath10k_vif_to_arvif(vifs[i].vif);
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d\n",
+ arvif->vdev_id,
+ vifs[i].old_ctx->def.chan->center_freq,
+ vifs[i].new_ctx->def.chan->center_freq,
+ vifs[i].old_ctx->def.width,
+ vifs[i].new_ctx->def.width);
+
+ if (WARN_ON(!arvif->is_started))
+ continue;
+
+ if (WARN_ON(!arvif->is_up))
+ continue;
+
+ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
+ if (ret) {
+ ath10k_warn(ar, "failed to down vdev %d: %d\n",
+ arvif->vdev_id, ret);
+ continue;
+ }
+ }
+
+ /* All relevant vdevs are downed and associated channel resources
+ * should be available for the channel switch now.
+ */
+
+ spin_lock_bh(&ar->data_lock);
+ ath10k_mac_update_rx_channel(ar, NULL, vifs, n_vifs);
+ spin_unlock_bh(&ar->data_lock);
+
+ for (i = 0; i < n_vifs; i++) {
+ arvif = ath10k_vif_to_arvif(vifs[i].vif);
+
+ if (WARN_ON(!arvif->is_started))
+ continue;
+
+ if (WARN_ON(!arvif->is_up))
+ continue;
+
+ ret = ath10k_mac_setup_bcn_tmpl(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n",
+ ret);
+
+ ret = ath10k_mac_setup_prb_tmpl(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n",
+ ret);
+
+ ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def);
+ if (ret) {
+ ath10k_warn(ar, "failed to restart vdev %d: %d\n",
+ arvif->vdev_id, ret);
+ continue;
+ }
+
+ ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
+ arvif->bssid);
+ if (ret) {
+ ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
+ arvif->vdev_id, ret);
+ continue;
+ }
+ }
+
+ ath10k_monitor_recalc(ar);
+
+ mutex_unlock(&ar->conf_mutex);
+ return 0;
+}
+
static const struct ieee80211_ops ath10k_ops = {
.tx = ath10k_tx,
.start = ath10k_start,
@@ -5114,31 +6401,31 @@ static const struct ieee80211_ops ath10k_ops = {
.get_antenna = ath10k_get_antenna,
.reconfig_complete = ath10k_reconfig_complete,
.get_survey = ath10k_get_survey,
- .set_bitrate_mask = ath10k_set_bitrate_mask,
+ .set_bitrate_mask = ath10k_mac_op_set_bitrate_mask,
.sta_rc_update = ath10k_sta_rc_update,
.get_tsf = ath10k_get_tsf,
.ampdu_action = ath10k_ampdu_action,
.get_et_sset_count = ath10k_debug_get_et_sset_count,
.get_et_stats = ath10k_debug_get_et_stats,
.get_et_strings = ath10k_debug_get_et_strings,
+ .add_chanctx = ath10k_mac_op_add_chanctx,
+ .remove_chanctx = ath10k_mac_op_remove_chanctx,
+ .change_chanctx = ath10k_mac_op_change_chanctx,
+ .assign_vif_chanctx = ath10k_mac_op_assign_vif_chanctx,
+ .unassign_vif_chanctx = ath10k_mac_op_unassign_vif_chanctx,
+ .switch_vif_chanctx = ath10k_mac_op_switch_vif_chanctx,
CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
#ifdef CONFIG_PM
- .suspend = ath10k_suspend,
- .resume = ath10k_resume,
+ .suspend = ath10k_wow_op_suspend,
+ .resume = ath10k_wow_op_resume,
#endif
#ifdef CONFIG_MAC80211_DEBUGFS
.sta_add_debugfs = ath10k_sta_add_debugfs,
#endif
};
-#define RATETAB_ENT(_rate, _rateid, _flags) { \
- .bitrate = (_rate), \
- .flags = (_flags), \
- .hw_value = (_rateid), \
-}
-
#define CHAN2G(_channel, _freq, _flags) { \
.band = IEEE80211_BAND_2GHZ, \
.hw_value = (_channel), \
@@ -5194,6 +6481,7 @@ static const struct ieee80211_channel ath10k_5ghz_channels[] = {
CHAN5G(132, 5660, 0),
CHAN5G(136, 5680, 0),
CHAN5G(140, 5700, 0),
+ CHAN5G(144, 5720, 0),
CHAN5G(149, 5745, 0),
CHAN5G(153, 5765, 0),
CHAN5G(157, 5785, 0),
@@ -5201,31 +6489,6 @@ static const struct ieee80211_channel ath10k_5ghz_channels[] = {
CHAN5G(165, 5825, 0),
};
-/* Note: Be careful if you re-order these. There is code which depends on this
- * ordering.
- */
-static struct ieee80211_rate ath10k_rates[] = {
- /* CCK */
- RATETAB_ENT(10, 0x82, 0),
- RATETAB_ENT(20, 0x84, 0),
- RATETAB_ENT(55, 0x8b, 0),
- RATETAB_ENT(110, 0x96, 0),
- /* OFDM */
- RATETAB_ENT(60, 0x0c, 0),
- RATETAB_ENT(90, 0x12, 0),
- RATETAB_ENT(120, 0x18, 0),
- RATETAB_ENT(180, 0x24, 0),
- RATETAB_ENT(240, 0x30, 0),
- RATETAB_ENT(360, 0x48, 0),
- RATETAB_ENT(480, 0x60, 0),
- RATETAB_ENT(540, 0x6c, 0),
-};
-
-#define ath10k_a_rates (ath10k_rates + 4)
-#define ath10k_a_rates_size (ARRAY_SIZE(ath10k_rates) - 4)
-#define ath10k_g_rates (ath10k_rates + 0)
-#define ath10k_g_rates_size (ARRAY_SIZE(ath10k_rates))
-
struct ath10k *ath10k_mac_create(size_t priv_size)
{
struct ieee80211_hw *hw;
@@ -5299,15 +6562,92 @@ static const struct ieee80211_iface_combination ath10k_10x_if_comb[] = {
},
};
+static const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = {
+ {
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
+ },
+};
+
+static const struct ieee80211_iface_limit ath10k_tlv_if_limit_ibss[] = {
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_STATION),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_ADHOC),
+ },
+};
+
+/* FIXME: This is not thouroughly tested. These combinations may over- or
+ * underestimate hw/fw capabilities.
+ */
+static struct ieee80211_iface_combination ath10k_tlv_if_comb[] = {
+ {
+ .limits = ath10k_tlv_if_limit,
+ .num_different_channels = 1,
+ .max_interfaces = 3,
+ .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit),
+ },
+ {
+ .limits = ath10k_tlv_if_limit_ibss,
+ .num_different_channels = 1,
+ .max_interfaces = 2,
+ .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit_ibss),
+ },
+};
+
+static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = {
+ {
+ .limits = ath10k_tlv_if_limit,
+ .num_different_channels = 2,
+ .max_interfaces = 3,
+ .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit),
+ },
+ {
+ .limits = ath10k_tlv_if_limit_ibss,
+ .num_different_channels = 1,
+ .max_interfaces = 2,
+ .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit_ibss),
+ },
+};
+
static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
{
struct ieee80211_sta_vht_cap vht_cap = {0};
u16 mcs_map;
+ u32 val;
int i;
vht_cap.vht_supported = 1;
vht_cap.cap = ar->vht_cap_info;
+ if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) {
+ val = ar->num_rf_chains - 1;
+ val <<= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
+ val &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
+
+ vht_cap.cap |= val;
+ }
+
+ if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
+ IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) {
+ val = ar->num_rf_chains - 1;
+ val <<= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
+ val &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
+
+ vht_cap.cap |= val;
+ }
+
mcs_map = 0;
for (i = 0; i < 8; i++) {
if (i < ar->num_rf_chains)
@@ -5438,6 +6778,10 @@ int ath10k_mac_register(struct ath10k *ar)
ht_cap = ath10k_get_ht_cap(ar);
vht_cap = ath10k_create_vht_cap(ar);
+ BUILD_BUG_ON((ARRAY_SIZE(ath10k_2ghz_channels) +
+ ARRAY_SIZE(ath10k_5ghz_channels)) !=
+ ATH10K_NUM_CHANS);
+
if (ar->phy_capability & WHAL_WLAN_11G_CAPABILITY) {
channels = kmemdup(ath10k_2ghz_channels,
sizeof(ath10k_2ghz_channels),
@@ -5492,24 +6836,31 @@ int ath10k_mac_register(struct ath10k *ar)
BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO);
- ar->hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_MFP_CAPABLE |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_HAS_RATE_CONTROL |
- IEEE80211_HW_AP_LINK_PS |
- IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_SW_CRYPTO_CONTROL;
+ ieee80211_hw_set(ar->hw, SIGNAL_DBM);
+ ieee80211_hw_set(ar->hw, SUPPORTS_PS);
+ ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(ar->hw, MFP_CAPABLE);
+ ieee80211_hw_set(ar->hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(ar->hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(ar->hw, AP_LINK_PS);
+ ieee80211_hw_set(ar->hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL);
+ ieee80211_hw_set(ar->hw, SUPPORT_FAST_XMIT);
+ ieee80211_hw_set(ar->hw, CONNECTION_MONITOR);
+ ieee80211_hw_set(ar->hw, SUPPORTS_PER_STA_GTK);
+ ieee80211_hw_set(ar->hw, WANT_MONITOR_VIF);
+ ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA);
+ ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
+ ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS)
ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS;
if (ar->ht_cap_info & WMI_HT_CAP_ENABLED) {
- ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
- ar->hw->flags |= IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
+ ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW);
}
ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID;
@@ -5533,6 +6884,9 @@ int ath10k_mac_register(struct ath10k *ar)
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
}
+ if (test_bit(WMI_SERVICE_TDLS, ar->wmi.svc_map))
+ ar->hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
+
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
ar->hw->wiphy->max_remain_on_channel_duration = 5000;
@@ -5540,20 +6894,46 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
+ ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations;
+
+ ret = ath10k_wow_init(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to init wow: %d\n", ret);
+ goto err_free;
+ }
+
/*
* on LL hardware queues are managed entirely by the FW
* so we only advertise to mac we can do the queues thing
*/
- ar->hw->queues = 4;
+ ar->hw->queues = IEEE80211_MAX_QUEUES;
+
+ /* vdev_ids are used as hw queue numbers. Make sure offchan tx queue is
+ * something that vdev_ids can't reach so that we don't stop the queue
+ * accidentally.
+ */
+ ar->hw->offchannel_tx_hw_queue = IEEE80211_MAX_QUEUES - 1;
switch (ar->wmi.op_version) {
case ATH10K_FW_WMI_OP_VERSION_MAIN:
- case ATH10K_FW_WMI_OP_VERSION_TLV:
ar->hw->wiphy->iface_combinations = ath10k_if_comb;
ar->hw->wiphy->n_iface_combinations =
ARRAY_SIZE(ath10k_if_comb);
ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
break;
+ case ATH10K_FW_WMI_OP_VERSION_TLV:
+ if (test_bit(WMI_SERVICE_ADAPTIVE_OCS, ar->wmi.svc_map)) {
+ ar->hw->wiphy->iface_combinations =
+ ath10k_tlv_qcs_if_comb;
+ ar->hw->wiphy->n_iface_combinations =
+ ARRAY_SIZE(ath10k_tlv_qcs_if_comb);
+ } else {
+ ar->hw->wiphy->iface_combinations = ath10k_tlv_if_comb;
+ ar->hw->wiphy->n_iface_combinations =
+ ARRAY_SIZE(ath10k_tlv_if_comb);
+ }
+ ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
+ break;
case ATH10K_FW_WMI_OP_VERSION_10_1:
case ATH10K_FW_WMI_OP_VERSION_10_2:
case ATH10K_FW_WMI_OP_VERSION_10_2_4:
diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
index 68296117d203..b291f063705c 100644
--- a/drivers/net/wireless/ath/ath10k/mac.h
+++ b/drivers/net/wireless/ath/ath10k/mac.h
@@ -23,11 +23,22 @@
#define WEP_KEYID_SHIFT 6
+enum wmi_tlv_tx_pause_id;
+enum wmi_tlv_tx_pause_action;
+
struct ath10k_generic_iter {
struct ath10k *ar;
int ret;
};
+struct rfc1042_hdr {
+ u8 llc_dsap;
+ u8 llc_ssap;
+ u8 llc_ctrl;
+ u8 snap_oui[3];
+ __be16 snap_type;
+} __packed;
+
struct ath10k *ath10k_mac_create(size_t priv_size);
void ath10k_mac_destroy(struct ath10k *ar);
int ath10k_mac_register(struct ath10k *ar);
@@ -45,6 +56,24 @@ void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif);
void ath10k_drain_tx(struct ath10k *ar);
bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
u8 keyidx);
+int ath10k_mac_vif_chan(struct ieee80211_vif *vif,
+ struct cfg80211_chan_def *def);
+
+void ath10k_mac_handle_beacon(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_mac_handle_beacon_miss(struct ath10k *ar, u32 vdev_id);
+void ath10k_mac_handle_tx_pause(struct ath10k *ar, u32 vdev_id,
+ enum wmi_tlv_tx_pause_id pause_id,
+ enum wmi_tlv_tx_pause_action action);
+
+u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
+ u8 hw_rate);
+u8 ath10k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
+ u32 bitrate);
+
+void ath10k_mac_tx_lock(struct ath10k *ar, int reason);
+void ath10k_mac_tx_unlock(struct ath10k *ar, int reason);
+void ath10k_mac_vif_tx_lock(struct ath10k_vif *arvif, int reason);
+void ath10k_mac_vif_tx_unlock(struct ath10k_vif *arvif, int reason);
static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
{
diff --git a/drivers/net/wireless/ath/ath10k/p2p.c b/drivers/net/wireless/ath/ath10k/p2p.c
new file mode 100644
index 000000000000..c0b6ffaf3ec1
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/p2p.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2015 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "wmi.h"
+#include "mac.h"
+#include "p2p.h"
+
+static void ath10k_p2p_noa_ie_fill(u8 *data, size_t len,
+ const struct wmi_p2p_noa_info *noa)
+{
+ struct ieee80211_p2p_noa_attr *noa_attr;
+ u8 ctwindow_oppps = noa->ctwindow_oppps;
+ u8 ctwindow = ctwindow_oppps >> WMI_P2P_OPPPS_CTWINDOW_OFFSET;
+ bool oppps = !!(ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT);
+ __le16 *noa_attr_len;
+ u16 attr_len;
+ u8 noa_descriptors = noa->num_descriptors;
+ int i;
+
+ /* P2P IE */
+ data[0] = WLAN_EID_VENDOR_SPECIFIC;
+ data[1] = len - 2;
+ data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
+ data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
+ data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
+ data[5] = WLAN_OUI_TYPE_WFA_P2P;
+
+ /* NOA ATTR */
+ data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE;
+ noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */
+ noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9];
+
+ noa_attr->index = noa->index;
+ noa_attr->oppps_ctwindow = ctwindow;
+ if (oppps)
+ noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT;
+
+ for (i = 0; i < noa_descriptors; i++) {
+ noa_attr->desc[i].count =
+ __le32_to_cpu(noa->descriptors[i].type_count);
+ noa_attr->desc[i].duration = noa->descriptors[i].duration;
+ noa_attr->desc[i].interval = noa->descriptors[i].interval;
+ noa_attr->desc[i].start_time = noa->descriptors[i].start_time;
+ }
+
+ attr_len = 2; /* index + oppps_ctwindow */
+ attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc);
+ *noa_attr_len = __cpu_to_le16(attr_len);
+}
+
+static size_t ath10k_p2p_noa_ie_len_compute(const struct wmi_p2p_noa_info *noa)
+{
+ size_t len = 0;
+
+ if (!noa->num_descriptors &&
+ !(noa->ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT))
+ return 0;
+
+ len += 1 + 1 + 4; /* EID + len + OUI */
+ len += 1 + 2; /* noa attr + attr len */
+ len += 1 + 1; /* index + oppps_ctwindow */
+ len += noa->num_descriptors * sizeof(struct ieee80211_p2p_noa_desc);
+
+ return len;
+}
+
+static void ath10k_p2p_noa_ie_assign(struct ath10k_vif *arvif, void *ie,
+ size_t len)
+{
+ struct ath10k *ar = arvif->ar;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ kfree(arvif->u.ap.noa_data);
+
+ arvif->u.ap.noa_data = ie;
+ arvif->u.ap.noa_len = len;
+}
+
+static void __ath10k_p2p_noa_update(struct ath10k_vif *arvif,
+ const struct wmi_p2p_noa_info *noa)
+{
+ struct ath10k *ar = arvif->ar;
+ void *ie;
+ size_t len;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ ath10k_p2p_noa_ie_assign(arvif, NULL, 0);
+
+ len = ath10k_p2p_noa_ie_len_compute(noa);
+ if (!len)
+ return;
+
+ ie = kmalloc(len, GFP_ATOMIC);
+ if (!ie)
+ return;
+
+ ath10k_p2p_noa_ie_fill(ie, len, noa);
+ ath10k_p2p_noa_ie_assign(arvif, ie, len);
+}
+
+void ath10k_p2p_noa_update(struct ath10k_vif *arvif,
+ const struct wmi_p2p_noa_info *noa)
+{
+ struct ath10k *ar = arvif->ar;
+
+ spin_lock_bh(&ar->data_lock);
+ __ath10k_p2p_noa_update(arvif, noa);
+ spin_unlock_bh(&ar->data_lock);
+}
+
+struct ath10k_p2p_noa_arg {
+ u32 vdev_id;
+ const struct wmi_p2p_noa_info *noa;
+};
+
+static void ath10k_p2p_noa_update_vdev_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct ath10k_p2p_noa_arg *arg = data;
+
+ if (arvif->vdev_id != arg->vdev_id)
+ return;
+
+ ath10k_p2p_noa_update(arvif, arg->noa);
+}
+
+void ath10k_p2p_noa_update_by_vdev_id(struct ath10k *ar, u32 vdev_id,
+ const struct wmi_p2p_noa_info *noa)
+{
+ struct ath10k_p2p_noa_arg arg = {
+ .vdev_id = vdev_id,
+ .noa = noa,
+ };
+
+ ieee80211_iterate_active_interfaces_atomic(ar->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ ath10k_p2p_noa_update_vdev_iter,
+ &arg);
+}
diff --git a/drivers/net/wireless/ath/ath10k/p2p.h b/drivers/net/wireless/ath/ath10k/p2p.h
new file mode 100644
index 000000000000..7be616e2e121
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/p2p.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _P2P_H
+#define _P2P_H
+
+struct ath10k_vif;
+struct wmi_p2p_noa_info;
+
+void ath10k_p2p_noa_update(struct ath10k_vif *arvif,
+ const struct wmi_p2p_noa_info *noa);
+void ath10k_p2p_noa_update_by_vdev_id(struct ath10k *ar, u32 vdev_id,
+ const struct wmi_p2p_noa_info *noa);
+
+#endif
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 7681237fe298..ea656e011a96 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -113,7 +113,7 @@ static const struct ce_attr host_ce_config_wlan[] = {
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
- .dest_nentries = 32,
+ .dest_nentries = 128,
},
/* CE3: host->target WMI */
@@ -183,7 +183,7 @@ static const struct ce_pipe_config target_ce_config_wlan[] = {
{
.pipenum = __cpu_to_le32(2),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
- .nentries = __cpu_to_le32(32),
+ .nentries = __cpu_to_le32(64),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
@@ -330,6 +330,205 @@ static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
},
};
+static bool ath10k_pci_is_awake(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ u32 val = ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
+ RTC_STATE_ADDRESS);
+
+ return RTC_STATE_V_GET(val) == RTC_STATE_V_ON;
+}
+
+static void __ath10k_pci_wake(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+ lockdep_assert_held(&ar_pci->ps_lock);
+
+ ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps wake reg refcount %lu awake %d\n",
+ ar_pci->ps_wake_refcount, ar_pci->ps_awake);
+
+ iowrite32(PCIE_SOC_WAKE_V_MASK,
+ ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
+ PCIE_SOC_WAKE_ADDRESS);
+}
+
+static void __ath10k_pci_sleep(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+ lockdep_assert_held(&ar_pci->ps_lock);
+
+ ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps sleep reg refcount %lu awake %d\n",
+ ar_pci->ps_wake_refcount, ar_pci->ps_awake);
+
+ iowrite32(PCIE_SOC_WAKE_RESET,
+ ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
+ PCIE_SOC_WAKE_ADDRESS);
+ ar_pci->ps_awake = false;
+}
+
+static int ath10k_pci_wake_wait(struct ath10k *ar)
+{
+ int tot_delay = 0;
+ int curr_delay = 5;
+
+ while (tot_delay < PCIE_WAKE_TIMEOUT) {
+ if (ath10k_pci_is_awake(ar))
+ return 0;
+
+ udelay(curr_delay);
+ tot_delay += curr_delay;
+
+ if (curr_delay < 50)
+ curr_delay += 5;
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int ath10k_pci_wake(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&ar_pci->ps_lock, flags);
+
+ ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps wake refcount %lu awake %d\n",
+ ar_pci->ps_wake_refcount, ar_pci->ps_awake);
+
+ /* This function can be called very frequently. To avoid excessive
+ * CPU stalls for MMIO reads use a cache var to hold the device state.
+ */
+ if (!ar_pci->ps_awake) {
+ __ath10k_pci_wake(ar);
+
+ ret = ath10k_pci_wake_wait(ar);
+ if (ret == 0)
+ ar_pci->ps_awake = true;
+ }
+
+ if (ret == 0) {
+ ar_pci->ps_wake_refcount++;
+ WARN_ON(ar_pci->ps_wake_refcount == 0);
+ }
+
+ spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
+
+ return ret;
+}
+
+static void ath10k_pci_sleep(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ar_pci->ps_lock, flags);
+
+ ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps sleep refcount %lu awake %d\n",
+ ar_pci->ps_wake_refcount, ar_pci->ps_awake);
+
+ if (WARN_ON(ar_pci->ps_wake_refcount == 0))
+ goto skip;
+
+ ar_pci->ps_wake_refcount--;
+
+ mod_timer(&ar_pci->ps_timer, jiffies +
+ msecs_to_jiffies(ATH10K_PCI_SLEEP_GRACE_PERIOD_MSEC));
+
+skip:
+ spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
+}
+
+static void ath10k_pci_ps_timer(unsigned long ptr)
+{
+ struct ath10k *ar = (void *)ptr;
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ar_pci->ps_lock, flags);
+
+ ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps timer refcount %lu awake %d\n",
+ ar_pci->ps_wake_refcount, ar_pci->ps_awake);
+
+ if (ar_pci->ps_wake_refcount > 0)
+ goto skip;
+
+ __ath10k_pci_sleep(ar);
+
+skip:
+ spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
+}
+
+static void ath10k_pci_sleep_sync(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ unsigned long flags;
+
+ del_timer_sync(&ar_pci->ps_timer);
+
+ spin_lock_irqsave(&ar_pci->ps_lock, flags);
+ WARN_ON(ar_pci->ps_wake_refcount > 0);
+ __ath10k_pci_sleep(ar);
+ spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
+}
+
+void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ int ret;
+
+ ret = ath10k_pci_wake(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to wake target for write32 of 0x%08x at 0x%08x: %d\n",
+ value, offset, ret);
+ return;
+ }
+
+ iowrite32(value, ar_pci->mem + offset);
+ ath10k_pci_sleep(ar);
+}
+
+u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ u32 val;
+ int ret;
+
+ ret = ath10k_pci_wake(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to wake target for read32 at 0x%08x: %d\n",
+ offset, ret);
+ return 0xffffffff;
+ }
+
+ val = ioread32(ar_pci->mem + offset);
+ ath10k_pci_sleep(ar);
+
+ return val;
+}
+
+u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr)
+{
+ return ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + addr);
+}
+
+void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val)
+{
+ ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val);
+}
+
+u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
+{
+ return ath10k_pci_read32(ar, PCIE_LOCAL_BASE_ADDRESS + addr);
+}
+
+void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
+{
+ ath10k_pci_write32(ar, PCIE_LOCAL_BASE_ADDRESS + addr, val);
+}
+
static bool ath10k_pci_irq_pending(struct ath10k *ar)
{
u32 cause;
@@ -793,45 +992,6 @@ static int ath10k_pci_diag_write32(struct ath10k *ar, u32 address, u32 value)
return ath10k_pci_diag_write_mem(ar, address, &val, sizeof(val));
}
-static bool ath10k_pci_is_awake(struct ath10k *ar)
-{
- u32 val = ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS);
-
- return RTC_STATE_V_GET(val) == RTC_STATE_V_ON;
-}
-
-static int ath10k_pci_wake_wait(struct ath10k *ar)
-{
- int tot_delay = 0;
- int curr_delay = 5;
-
- while (tot_delay < PCIE_WAKE_TIMEOUT) {
- if (ath10k_pci_is_awake(ar))
- return 0;
-
- udelay(curr_delay);
- tot_delay += curr_delay;
-
- if (curr_delay < 50)
- curr_delay += 5;
- }
-
- return -ETIMEDOUT;
-}
-
-static int ath10k_pci_wake(struct ath10k *ar)
-{
- ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
- PCIE_SOC_WAKE_V_MASK);
- return ath10k_pci_wake_wait(ar);
-}
-
-static void ath10k_pci_sleep(struct ath10k *ar)
-{
- ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
- PCIE_SOC_WAKE_RESET);
-}
-
/* Called by lower (CE) layer when a send to Target completes. */
static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
{
@@ -1212,11 +1372,15 @@ static void ath10k_pci_irq_enable(struct ath10k *ar)
static int ath10k_pci_hif_start(struct ath10k *ar)
{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
ath10k_pci_irq_enable(ar);
ath10k_pci_rx_post(ar);
+ pcie_capability_write_word(ar_pci->pdev, PCI_EXP_LNKCTL,
+ ar_pci->link_ctl);
+
return 0;
}
@@ -1260,7 +1424,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe)
struct ath10k_ce_ring *ce_ring;
struct ce_desc *ce_desc;
struct sk_buff *skb;
- unsigned int id;
int i;
ar = pci_pipe->hif_ce_state;
@@ -1284,8 +1447,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe)
continue;
ce_ring->per_transfer_context[i] = NULL;
- id = MS(__le16_to_cpu(ce_desc[i].flags),
- CE_DESC_FLAGS_META_DATA);
ar_pci->msg_callbacks_current.tx_completion(ar, skb);
}
@@ -1329,6 +1490,9 @@ static void ath10k_pci_flush(struct ath10k *ar)
static void ath10k_pci_hif_stop(struct ath10k *ar)
{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ unsigned long flags;
+
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
/* Most likely the device has HTT Rx ring configured. The only way to
@@ -1347,6 +1511,10 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_pci_irq_disable(ar);
ath10k_pci_irq_sync(ar);
ath10k_pci_flush(ar);
+
+ spin_lock_irqsave(&ar_pci->ps_lock, flags);
+ WARN_ON(ar_pci->ps_wake_refcount > 0);
+ spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
}
static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
@@ -1524,12 +1692,11 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) {
case QCA6174_HW_1_0_CHIP_ID_REV:
case QCA6174_HW_1_1_CHIP_ID_REV:
+ case QCA6174_HW_2_1_CHIP_ID_REV:
+ case QCA6174_HW_2_2_CHIP_ID_REV:
return 3;
case QCA6174_HW_1_3_CHIP_ID_REV:
return 2;
- case QCA6174_HW_2_1_CHIP_ID_REV:
- case QCA6174_HW_2_2_CHIP_ID_REV:
- return 6;
case QCA6174_HW_3_0_CHIP_ID_REV:
case QCA6174_HW_3_1_CHIP_ID_REV:
case QCA6174_HW_3_2_CHIP_ID_REV:
@@ -1967,15 +2134,15 @@ static int ath10k_pci_chip_reset(struct ath10k *ar)
static int ath10k_pci_hif_power_up(struct ath10k *ar)
{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int ret;
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n");
- ret = ath10k_pci_wake(ar);
- if (ret) {
- ath10k_err(ar, "failed to wake up target: %d\n", ret);
- return ret;
- }
+ pcie_capability_read_word(ar_pci->pdev, PCI_EXP_LNKCTL,
+ &ar_pci->link_ctl);
+ pcie_capability_write_word(ar_pci->pdev, PCI_EXP_LNKCTL,
+ ar_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
/*
* Bring the target up cleanly.
@@ -2023,7 +2190,6 @@ err_ce:
ath10k_pci_ce_deinit(ar);
err_sleep:
- ath10k_pci_sleep(ar);
return ret;
}
@@ -2034,28 +2200,18 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
/* Currently hif_power_up performs effectively a reset and hif_stop
* resets the chip as well so there's no point in resetting here.
*/
-
- ath10k_pci_sleep(ar);
}
#ifdef CONFIG_PM
-#define ATH10K_PCI_PM_CONTROL 0x44
-
static int ath10k_pci_hif_suspend(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- struct pci_dev *pdev = ar_pci->pdev;
- u32 val;
-
- pci_read_config_dword(pdev, ATH10K_PCI_PM_CONTROL, &val);
-
- if ((val & 0x000000ff) != 0x3) {
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_write_config_dword(pdev, ATH10K_PCI_PM_CONTROL,
- (val & 0xffffff00) | 0x03);
- }
+ /* The grace timer can still be counting down and ar->ps_awake be true.
+ * It is known that the device may be asleep after resuming regardless
+ * of the SoC powersave state before suspending. Hence make sure the
+ * device is asleep before proceeding.
+ */
+ ath10k_pci_sleep_sync(ar);
return 0;
}
@@ -2066,22 +2222,14 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
struct pci_dev *pdev = ar_pci->pdev;
u32 val;
- pci_read_config_dword(pdev, ATH10K_PCI_PM_CONTROL, &val);
-
- if ((val & 0x000000ff) != 0) {
- pci_restore_state(pdev);
- pci_write_config_dword(pdev, ATH10K_PCI_PM_CONTROL,
- val & 0xffffff00);
- /*
- * Suspend/Resume resets the PCI configuration space,
- * so we have to re-disable the RETRY_TIMEOUT register (0x41)
- * to keep PCI Tx retries from interfering with C3 CPU state
- */
- pci_read_config_dword(pdev, 0x40, &val);
-
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
- }
+ /* Suspend/Resume resets the PCI configuration space, so we have to
+ * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
+ * from interfering with C3 CPU state. pci_restore_state won't help
+ * here since it only restores the first 64 bytes pci config header.
+ */
+ pci_read_config_dword(pdev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
return 0;
}
@@ -2497,7 +2645,6 @@ static int ath10k_pci_claim(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct pci_dev *pdev = ar_pci->pdev;
- u32 lcr_val;
int ret;
pci_set_drvdata(pdev, ar);
@@ -2531,10 +2678,6 @@ static int ath10k_pci_claim(struct ath10k *ar)
pci_set_master(pdev);
- /* Workaround: Disable ASPM */
- pci_read_config_dword(pdev, 0x80, &lcr_val);
- pci_write_config_dword(pdev, 0x80, (lcr_val & 0xffffff00));
-
/* Arrange for access to Target SoC registers. */
ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0);
if (!ar_pci->mem) {
@@ -2621,9 +2764,19 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
ar_pci->dev = &pdev->dev;
ar_pci->ar = ar;
+ if (pdev->subsystem_vendor || pdev->subsystem_device)
+ scnprintf(ar->spec_board_id, sizeof(ar->spec_board_id),
+ "%04x:%04x:%04x:%04x",
+ pdev->vendor, pdev->device,
+ pdev->subsystem_vendor, pdev->subsystem_device);
+
spin_lock_init(&ar_pci->ce_lock);
+ spin_lock_init(&ar_pci->ps_lock);
+
setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry,
(unsigned long)ar);
+ setup_timer(&ar_pci->ps_timer, ath10k_pci_ps_timer,
+ (unsigned long)ar);
ret = ath10k_pci_claim(ar);
if (ret) {
@@ -2631,12 +2784,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_core_destroy;
}
- ret = ath10k_pci_wake(ar);
- if (ret) {
- ath10k_err(ar, "failed to wake up: %d\n", ret);
- goto err_release;
- }
-
ret = ath10k_pci_alloc_pipes(ar);
if (ret) {
ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
@@ -2678,11 +2825,9 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) {
ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n",
pdev->device, chip_id);
- goto err_sleep;
+ goto err_free_irq;
}
- ath10k_pci_sleep(ar);
-
ret = ath10k_core_register(ar, chip_id);
if (ret) {
ath10k_err(ar, "failed to register driver core: %d\n", ret);
@@ -2702,9 +2847,7 @@ err_free_pipes:
ath10k_pci_free_pipes(ar);
err_sleep:
- ath10k_pci_sleep(ar);
-
-err_release:
+ ath10k_pci_sleep_sync(ar);
ath10k_pci_release(ar);
err_core_destroy:
@@ -2734,6 +2877,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
ath10k_pci_deinit_irq(ar);
ath10k_pci_ce_deinit(ar);
ath10k_pci_free_pipes(ar);
+ ath10k_pci_sleep_sync(ar);
ath10k_pci_release(ar);
ath10k_core_destroy(ar);
}
@@ -2770,7 +2914,21 @@ module_exit(ath10k_pci_exit);
MODULE_AUTHOR("Qualcomm Atheros");
MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
MODULE_LICENSE("Dual BSD/GPL");
+
+/* QCA988x 2.0 firmware files */
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API2_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_FILE);
+MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API4_FILE);
+MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API5_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
+
+/* QCA6174 2.1 firmware files */
+MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API4_FILE);
+MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API5_FILE);
+MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" QCA6174_HW_2_1_BOARD_DATA_FILE);
+
+/* QCA6174 3.1 firmware files */
+MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE);
+MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API5_FILE);
+MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE);
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index bddf54320160..d7696ddc03c4 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -185,6 +185,41 @@ struct ath10k_pci {
/* Map CE id to ce_state */
struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
struct timer_list rx_post_retry;
+
+ /* Due to HW quirks it is recommended to disable ASPM during device
+ * bootup. To do that the original PCI-E Link Control is stored before
+ * device bootup is executed and re-programmed later.
+ */
+ u16 link_ctl;
+
+ /* Protects ps_awake and ps_wake_refcount */
+ spinlock_t ps_lock;
+
+ /* The device has a special powersave-oriented register. When device is
+ * considered asleep it drains less power and driver is forbidden from
+ * accessing most MMIO registers. If host were to access them without
+ * waking up the device might scribble over host memory or return
+ * 0xdeadbeef readouts.
+ */
+ unsigned long ps_wake_refcount;
+
+ /* Waking up takes some time (up to 2ms in some cases) so it can be bad
+ * for latency. To mitigate this the device isn't immediately allowed
+ * to sleep after all references are undone - instead there's a grace
+ * period after which the powersave register is updated unless some
+ * activity to/from device happened in the meantime.
+ *
+ * Also see comments on ATH10K_PCI_SLEEP_GRACE_PERIOD_MSEC.
+ */
+ struct timer_list ps_timer;
+
+ /* MMIO registers are used to communicate with the device. With
+ * intensive traffic accessing powersave register would be a bit
+ * wasteful overhead and would needlessly stall CPU. It is far more
+ * efficient to rely on a variable in RAM and update it only upon
+ * powersave register state changes.
+ */
+ bool ps_awake;
};
static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
@@ -209,61 +244,25 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
* for this device; but that's not guaranteed.
*/
#define TARG_CPU_SPACE_TO_CE_SPACE(ar, pci_addr, addr) \
- (((ioread32((pci_addr)+(SOC_CORE_BASE_ADDRESS| \
+ (((ath10k_pci_read32(ar, (SOC_CORE_BASE_ADDRESS | \
CORE_CTRL_ADDRESS)) & 0x7ff) << 21) | \
0x100000 | ((addr) & 0xfffff))
/* Wait up to this many Ms for a Diagnostic Access CE operation to complete */
#define DIAG_ACCESS_CE_TIMEOUT_MS 10
-/* Target exposes its registers for direct access. However before host can
- * access them it needs to make sure the target is awake (ath10k_pci_wake,
- * ath10k_pci_wake_wait, ath10k_pci_is_awake). Once target is awake it won't go
- * to sleep unless host tells it to (ath10k_pci_sleep).
- *
- * If host tries to access target registers without waking it up it can
- * scribble over host memory.
- *
- * If target is asleep waking it up may take up to even 2ms.
- */
-
-static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset,
- u32 value)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
- iowrite32(value, ar_pci->mem + offset);
-}
-
-static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
- return ioread32(ar_pci->mem + offset);
-}
-
-static inline u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr)
-{
- return ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + addr);
-}
-
-static inline void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val)
-{
- ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val);
-}
-
-static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
- return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
-}
+void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value);
+void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val);
+void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val);
-static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+u32 ath10k_pci_read32(struct ath10k *ar, u32 offset);
+u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr);
+u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr);
- iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
-}
+/* QCA6174 is known to have Tx/Rx issues when SOC_WAKE register is poked too
+ * frequently. To avoid this put SoC to sleep after a very conservative grace
+ * period. Adjust with great care.
+ */
+#define ATH10K_PCI_SLEEP_GRACE_PERIOD_MSEC 60
#endif /* _PCI_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h
index e9cc7787bf5f..492b5a5af434 100644
--- a/drivers/net/wireless/ath/ath10k/rx_desc.h
+++ b/drivers/net/wireless/ath/ath10k/rx_desc.h
@@ -661,6 +661,28 @@ struct rx_msdu_end {
#define RX_PPDU_START_INFO5_SERVICE_MASK 0x0000ffff
#define RX_PPDU_START_INFO5_SERVICE_LSB 0
+/* No idea what this flag means. It seems to be always set in rate. */
+#define RX_PPDU_START_RATE_FLAG BIT(3)
+
+enum rx_ppdu_start_rate {
+ RX_PPDU_START_RATE_OFDM_48M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_48M,
+ RX_PPDU_START_RATE_OFDM_24M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_24M,
+ RX_PPDU_START_RATE_OFDM_12M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_12M,
+ RX_PPDU_START_RATE_OFDM_6M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_6M,
+ RX_PPDU_START_RATE_OFDM_54M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_54M,
+ RX_PPDU_START_RATE_OFDM_36M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_36M,
+ RX_PPDU_START_RATE_OFDM_18M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_18M,
+ RX_PPDU_START_RATE_OFDM_9M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_9M,
+
+ RX_PPDU_START_RATE_CCK_LP_11M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_11M,
+ RX_PPDU_START_RATE_CCK_LP_5_5M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_5_5M,
+ RX_PPDU_START_RATE_CCK_LP_2M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_2M,
+ RX_PPDU_START_RATE_CCK_LP_1M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_1M,
+ RX_PPDU_START_RATE_CCK_SP_11M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_SP_11M,
+ RX_PPDU_START_RATE_CCK_SP_5_5M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_SP_5_5M,
+ RX_PPDU_START_RATE_CCK_SP_2M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_SP_2M,
+};
+
struct rx_ppdu_start {
struct {
u8 pri20_mhz;
diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c
index d22addf6118b..8dcd424aa502 100644
--- a/drivers/net/wireless/ath/ath10k/spectral.c
+++ b/drivers/net/wireless/ath/ath10k/spectral.c
@@ -519,9 +519,12 @@ int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
int ath10k_spectral_create(struct ath10k *ar)
{
+ /* The buffer size covers whole channels in dual bands up to 128 bins.
+ * Scan with bigger than 128 bins needs to be run on single band each.
+ */
ar->spectral.rfs_chan_spec_scan = relay_open("spectral_scan",
ar->debug.debugfs_phy,
- 1024, 256,
+ 1140, 2500,
&rfs_spec_scan_cb, NULL);
debugfs_create_file("spectral_scan_ctl",
S_IRUSR | S_IWUSR,
diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c
index aede750809fe..1a899d70dc5d 100644
--- a/drivers/net/wireless/ath/ath10k/thermal.c
+++ b/drivers/net/wireless/ath/ath10k/thermal.c
@@ -23,102 +23,50 @@
#include "debug.h"
#include "wmi-ops.h"
-static int ath10k_thermal_get_active_vifs(struct ath10k *ar,
- enum wmi_vdev_type type)
+static int
+ath10k_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
{
- struct ath10k_vif *arvif;
- int count = 0;
-
- lockdep_assert_held(&ar->conf_mutex);
-
- list_for_each_entry(arvif, &ar->arvifs, list) {
- if (!arvif->is_started)
- continue;
-
- if (!arvif->is_up)
- continue;
-
- if (arvif->vdev_type != type)
- continue;
-
- count++;
- }
- return count;
-}
-
-static int ath10k_thermal_get_max_dutycycle(struct thermal_cooling_device *cdev,
- unsigned long *state)
-{
- *state = ATH10K_QUIET_DUTY_CYCLE_MAX;
+ *state = ATH10K_THERMAL_THROTTLE_MAX;
return 0;
}
-static int ath10k_thermal_get_cur_dutycycle(struct thermal_cooling_device *cdev,
- unsigned long *state)
+static int
+ath10k_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
{
struct ath10k *ar = cdev->devdata;
mutex_lock(&ar->conf_mutex);
- *state = ar->thermal.duty_cycle;
+ *state = ar->thermal.throttle_state;
mutex_unlock(&ar->conf_mutex);
return 0;
}
-static int ath10k_thermal_set_cur_dutycycle(struct thermal_cooling_device *cdev,
- unsigned long duty_cycle)
+static int
+ath10k_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long throttle_state)
{
struct ath10k *ar = cdev->devdata;
- u32 period, duration, enabled;
- int num_bss, ret = 0;
- mutex_lock(&ar->conf_mutex);
- if (ar->state != ATH10K_STATE_ON) {
- ret = -ENETDOWN;
- goto out;
- }
-
- if (duty_cycle > ATH10K_QUIET_DUTY_CYCLE_MAX) {
- ath10k_warn(ar, "duty cycle %ld is exceeding the limit %d\n",
- duty_cycle, ATH10K_QUIET_DUTY_CYCLE_MAX);
- ret = -EINVAL;
- goto out;
- }
- /* TODO: Right now, thermal mitigation is handled only for single/multi
- * vif AP mode. Since quiet param is not validated in STA mode, it needs
- * to be investigated further to handle multi STA and multi-vif (AP+STA)
- * mode properly.
- */
- num_bss = ath10k_thermal_get_active_vifs(ar, WMI_VDEV_TYPE_AP);
- if (!num_bss) {
- ath10k_warn(ar, "no active AP interfaces\n");
- ret = -ENETDOWN;
- goto out;
- }
- period = max(ATH10K_QUIET_PERIOD_MIN,
- (ATH10K_QUIET_PERIOD_DEFAULT / num_bss));
- duration = (period * duty_cycle) / 100;
- enabled = duration ? 1 : 0;
-
- ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration,
- ATH10K_QUIET_START_OFFSET,
- enabled);
- if (ret) {
- ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n",
- period, duration, enabled, ret);
- goto out;
+ if (throttle_state > ATH10K_THERMAL_THROTTLE_MAX) {
+ ath10k_warn(ar, "throttle state %ld is exceeding the limit %d\n",
+ throttle_state, ATH10K_THERMAL_THROTTLE_MAX);
+ return -EINVAL;
}
- ar->thermal.duty_cycle = duty_cycle;
-out:
+ mutex_lock(&ar->conf_mutex);
+ ar->thermal.throttle_state = throttle_state;
+ ath10k_thermal_set_throttling(ar);
mutex_unlock(&ar->conf_mutex);
- return ret;
+ return 0;
}
static struct thermal_cooling_device_ops ath10k_thermal_ops = {
- .get_max_state = ath10k_thermal_get_max_dutycycle,
- .get_cur_state = ath10k_thermal_get_cur_dutycycle,
- .set_cur_state = ath10k_thermal_set_cur_dutycycle,
+ .get_max_state = ath10k_thermal_get_max_throttle_state,
+ .get_cur_state = ath10k_thermal_get_cur_throttle_state,
+ .set_cur_state = ath10k_thermal_set_cur_throttle_state,
};
static ssize_t ath10k_thermal_show_temp(struct device *dev,
@@ -127,6 +75,7 @@ static ssize_t ath10k_thermal_show_temp(struct device *dev,
{
struct ath10k *ar = dev_get_drvdata(dev);
int ret, temperature;
+ unsigned long time_left;
mutex_lock(&ar->conf_mutex);
@@ -148,9 +97,9 @@ static ssize_t ath10k_thermal_show_temp(struct device *dev,
goto out;
}
- ret = wait_for_completion_timeout(&ar->thermal.wmi_sync,
- ATH10K_THERMAL_SYNC_TIMEOUT_HZ);
- if (ret == 0) {
+ time_left = wait_for_completion_timeout(&ar->thermal.wmi_sync,
+ ATH10K_THERMAL_SYNC_TIMEOUT_HZ);
+ if (!time_left) {
ath10k_warn(ar, "failed to synchronize thermal read\n");
ret = -ETIMEDOUT;
goto out;
@@ -184,6 +133,32 @@ static struct attribute *ath10k_hwmon_attrs[] = {
};
ATTRIBUTE_GROUPS(ath10k_hwmon);
+void ath10k_thermal_set_throttling(struct ath10k *ar)
+{
+ u32 period, duration, enabled;
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ if (!ar->wmi.ops->gen_pdev_set_quiet_mode)
+ return;
+
+ if (ar->state != ATH10K_STATE_ON)
+ return;
+
+ period = ar->thermal.quiet_period;
+ duration = (period * ar->thermal.throttle_state) / 100;
+ enabled = duration ? 1 : 0;
+
+ ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration,
+ ATH10K_QUIET_START_OFFSET,
+ enabled);
+ if (ret) {
+ ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n",
+ period, duration, enabled, ret);
+ }
+}
+
int ath10k_thermal_register(struct ath10k *ar)
{
struct thermal_cooling_device *cdev;
@@ -202,11 +177,12 @@ int ath10k_thermal_register(struct ath10k *ar)
ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj,
"cooling_device");
if (ret) {
- ath10k_err(ar, "failed to create thermal symlink\n");
+ ath10k_err(ar, "failed to create cooling device symlink\n");
goto err_cooling_destroy;
}
ar->thermal.cdev = cdev;
+ ar->thermal.quiet_period = ATH10K_QUIET_PERIOD_DEFAULT;
/* Do not register hwmon device when temperature reading is not
* supported by firmware
@@ -231,7 +207,7 @@ int ath10k_thermal_register(struct ath10k *ar)
return 0;
err_remove_link:
- sysfs_remove_link(&ar->dev->kobj, "thermal_sensor");
+ sysfs_remove_link(&ar->dev->kobj, "cooling_device");
err_cooling_destroy:
thermal_cooling_device_unregister(cdev);
return ret;
diff --git a/drivers/net/wireless/ath/ath10k/thermal.h b/drivers/net/wireless/ath/ath10k/thermal.h
index bccc17ae0fde..b610ea5caae8 100644
--- a/drivers/net/wireless/ath/ath10k/thermal.h
+++ b/drivers/net/wireless/ath/ath10k/thermal.h
@@ -19,16 +19,17 @@
#define ATH10K_QUIET_PERIOD_DEFAULT 100
#define ATH10K_QUIET_PERIOD_MIN 25
#define ATH10K_QUIET_START_OFFSET 10
-#define ATH10K_QUIET_DUTY_CYCLE_MAX 70
#define ATH10K_HWMON_NAME_LEN 15
#define ATH10K_THERMAL_SYNC_TIMEOUT_HZ (5*HZ)
+#define ATH10K_THERMAL_THROTTLE_MAX 100
struct ath10k_thermal {
struct thermal_cooling_device *cdev;
struct completion wmi_sync;
/* protected by conf_mutex */
- u32 duty_cycle;
+ u32 throttle_state;
+ u32 quiet_period;
/* temperature value in Celcius degree
* protected by data_lock
*/
@@ -39,6 +40,7 @@ struct ath10k_thermal {
int ath10k_thermal_register(struct ath10k *ar);
void ath10k_thermal_unregister(struct ath10k *ar);
void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature);
+void ath10k_thermal_set_throttling(struct ath10k *ar);
#else
static inline int ath10k_thermal_register(struct ath10k *ar)
{
@@ -54,5 +56,9 @@ static inline void ath10k_thermal_event_temperature(struct ath10k *ar,
{
}
+static inline void ath10k_thermal_set_throttling(struct ath10k *ar)
+{
+}
+
#endif
#endif /* _THERMAL_ */
diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h
index 5407887380ab..71bdb368813d 100644
--- a/drivers/net/wireless/ath/ath10k/trace.h
+++ b/drivers/net/wireless/ath/ath10k/trace.h
@@ -21,11 +21,16 @@
#include "core.h"
#if !defined(_TRACE_H_)
-static inline u32 ath10k_frm_hdr_len(const void *buf)
+static inline u32 ath10k_frm_hdr_len(const void *buf, size_t len)
{
const struct ieee80211_hdr *hdr = buf;
- return ieee80211_hdrlen(hdr->frame_control);
+ /* In some rare cases (e.g. fcs error) device reports frame buffer
+ * shorter than what frame header implies (e.g. len = 0). The buffer
+ * can still be accessed so do a simple min() to guarantee caller
+ * doesn't get value greater than len.
+ */
+ return min_t(u32, len, ieee80211_hdrlen(hdr->frame_control));
}
#endif
@@ -46,7 +51,7 @@ static inline void trace_ ## name(proto) {}
#undef TRACE_SYSTEM
#define TRACE_SYSTEM ath10k
-#define ATH10K_MSG_MAX 200
+#define ATH10K_MSG_MAX 400
DECLARE_EVENT_CLASS(ath10k_log_event,
TP_PROTO(struct ath10k *ar, struct va_format *vaf),
@@ -360,13 +365,13 @@ DECLARE_EVENT_CLASS(ath10k_hdr_event,
__string(device, dev_name(ar->dev))
__string(driver, dev_driver_string(ar->dev))
__field(size_t, len)
- __dynamic_array(u8, data, ath10k_frm_hdr_len(data))
+ __dynamic_array(u8, data, ath10k_frm_hdr_len(data, len))
),
TP_fast_assign(
__assign_str(device, dev_name(ar->dev));
__assign_str(driver, dev_driver_string(ar->dev));
- __entry->len = ath10k_frm_hdr_len(data);
+ __entry->len = ath10k_frm_hdr_len(data, len);
memcpy(__get_dynamic_array(data), data, __entry->len);
),
@@ -387,15 +392,16 @@ DECLARE_EVENT_CLASS(ath10k_payload_event,
__string(device, dev_name(ar->dev))
__string(driver, dev_driver_string(ar->dev))
__field(size_t, len)
- __dynamic_array(u8, payload, (len - ath10k_frm_hdr_len(data)))
+ __dynamic_array(u8, payload, (len -
+ ath10k_frm_hdr_len(data, len)))
),
TP_fast_assign(
__assign_str(device, dev_name(ar->dev));
__assign_str(driver, dev_driver_string(ar->dev));
- __entry->len = len - ath10k_frm_hdr_len(data);
+ __entry->len = len - ath10k_frm_hdr_len(data, len);
memcpy(__get_dynamic_array(payload),
- data + ath10k_frm_hdr_len(data), __entry->len);
+ data + ath10k_frm_hdr_len(data, len), __entry->len);
),
TP_printk(
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index 3f00cec8aef5..826500bb2b1b 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -55,8 +55,10 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
lockdep_assert_held(&htt->tx_lock);
- ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
- tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack);
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
+ "htt tx completion msdu_id %u discard %d no_ack %d success %d\n",
+ tx_done->msdu_id, !!tx_done->discard,
+ !!tx_done->no_ack, !!tx_done->success);
if (tx_done->msdu_id >= htt->max_num_pending_tx) {
ath10k_warn(ar, "warning: msdu_id %d too big, ignoring\n",
@@ -97,6 +99,9 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
if (tx_done->no_ack)
info->flags &= ~IEEE80211_TX_STAT_ACK;
+ if (tx_done->success && (info->flags & IEEE80211_TX_CTL_NO_ACK))
+ info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+
ieee80211_tx_status(htt->ar->hw, msdu);
/* we do not own the msdu anymore */
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index c8b64e7a6089..47fe2e756bec 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -45,6 +45,10 @@ struct wmi_ops {
struct wmi_rdy_ev_arg *arg);
int (*pull_fw_stats)(struct ath10k *ar, struct sk_buff *skb,
struct ath10k_fw_stats *stats);
+ int (*pull_roam_ev)(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_roam_ev_arg *arg);
+ int (*pull_wow_event)(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_wow_ev_arg *arg);
struct sk_buff *(*gen_pdev_suspend)(struct ath10k *ar, u32 suspend_opt);
struct sk_buff *(*gen_pdev_resume)(struct ath10k *ar);
@@ -81,7 +85,8 @@ struct wmi_ops {
struct sk_buff *(*gen_vdev_wmm_conf)(struct ath10k *ar, u32 vdev_id,
const struct wmi_wmm_params_all_arg *arg);
struct sk_buff *(*gen_peer_create)(struct ath10k *ar, u32 vdev_id,
- const u8 peer_addr[ETH_ALEN]);
+ const u8 peer_addr[ETH_ALEN],
+ enum wmi_peer_type peer_type);
struct sk_buff *(*gen_peer_delete)(struct ath10k *ar, u32 vdev_id,
const u8 peer_addr[ETH_ALEN]);
struct sk_buff *(*gen_peer_flush)(struct ath10k *ar, u32 vdev_id,
@@ -148,6 +153,27 @@ struct wmi_ops {
u32 num_ac);
struct sk_buff *(*gen_sta_keepalive)(struct ath10k *ar,
const struct wmi_sta_keepalive_arg *arg);
+ struct sk_buff *(*gen_wow_enable)(struct ath10k *ar);
+ struct sk_buff *(*gen_wow_add_wakeup_event)(struct ath10k *ar, u32 vdev_id,
+ enum wmi_wow_wakeup_event event,
+ u32 enable);
+ struct sk_buff *(*gen_wow_host_wakeup_ind)(struct ath10k *ar);
+ struct sk_buff *(*gen_wow_add_pattern)(struct ath10k *ar, u32 vdev_id,
+ u32 pattern_id,
+ const u8 *pattern,
+ const u8 *mask,
+ int pattern_len,
+ int pattern_offset);
+ struct sk_buff *(*gen_wow_del_pattern)(struct ath10k *ar, u32 vdev_id,
+ u32 pattern_id);
+ struct sk_buff *(*gen_update_fw_tdls_state)(struct ath10k *ar,
+ u32 vdev_id,
+ enum wmi_tdls_state state);
+ struct sk_buff *(*gen_tdls_peer_update)(struct ath10k *ar,
+ const struct wmi_tdls_peer_update_cmd_arg *arg,
+ const struct wmi_tdls_peer_capab_arg *cap,
+ const struct wmi_channel_arg *chan);
+ struct sk_buff *(*gen_adaptive_qcs)(struct ath10k *ar, bool enable);
};
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
@@ -274,6 +300,26 @@ ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb,
}
static inline int
+ath10k_wmi_pull_roam_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_roam_ev_arg *arg)
+{
+ if (!ar->wmi.ops->pull_roam_ev)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->pull_roam_ev(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_wow_event(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_wow_ev_arg *arg)
+{
+ if (!ar->wmi.ops->pull_wow_event)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->pull_wow_event(ar, skb, arg);
+}
+
+static inline int
ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
@@ -624,14 +670,15 @@ ath10k_wmi_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id,
static inline int
ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
- const u8 peer_addr[ETH_ALEN])
+ const u8 peer_addr[ETH_ALEN],
+ enum wmi_peer_type peer_type)
{
struct sk_buff *skb;
if (!ar->wmi.ops->gen_peer_create)
return -EOPNOTSUPP;
- skb = ar->wmi.ops->gen_peer_create(ar, vdev_id, peer_addr);
+ skb = ar->wmi.ops->gen_peer_create(ar, vdev_id, peer_addr, peer_type);
if (IS_ERR(skb))
return PTR_ERR(skb);
@@ -1060,4 +1107,145 @@ ath10k_wmi_sta_keepalive(struct ath10k *ar,
return ath10k_wmi_cmd_send(ar, skb, cmd_id);
}
+static inline int
+ath10k_wmi_wow_enable(struct ath10k *ar)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ if (!ar->wmi.ops->gen_wow_enable)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_wow_enable(ar);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->wow_enable_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_wow_add_wakeup_event(struct ath10k *ar, u32 vdev_id,
+ enum wmi_wow_wakeup_event event,
+ u32 enable)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ if (!ar->wmi.ops->gen_wow_add_wakeup_event)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_wow_add_wakeup_event(ar, vdev_id, event, enable);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->wow_enable_disable_wake_event_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_wow_host_wakeup_ind(struct ath10k *ar)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ if (!ar->wmi.ops->gen_wow_host_wakeup_ind)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_wow_host_wakeup_ind(ar);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->wow_hostwakeup_from_sleep_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_wow_add_pattern(struct ath10k *ar, u32 vdev_id, u32 pattern_id,
+ const u8 *pattern, const u8 *mask,
+ int pattern_len, int pattern_offset)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ if (!ar->wmi.ops->gen_wow_add_pattern)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_wow_add_pattern(ar, vdev_id, pattern_id,
+ pattern, mask, pattern_len,
+ pattern_offset);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->wow_add_wake_pattern_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_wow_del_pattern(struct ath10k *ar, u32 vdev_id, u32 pattern_id)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ if (!ar->wmi.ops->gen_wow_del_pattern)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_wow_del_pattern(ar, vdev_id, pattern_id);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->wow_del_wake_pattern_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id,
+ enum wmi_tdls_state state)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_update_fw_tdls_state)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_update_fw_tdls_state(ar, vdev_id, state);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->tdls_set_state_cmdid);
+}
+
+static inline int
+ath10k_wmi_tdls_peer_update(struct ath10k *ar,
+ const struct wmi_tdls_peer_update_cmd_arg *arg,
+ const struct wmi_tdls_peer_capab_arg *cap,
+ const struct wmi_channel_arg *chan)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_tdls_peer_update)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_tdls_peer_update(ar, arg, cap, chan);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->tdls_peer_update_cmdid);
+}
+
+static inline int
+ath10k_wmi_adaptive_qcs(struct ath10k *ar, bool enable)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_adaptive_qcs)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_adaptive_qcs(ar, enable);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->adaptive_qcs_cmdid);
+}
+
#endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index ee0c5f602e29..8fdba3865c96 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -16,10 +16,13 @@
*/
#include "core.h"
#include "debug.h"
+#include "mac.h"
#include "hw.h"
+#include "mac.h"
#include "wmi.h"
#include "wmi-ops.h"
#include "wmi-tlv.h"
+#include "p2p.h"
/***************/
/* TLV helpers */
@@ -31,9 +34,9 @@ struct wmi_tlv_policy {
static const struct wmi_tlv_policy wmi_tlv_policies[] = {
[WMI_TLV_TAG_ARRAY_BYTE]
- = { .min_len = sizeof(u8) },
+ = { .min_len = 0 },
[WMI_TLV_TAG_ARRAY_UINT32]
- = { .min_len = sizeof(u32) },
+ = { .min_len = 0 },
[WMI_TLV_TAG_STRUCT_SCAN_EVENT]
= { .min_len = sizeof(struct wmi_scan_event) },
[WMI_TLV_TAG_STRUCT_MGMT_RX_HDR]
@@ -62,6 +65,14 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = {
= { .min_len = sizeof(struct wmi_tlv_bcn_tx_status_ev) },
[WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT]
= { .min_len = sizeof(struct wmi_tlv_diag_data_ev) },
+ [WMI_TLV_TAG_STRUCT_P2P_NOA_EVENT]
+ = { .min_len = sizeof(struct wmi_tlv_p2p_noa_ev) },
+ [WMI_TLV_TAG_STRUCT_ROAM_EVENT]
+ = { .min_len = sizeof(struct wmi_tlv_roam_ev) },
+ [WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO]
+ = { .min_len = sizeof(struct wmi_tlv_wow_event_info) },
+ [WMI_TLV_TAG_STRUCT_TX_PAUSE_EVENT]
+ = { .min_len = sizeof(struct wmi_tlv_tx_pause_ev) },
};
static int
@@ -168,6 +179,7 @@ static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar,
{
const void **tb;
const struct wmi_tlv_bcn_tx_status_ev *ev;
+ struct ath10k_vif *arvif;
u32 vdev_id, tx_status;
int ret;
@@ -201,6 +213,10 @@ static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar,
break;
}
+ arvif = ath10k_get_arvif(ar, vdev_id);
+ if (arvif && arvif->is_up && arvif->vif->csa_active)
+ ieee80211_queue_work(ar->hw, &arvif->ap_csa_work);
+
kfree(tb);
return 0;
}
@@ -296,6 +312,83 @@ static int ath10k_wmi_tlv_event_diag(struct ath10k *ar,
return 0;
}
+static int ath10k_wmi_tlv_event_p2p_noa(struct ath10k *ar,
+ struct sk_buff *skb)
+{
+ const void **tb;
+ const struct wmi_tlv_p2p_noa_ev *ev;
+ const struct wmi_p2p_noa_info *noa;
+ int ret, vdev_id;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_P2P_NOA_EVENT];
+ noa = tb[WMI_TLV_TAG_STRUCT_P2P_NOA_INFO];
+
+ if (!ev || !noa) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ vdev_id = __le32_to_cpu(ev->vdev_id);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi tlv p2p noa vdev_id %i descriptors %hhu\n",
+ vdev_id, noa->num_descriptors);
+
+ ath10k_p2p_noa_update_by_vdev_id(ar, vdev_id, noa);
+ kfree(tb);
+ return 0;
+}
+
+static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar,
+ struct sk_buff *skb)
+{
+ const void **tb;
+ const struct wmi_tlv_tx_pause_ev *ev;
+ int ret, vdev_id;
+ u32 pause_id, action, vdev_map, peer_id, tid_map;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_TX_PAUSE_EVENT];
+ if (!ev) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ pause_id = __le32_to_cpu(ev->pause_id);
+ action = __le32_to_cpu(ev->action);
+ vdev_map = __le32_to_cpu(ev->vdev_map);
+ peer_id = __le32_to_cpu(ev->peer_id);
+ tid_map = __le32_to_cpu(ev->tid_map);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi tlv tx pause pause_id %u action %u vdev_map 0x%08x peer_id %u tid_map 0x%08x\n",
+ pause_id, action, vdev_map, peer_id, tid_map);
+
+ for (vdev_id = 0; vdev_map; vdev_id++) {
+ if (!(vdev_map & BIT(vdev_id)))
+ continue;
+
+ vdev_map &= ~BIT(vdev_id);
+ ath10k_mac_handle_tx_pause(ar, vdev_id, pause_id, action);
+ }
+
+ kfree(tb);
+ return 0;
+}
+
/***********/
/* TLV ops */
/***********/
@@ -309,7 +402,7 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
- return;
+ goto out;
trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
@@ -417,11 +510,18 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_TLV_DIAG_EVENTID:
ath10k_wmi_tlv_event_diag(ar, skb);
break;
+ case WMI_TLV_P2P_NOA_EVENTID:
+ ath10k_wmi_tlv_event_p2p_noa(ar, skb);
+ break;
+ case WMI_TLV_TX_PAUSE_EVENTID:
+ ath10k_wmi_tlv_event_tx_pause(ar, skb);
+ break;
default:
ath10k_warn(ar, "Unknown eventid: %d\n", id);
break;
}
+out:
dev_kfree_skb(skb);
}
@@ -1012,6 +1112,65 @@ static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar,
return 0;
}
+static int ath10k_wmi_tlv_op_pull_roam_ev(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct wmi_roam_ev_arg *arg)
+{
+ const void **tb;
+ const struct wmi_tlv_roam_ev *ev;
+ int ret;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_ROAM_EVENT];
+ if (!ev) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ arg->vdev_id = ev->vdev_id;
+ arg->reason = ev->reason;
+ arg->rssi = ev->rssi;
+
+ kfree(tb);
+ return 0;
+}
+
+static int
+ath10k_wmi_tlv_op_pull_wow_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_wow_ev_arg *arg)
+{
+ const void **tb;
+ const struct wmi_tlv_wow_event_info *ev;
+ int ret;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO];
+ if (!ev) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ arg->vdev_id = __le32_to_cpu(ev->vdev_id);
+ arg->flag = __le32_to_cpu(ev->flag);
+ arg->wake_reason = __le32_to_cpu(ev->wake_reason);
+ arg->data_len = __le32_to_cpu(ev->data_len);
+
+ kfree(tb);
+ return 0;
+}
+
static struct sk_buff *
ath10k_wmi_tlv_op_gen_pdev_suspend(struct ath10k *ar, u32 opt)
{
@@ -1160,8 +1319,8 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS);
if (test_bit(WMI_SERVICE_RX_FULL_REORDER, ar->wmi.svc_map)) {
- cfg->num_offload_peers = __cpu_to_le32(3);
- cfg->num_offload_reorder_bufs = __cpu_to_le32(3);
+ cfg->num_offload_peers = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
+ cfg->num_offload_reorder_bufs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
} else {
cfg->num_offload_peers = __cpu_to_le32(0);
cfg->num_offload_reorder_bufs = __cpu_to_le32(0);
@@ -1178,8 +1337,8 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
cfg->rx_timeout_pri[3] = __cpu_to_le32(0x28);
cfg->rx_decap_mode = __cpu_to_le32(1);
cfg->scan_max_pending_reqs = __cpu_to_le32(4);
- cfg->bmiss_offload_max_vdev = __cpu_to_le32(3);
- cfg->roam_offload_max_vdev = __cpu_to_le32(3);
+ cfg->bmiss_offload_max_vdev = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
+ cfg->roam_offload_max_vdev = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
cfg->roam_offload_max_ap_profiles = __cpu_to_le32(8);
cfg->num_mcast_groups = __cpu_to_le32(0);
cfg->num_mcast_table_elems = __cpu_to_le32(0);
@@ -1193,11 +1352,11 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
cfg->gtk_offload_max_vdev = __cpu_to_le32(2);
cfg->num_msdu_desc = __cpu_to_le32(TARGET_TLV_NUM_MSDU_DESC);
cfg->max_frag_entries = __cpu_to_le32(2);
- cfg->num_tdls_vdevs = __cpu_to_le32(1);
+ cfg->num_tdls_vdevs = __cpu_to_le32(TARGET_TLV_NUM_TDLS_VDEVS);
cfg->num_tdls_conn_table_entries = __cpu_to_le32(0x20);
cfg->beacon_tx_offload_max_vdev = __cpu_to_le32(2);
cfg->num_multicast_filter_entries = __cpu_to_le32(5);
- cfg->num_wow_filters = __cpu_to_le32(0x16);
+ cfg->num_wow_filters = __cpu_to_le32(ar->wow.max_num_patterns);
cfg->num_keep_alive_pattern = __cpu_to_le32(6);
cfg->keep_alive_pattern_size = __cpu_to_le32(0);
cfg->max_tdls_concurrent_sleep_sta = __cpu_to_le32(1);
@@ -1248,7 +1407,7 @@ ath10k_wmi_tlv_op_gen_start_scan(struct ath10k *ar,
cmd = (void *)tlv->value;
ath10k_wmi_put_start_scan_common(&cmd->common, arg);
- cmd->burst_duration_ms = __cpu_to_le32(0);
+ cmd->burst_duration_ms = __cpu_to_le32(arg->burst_duration_ms);
cmd->num_channels = __cpu_to_le32(arg->n_channels);
cmd->num_ssids = __cpu_to_le32(arg->n_ssids);
cmd->num_bssids = __cpu_to_le32(arg->n_bssids);
@@ -1408,8 +1567,6 @@ ath10k_wmi_tlv_op_gen_vdev_start(struct ath10k *ar,
void *ptr;
u32 flags = 0;
- if (WARN_ON(arg->ssid && arg->ssid_len == 0))
- return ERR_PTR(-EINVAL);
if (WARN_ON(arg->hidden_ssid && !arg->ssid))
return ERR_PTR(-EINVAL);
if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid)))
@@ -1782,7 +1939,8 @@ ath10k_wmi_tlv_op_gen_sta_keepalive(struct ath10k *ar,
static struct sk_buff *
ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
- const u8 peer_addr[ETH_ALEN])
+ const u8 peer_addr[ETH_ALEN],
+ enum wmi_peer_type peer_type)
{
struct wmi_tlv_peer_create_cmd *cmd;
struct wmi_tlv *tlv;
@@ -1797,7 +1955,7 @@ ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
tlv->len = __cpu_to_le16(sizeof(*cmd));
cmd = (void *)tlv->value;
cmd->vdev_id = __cpu_to_le32(vdev_id);
- cmd->peer_type = __cpu_to_le32(WMI_TLV_PEER_TYPE_DEFAULT); /* FIXME */
+ cmd->peer_type = __cpu_to_le32(peer_type);
ether_addr_copy(cmd->peer_addr.addr, peer_addr);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer create\n");
@@ -2027,7 +2185,7 @@ ath10k_wmi_tlv_op_gen_set_ap_ps(struct ath10k *ar, u32 vdev_id, const u8 *mac,
if (!mac)
return ERR_PTR(-EINVAL);
- skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
if (!skb)
return ERR_PTR(-ENOMEM);
@@ -2485,6 +2643,387 @@ ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id,
return skb;
}
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id,
+ enum wmi_tdls_state state)
+{
+ struct wmi_tdls_set_state_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ void *ptr;
+ size_t len;
+ /* Set to options from wmi_tlv_tdls_options,
+ * for now none of them are enabled.
+ */
+ u32 options = 0;
+
+ len = sizeof(*tlv) + sizeof(*cmd);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_TDLS_SET_STATE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->state = __cpu_to_le32(state);
+ cmd->notification_interval_ms = __cpu_to_le32(5000);
+ cmd->tx_discovery_threshold = __cpu_to_le32(100);
+ cmd->tx_teardown_threshold = __cpu_to_le32(5);
+ cmd->rssi_teardown_threshold = __cpu_to_le32(-75);
+ cmd->rssi_delta = __cpu_to_le32(-20);
+ cmd->tdls_options = __cpu_to_le32(options);
+ cmd->tdls_peer_traffic_ind_window = __cpu_to_le32(2);
+ cmd->tdls_peer_traffic_response_timeout_ms = __cpu_to_le32(5000);
+ cmd->tdls_puapsd_mask = __cpu_to_le32(0xf);
+ cmd->tdls_puapsd_inactivity_time_ms = __cpu_to_le32(0);
+ cmd->tdls_puapsd_rx_frame_threshold = __cpu_to_le32(10);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv update fw tdls state %d for vdev %i\n",
+ state, vdev_id);
+ return skb;
+}
+
+static u32 ath10k_wmi_tlv_prepare_peer_qos(u8 uapsd_queues, u8 sp)
+{
+ u32 peer_qos = 0;
+
+ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
+ peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_VO;
+ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
+ peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_VI;
+ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
+ peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_BK;
+ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
+ peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_BE;
+
+ peer_qos |= SM(sp, WMI_TLV_TDLS_PEER_SP);
+
+ return peer_qos;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_tdls_peer_update(struct ath10k *ar,
+ const struct wmi_tdls_peer_update_cmd_arg *arg,
+ const struct wmi_tdls_peer_capab_arg *cap,
+ const struct wmi_channel_arg *chan_arg)
+{
+ struct wmi_tdls_peer_update_cmd *cmd;
+ struct wmi_tdls_peer_capab *peer_cap;
+ struct wmi_channel *chan;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ u32 peer_qos;
+ void *ptr;
+ int len;
+ int i;
+
+ len = sizeof(*tlv) + sizeof(*cmd) +
+ sizeof(*tlv) + sizeof(*peer_cap) +
+ sizeof(*tlv) + cap->peer_chan_len * sizeof(*chan);
+
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_TDLS_PEER_UPDATE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
+ ether_addr_copy(cmd->peer_macaddr.addr, arg->addr);
+ cmd->peer_state = __cpu_to_le32(arg->peer_state);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_TDLS_PEER_CAPABILITIES);
+ tlv->len = __cpu_to_le16(sizeof(*peer_cap));
+ peer_cap = (void *)tlv->value;
+ peer_qos = ath10k_wmi_tlv_prepare_peer_qos(cap->peer_uapsd_queues,
+ cap->peer_max_sp);
+ peer_cap->peer_qos = __cpu_to_le32(peer_qos);
+ peer_cap->buff_sta_support = __cpu_to_le32(cap->buff_sta_support);
+ peer_cap->off_chan_support = __cpu_to_le32(cap->off_chan_support);
+ peer_cap->peer_curr_operclass = __cpu_to_le32(cap->peer_curr_operclass);
+ peer_cap->self_curr_operclass = __cpu_to_le32(cap->self_curr_operclass);
+ peer_cap->peer_chan_len = __cpu_to_le32(cap->peer_chan_len);
+ peer_cap->peer_operclass_len = __cpu_to_le32(cap->peer_operclass_len);
+
+ for (i = 0; i < WMI_TDLS_MAX_SUPP_OPER_CLASSES; i++)
+ peer_cap->peer_operclass[i] = cap->peer_operclass[i];
+
+ peer_cap->is_peer_responder = __cpu_to_le32(cap->is_peer_responder);
+ peer_cap->pref_offchan_num = __cpu_to_le32(cap->pref_offchan_num);
+ peer_cap->pref_offchan_bw = __cpu_to_le32(cap->pref_offchan_bw);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*peer_cap);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = __cpu_to_le16(cap->peer_chan_len * sizeof(*chan));
+
+ ptr += sizeof(*tlv);
+
+ for (i = 0; i < cap->peer_chan_len; i++) {
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL);
+ tlv->len = __cpu_to_le16(sizeof(*chan));
+ chan = (void *)tlv->value;
+ ath10k_wmi_put_wmi_channel(chan, &chan_arg[i]);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*chan);
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi tlv tdls peer update vdev %i state %d n_chans %u\n",
+ arg->vdev_id, arg->peer_state, cap->peer_chan_len);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_wow_enable(struct ath10k *ar)
+{
+ struct wmi_tlv_wow_enable_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (struct wmi_tlv *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WOW_ENABLE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ cmd->enable = __cpu_to_le32(1);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv wow enable\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_wow_add_wakeup_event(struct ath10k *ar,
+ u32 vdev_id,
+ enum wmi_wow_wakeup_event event,
+ u32 enable)
+{
+ struct wmi_tlv_wow_add_del_event_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (struct wmi_tlv *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WOW_ADD_DEL_EVT_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->is_add = __cpu_to_le32(enable);
+ cmd->event_bitmap = __cpu_to_le32(1 << event);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv wow add wakeup event %s enable %d vdev_id %d\n",
+ wow_wakeup_event(event), enable, vdev_id);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_gen_wow_host_wakeup_ind(struct ath10k *ar)
+{
+ struct wmi_tlv_wow_host_wakeup_ind *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (struct wmi_tlv *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WOW_HOSTWAKEUP_FROM_SLEEP_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv wow host wakeup ind\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_wow_add_pattern(struct ath10k *ar, u32 vdev_id,
+ u32 pattern_id, const u8 *pattern,
+ const u8 *bitmask, int pattern_len,
+ int pattern_offset)
+{
+ struct wmi_tlv_wow_add_pattern_cmd *cmd;
+ struct wmi_tlv_wow_bitmap_pattern *bitmap;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ void *ptr;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd) +
+ sizeof(*tlv) + /* array struct */
+ sizeof(*tlv) + sizeof(*bitmap) + /* bitmap */
+ sizeof(*tlv) + /* empty ipv4 sync */
+ sizeof(*tlv) + /* empty ipv6 sync */
+ sizeof(*tlv) + /* empty magic */
+ sizeof(*tlv) + /* empty info timeout */
+ sizeof(*tlv) + sizeof(u32); /* ratelimit interval */
+
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ /* cmd */
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WOW_ADD_PATTERN_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->pattern_id = __cpu_to_le32(pattern_id);
+ cmd->pattern_type = __cpu_to_le32(WOW_BITMAP_PATTERN);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ /* bitmap */
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = __cpu_to_le16(sizeof(*tlv) + sizeof(*bitmap));
+
+ ptr += sizeof(*tlv);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WOW_BITMAP_PATTERN_T);
+ tlv->len = __cpu_to_le16(sizeof(*bitmap));
+ bitmap = (void *)tlv->value;
+
+ memcpy(bitmap->patternbuf, pattern, pattern_len);
+ memcpy(bitmap->bitmaskbuf, bitmask, pattern_len);
+ bitmap->pattern_offset = __cpu_to_le32(pattern_offset);
+ bitmap->pattern_len = __cpu_to_le32(pattern_len);
+ bitmap->bitmask_len = __cpu_to_le32(pattern_len);
+ bitmap->pattern_id = __cpu_to_le32(pattern_id);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*bitmap);
+
+ /* ipv4 sync */
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = __cpu_to_le16(0);
+
+ ptr += sizeof(*tlv);
+
+ /* ipv6 sync */
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = __cpu_to_le16(0);
+
+ ptr += sizeof(*tlv);
+
+ /* magic */
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = __cpu_to_le16(0);
+
+ ptr += sizeof(*tlv);
+
+ /* pattern info timeout */
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32);
+ tlv->len = __cpu_to_le16(0);
+
+ ptr += sizeof(*tlv);
+
+ /* ratelimit interval */
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32);
+ tlv->len = __cpu_to_le16(sizeof(u32));
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv wow add pattern vdev_id %d pattern_id %d, pattern_offset %d\n",
+ vdev_id, pattern_id, pattern_offset);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_wow_del_pattern(struct ath10k *ar, u32 vdev_id,
+ u32 pattern_id)
+{
+ struct wmi_tlv_wow_del_pattern_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (struct wmi_tlv *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WOW_DEL_PATTERN_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->pattern_id = __cpu_to_le32(pattern_id);
+ cmd->pattern_type = __cpu_to_le32(WOW_BITMAP_PATTERN);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv wow del pattern vdev_id %d pattern_id %d\n",
+ vdev_id, pattern_id);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_adaptive_qcs(struct ath10k *ar, bool enable)
+{
+ struct wmi_tlv_adaptive_qcs *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ void *ptr;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_RESMGR_ADAPTIVE_OCS_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->enable = __cpu_to_le32(enable ? 1 : 0);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv adaptive qcs %d\n", enable);
+ return skb;
+}
+
/****************/
/* TLV mappings */
/****************/
@@ -2609,6 +3148,9 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = {
.gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID,
.pdev_get_temperature_cmdid = WMI_TLV_CMD_UNSUPPORTED,
.vdev_set_wmm_params_cmdid = WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID,
+ .tdls_set_state_cmdid = WMI_TLV_TDLS_SET_STATE_CMDID,
+ .tdls_peer_update_cmdid = WMI_TLV_TDLS_PEER_UPDATE_CMDID,
+ .adaptive_qcs_cmdid = WMI_TLV_RESMGR_ADAPTIVE_OCS_CMDID,
};
static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = {
@@ -2736,6 +3278,8 @@ static const struct wmi_ops wmi_tlv_ops = {
.pull_svc_rdy = ath10k_wmi_tlv_op_pull_svc_rdy_ev,
.pull_rdy = ath10k_wmi_tlv_op_pull_rdy_ev,
.pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats,
+ .pull_roam_ev = ath10k_wmi_tlv_op_pull_roam_ev,
+ .pull_wow_event = ath10k_wmi_tlv_op_pull_wow_ev,
.gen_pdev_suspend = ath10k_wmi_tlv_op_gen_pdev_suspend,
.gen_pdev_resume = ath10k_wmi_tlv_op_gen_pdev_resume,
@@ -2781,6 +3325,14 @@ static const struct wmi_ops wmi_tlv_ops = {
.gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie,
.gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd,
.gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive,
+ .gen_wow_enable = ath10k_wmi_tlv_op_gen_wow_enable,
+ .gen_wow_add_wakeup_event = ath10k_wmi_tlv_op_gen_wow_add_wakeup_event,
+ .gen_wow_host_wakeup_ind = ath10k_wmi_tlv_gen_wow_host_wakeup_ind,
+ .gen_wow_add_pattern = ath10k_wmi_tlv_op_gen_wow_add_pattern,
+ .gen_wow_del_pattern = ath10k_wmi_tlv_op_gen_wow_del_pattern,
+ .gen_update_fw_tdls_state = ath10k_wmi_tlv_op_gen_update_fw_tdls_state,
+ .gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update,
+ .gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs,
};
/************/
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index a6c8280cc4b1..ad655c44afdb 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -1454,6 +1454,174 @@ struct wmi_tlv_stats_ev {
__le32 num_chan_stats;
} __packed;
+struct wmi_tlv_p2p_noa_ev {
+ __le32 vdev_id;
+} __packed;
+
+struct wmi_tlv_roam_ev {
+ __le32 vdev_id;
+ __le32 reason;
+ __le32 rssi;
+} __packed;
+
+struct wmi_tlv_wow_add_del_event_cmd {
+ __le32 vdev_id;
+ __le32 is_add;
+ __le32 event_bitmap;
+} __packed;
+
+struct wmi_tlv_wow_enable_cmd {
+ __le32 enable;
+} __packed;
+
+struct wmi_tlv_wow_host_wakeup_ind {
+ __le32 reserved;
+} __packed;
+
+struct wmi_tlv_wow_event_info {
+ __le32 vdev_id;
+ __le32 flag;
+ __le32 wake_reason;
+ __le32 data_len;
+} __packed;
+
+enum wmi_tlv_pattern_type {
+ WOW_PATTERN_MIN = 0,
+ WOW_BITMAP_PATTERN = WOW_PATTERN_MIN,
+ WOW_IPV4_SYNC_PATTERN,
+ WOW_IPV6_SYNC_PATTERN,
+ WOW_WILD_CARD_PATTERN,
+ WOW_TIMER_PATTERN,
+ WOW_MAGIC_PATTERN,
+ WOW_IPV6_RA_PATTERN,
+ WOW_IOAC_PKT_PATTERN,
+ WOW_IOAC_TMR_PATTERN,
+ WOW_PATTERN_MAX
+};
+
+#define WOW_DEFAULT_BITMAP_PATTERN_SIZE 148
+#define WOW_DEFAULT_BITMASK_SIZE 148
+
+struct wmi_tlv_wow_bitmap_pattern {
+ u8 patternbuf[WOW_DEFAULT_BITMAP_PATTERN_SIZE];
+ u8 bitmaskbuf[WOW_DEFAULT_BITMASK_SIZE];
+ __le32 pattern_offset;
+ __le32 pattern_len;
+ __le32 bitmask_len;
+ __le32 pattern_id;
+} __packed;
+
+struct wmi_tlv_wow_add_pattern_cmd {
+ __le32 vdev_id;
+ __le32 pattern_id;
+ __le32 pattern_type;
+} __packed;
+
+struct wmi_tlv_wow_del_pattern_cmd {
+ __le32 vdev_id;
+ __le32 pattern_id;
+ __le32 pattern_type;
+} __packed;
+
+/* TDLS Options */
+enum wmi_tlv_tdls_options {
+ WMI_TLV_TDLS_OFFCHAN_EN = BIT(0),
+ WMI_TLV_TDLS_BUFFER_STA_EN = BIT(1),
+ WMI_TLV_TDLS_SLEEP_STA_EN = BIT(2),
+};
+
+struct wmi_tdls_set_state_cmd {
+ __le32 vdev_id;
+ __le32 state;
+ __le32 notification_interval_ms;
+ __le32 tx_discovery_threshold;
+ __le32 tx_teardown_threshold;
+ __le32 rssi_teardown_threshold;
+ __le32 rssi_delta;
+ __le32 tdls_options;
+ __le32 tdls_peer_traffic_ind_window;
+ __le32 tdls_peer_traffic_response_timeout_ms;
+ __le32 tdls_puapsd_mask;
+ __le32 tdls_puapsd_inactivity_time_ms;
+ __le32 tdls_puapsd_rx_frame_threshold;
+} __packed;
+
+struct wmi_tdls_peer_update_cmd {
+ __le32 vdev_id;
+ struct wmi_mac_addr peer_macaddr;
+ __le32 peer_state;
+} __packed;
+
+enum {
+ WMI_TLV_TDLS_PEER_QOS_AC_VO = BIT(0),
+ WMI_TLV_TDLS_PEER_QOS_AC_VI = BIT(1),
+ WMI_TLV_TDLS_PEER_QOS_AC_BK = BIT(2),
+ WMI_TLV_TDLS_PEER_QOS_AC_BE = BIT(3),
+};
+
+#define WMI_TLV_TDLS_PEER_SP_MASK 0x60
+#define WMI_TLV_TDLS_PEER_SP_LSB 5
+
+struct wmi_tdls_peer_capab {
+ __le32 peer_qos;
+ __le32 buff_sta_support;
+ __le32 off_chan_support;
+ __le32 peer_curr_operclass;
+ __le32 self_curr_operclass;
+ __le32 peer_chan_len;
+ __le32 peer_operclass_len;
+ u8 peer_operclass[WMI_TDLS_MAX_SUPP_OPER_CLASSES];
+ __le32 is_peer_responder;
+ __le32 pref_offchan_num;
+ __le32 pref_offchan_bw;
+} __packed;
+
+struct wmi_tlv_adaptive_qcs {
+ __le32 enable;
+} __packed;
+
+/**
+ * wmi_tlv_tx_pause_id - firmware tx queue pause reason types
+ *
+ * @WMI_TLV_TX_PAUSE_ID_MCC: used for by multi-channel firmware scheduler.
+ * Only vdev_map is valid.
+ * @WMI_TLV_TX_PAUSE_ID_AP_PEER_PS: peer in AP mode is asleep.
+ * Only peer_id is valid.
+ * @WMI_TLV_TX_PAUSE_ID_AP_PEER_UAPSD: Only peer_id and tid_map are valid.
+ * @WMI_TLV_TX_PAUSE_ID_P2P_CLI_NOA: Only vdev_map is valid.
+ * @WMI_TLV_TX_PAUSE_ID_P2P_GO_PS: Only vdev_map is valid.
+ * @WMI_TLV_TX_PAUSE_ID_STA_ADD_BA: Only peer_id and tid_map are valid.
+ * @WMI_TLV_TX_PAUSE_ID_AP_PS: When all peers are asleep in AP mode. Only
+ * vdev_map is valid.
+ * @WMI_TLV_TX_PAUSE_ID_IBSS_PS: When all peers are asleep in IBSS mode. Only
+ * vdev_map is valid.
+ * @WMI_TLV_TX_PAUSE_ID_HOST: Host itself requested tx pause.
+ */
+enum wmi_tlv_tx_pause_id {
+ WMI_TLV_TX_PAUSE_ID_MCC = 1,
+ WMI_TLV_TX_PAUSE_ID_AP_PEER_PS = 2,
+ WMI_TLV_TX_PAUSE_ID_AP_PEER_UAPSD = 3,
+ WMI_TLV_TX_PAUSE_ID_P2P_CLI_NOA = 4,
+ WMI_TLV_TX_PAUSE_ID_P2P_GO_PS = 5,
+ WMI_TLV_TX_PAUSE_ID_STA_ADD_BA = 6,
+ WMI_TLV_TX_PAUSE_ID_AP_PS = 7,
+ WMI_TLV_TX_PAUSE_ID_IBSS_PS = 8,
+ WMI_TLV_TX_PAUSE_ID_HOST = 21,
+};
+
+enum wmi_tlv_tx_pause_action {
+ WMI_TLV_TX_PAUSE_ACTION_STOP,
+ WMI_TLV_TX_PAUSE_ACTION_WAKE,
+};
+
+struct wmi_tlv_tx_pause_ev {
+ __le32 pause_id;
+ __le32 action;
+ __le32 vdev_map;
+ __le32 peer_id;
+ __le32 tid_map;
+} __packed;
+
void ath10k_wmi_tlv_attach(struct ath10k *ar);
#endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c7ea77edce24..6c046c244705 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -26,6 +26,8 @@
#include "mac.h"
#include "testmode.h"
#include "wmi-ops.h"
+#include "p2p.h"
+#include "hw.h"
/* MAIN WMI cmd track */
static struct wmi_cmd_map wmi_cmd_map = {
@@ -884,20 +886,24 @@ void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)
{
- int ret;
+ unsigned long time_left;
- ret = wait_for_completion_timeout(&ar->wmi.service_ready,
- WMI_SERVICE_READY_TIMEOUT_HZ);
- return ret;
+ time_left = wait_for_completion_timeout(&ar->wmi.service_ready,
+ WMI_SERVICE_READY_TIMEOUT_HZ);
+ if (!time_left)
+ return -ETIMEDOUT;
+ return 0;
}
int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar)
{
- int ret;
+ unsigned long time_left;
- ret = wait_for_completion_timeout(&ar->wmi.unified_ready,
- WMI_UNIFIED_READY_TIMEOUT_HZ);
- return ret;
+ time_left = wait_for_completion_timeout(&ar->wmi.unified_ready,
+ WMI_UNIFIED_READY_TIMEOUT_HZ);
+ if (!time_left)
+ return -ETIMEDOUT;
+ return 0;
}
struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len)
@@ -1351,63 +1357,6 @@ static inline enum ieee80211_band phy_mode_to_band(u32 phy_mode)
return band;
}
-static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band)
-{
- u8 rate_idx = 0;
-
- /* rate in Kbps */
- switch (rate) {
- case 1000:
- rate_idx = 0;
- break;
- case 2000:
- rate_idx = 1;
- break;
- case 5500:
- rate_idx = 2;
- break;
- case 11000:
- rate_idx = 3;
- break;
- case 6000:
- rate_idx = 4;
- break;
- case 9000:
- rate_idx = 5;
- break;
- case 12000:
- rate_idx = 6;
- break;
- case 18000:
- rate_idx = 7;
- break;
- case 24000:
- rate_idx = 8;
- break;
- case 36000:
- rate_idx = 9;
- break;
- case 48000:
- rate_idx = 10;
- break;
- case 54000:
- rate_idx = 11;
- break;
- default:
- break;
- }
-
- if (band == IEEE80211_BAND_5GHZ) {
- if (rate_idx > 3)
- /* Omit CCK rates */
- rate_idx -= 4;
- else
- rate_idx = 0;
- }
-
- return rate_idx;
-}
-
/* If keys are configured, HW decrypts all frames
* with protected bit set. Mark such frames as decrypted.
*/
@@ -1489,6 +1438,7 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
struct wmi_mgmt_rx_ev_arg arg = {};
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr;
+ struct ieee80211_supported_band *sband;
u32 rx_status;
u32 channel;
u32 phy_mode;
@@ -1501,6 +1451,7 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
ret = ath10k_wmi_pull_mgmt_rx(ar, skb, &arg);
if (ret) {
ath10k_warn(ar, "failed to parse mgmt rx event: %d\n", ret);
+ dev_kfree_skb(skb);
return ret;
}
@@ -1559,9 +1510,11 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
if (phy_mode == MODE_11B && status->band == IEEE80211_BAND_5GHZ)
ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
+ sband = &ar->mac.sbands[status->band];
+
status->freq = ieee80211_channel_to_frequency(channel, status->band);
status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR;
- status->rate_idx = get_rate_idx(rate, status->band);
+ status->rate_idx = ath10k_mac_bitrate_to_idx(sband, rate / 100);
hdr = (struct ieee80211_hdr *)skb->data;
fc = le16_to_cpu(hdr->frame_control);
@@ -1585,6 +1538,9 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
}
}
+ if (ieee80211_is_beacon(hdr->frame_control))
+ ath10k_mac_handle_beacon(ar, skb);
+
ath10k_dbg(ar, ATH10K_DBG_MGMT,
"event mgmt rx skb %p len %d ftype %02x stype %02x\n",
skb, skb->len,
@@ -1682,20 +1638,22 @@ void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
}
if (cmd_flags & WMI_CHAN_INFO_FLAG_COMPLETE) {
- /* During scanning chan info is reported twice for each
- * visited channel. The reported cycle count is global
- * and per-channel cycle count must be calculated */
-
- cycle_count -= ar->survey_last_cycle_count;
- rx_clear_count -= ar->survey_last_rx_clear_count;
-
- survey = &ar->survey[idx];
- survey->time = WMI_CHAN_INFO_MSEC(cycle_count);
- survey->time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count);
- survey->noise = noise_floor;
- survey->filled = SURVEY_INFO_TIME |
- SURVEY_INFO_TIME_RX |
- SURVEY_INFO_NOISE_DBM;
+ if (ar->ch_info_can_report_survey) {
+ survey = &ar->survey[idx];
+ survey->noise = noise_floor;
+ survey->filled = SURVEY_INFO_NOISE_DBM;
+
+ ath10k_hw_fill_survey_time(ar,
+ survey,
+ cycle_count,
+ rx_clear_count,
+ ar->survey_last_cycle_count,
+ ar->survey_last_rx_clear_count);
+ }
+
+ ar->ch_info_can_report_survey = false;
+ } else {
+ ar->ch_info_can_report_survey = true;
}
ar->survey_last_rx_clear_count = rx_clear_count;
@@ -2276,109 +2234,25 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
tim->bitmap_ctrl, pvm_len);
}
-static void ath10k_p2p_fill_noa_ie(u8 *data, u32 len,
- const struct wmi_p2p_noa_info *noa)
-{
- struct ieee80211_p2p_noa_attr *noa_attr;
- u8 ctwindow_oppps = noa->ctwindow_oppps;
- u8 ctwindow = ctwindow_oppps >> WMI_P2P_OPPPS_CTWINDOW_OFFSET;
- bool oppps = !!(ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT);
- __le16 *noa_attr_len;
- u16 attr_len;
- u8 noa_descriptors = noa->num_descriptors;
- int i;
-
- /* P2P IE */
- data[0] = WLAN_EID_VENDOR_SPECIFIC;
- data[1] = len - 2;
- data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
- data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
- data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
- data[5] = WLAN_OUI_TYPE_WFA_P2P;
-
- /* NOA ATTR */
- data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE;
- noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */
- noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9];
-
- noa_attr->index = noa->index;
- noa_attr->oppps_ctwindow = ctwindow;
- if (oppps)
- noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT;
-
- for (i = 0; i < noa_descriptors; i++) {
- noa_attr->desc[i].count =
- __le32_to_cpu(noa->descriptors[i].type_count);
- noa_attr->desc[i].duration = noa->descriptors[i].duration;
- noa_attr->desc[i].interval = noa->descriptors[i].interval;
- noa_attr->desc[i].start_time = noa->descriptors[i].start_time;
- }
-
- attr_len = 2; /* index + oppps_ctwindow */
- attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc);
- *noa_attr_len = __cpu_to_le16(attr_len);
-}
-
-static u32 ath10k_p2p_calc_noa_ie_len(const struct wmi_p2p_noa_info *noa)
-{
- u32 len = 0;
- u8 noa_descriptors = noa->num_descriptors;
- u8 opp_ps_info = noa->ctwindow_oppps;
- bool opps_enabled = !!(opp_ps_info & WMI_P2P_OPPPS_ENABLE_BIT);
-
- if (!noa_descriptors && !opps_enabled)
- return len;
-
- len += 1 + 1 + 4; /* EID + len + OUI */
- len += 1 + 2; /* noa attr + attr len */
- len += 1 + 1; /* index + oppps_ctwindow */
- len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc);
-
- return len;
-}
-
static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif,
struct sk_buff *bcn,
const struct wmi_p2p_noa_info *noa)
{
- u8 *new_data, *old_data = arvif->u.ap.noa_data;
- u32 new_len;
-
if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
return;
ath10k_dbg(ar, ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed);
- if (noa->changed & WMI_P2P_NOA_CHANGED_BIT) {
- new_len = ath10k_p2p_calc_noa_ie_len(noa);
- if (!new_len)
- goto cleanup;
-
- new_data = kmalloc(new_len, GFP_ATOMIC);
- if (!new_data)
- goto cleanup;
-
- ath10k_p2p_fill_noa_ie(new_data, new_len, noa);
- spin_lock_bh(&ar->data_lock);
- arvif->u.ap.noa_data = new_data;
- arvif->u.ap.noa_len = new_len;
- spin_unlock_bh(&ar->data_lock);
- kfree(old_data);
- }
+ if (noa->changed & WMI_P2P_NOA_CHANGED_BIT)
+ ath10k_p2p_noa_update(arvif, noa);
if (arvif->u.ap.noa_data)
if (!pskb_expand_head(bcn, 0, arvif->u.ap.noa_len, GFP_ATOMIC))
memcpy(skb_put(bcn, arvif->u.ap.noa_len),
arvif->u.ap.noa_data,
arvif->u.ap.noa_len);
- return;
-cleanup:
- spin_lock_bh(&ar->data_lock);
- arvif->u.ap.noa_data = NULL;
- arvif->u.ap.noa_len = 0;
- spin_unlock_bh(&ar->data_lock);
- kfree(old_data);
+ return;
}
static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb,
@@ -2555,6 +2429,7 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
u64 tsf)
{
u32 reg0, reg1, tsf32l;
+ struct ieee80211_channel *ch;
struct pulse_event pe;
u64 tsf64;
u8 rssi, width;
@@ -2583,6 +2458,15 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
if (!ar->dfs_detector)
return;
+ spin_lock_bh(&ar->data_lock);
+ ch = ar->rx_channel;
+ spin_unlock_bh(&ar->data_lock);
+
+ if (!ch) {
+ ath10k_warn(ar, "failed to derive channel for radar pulse, treating as radar\n");
+ goto radar_detected;
+ }
+
/* report event to DFS pattern detector */
tsf32l = __le32_to_cpu(phyerr->tsf_timestamp);
tsf64 = tsf & (~0xFFFFFFFFULL);
@@ -2598,10 +2482,10 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
rssi = 0;
pe.ts = tsf64;
- pe.freq = ar->hw->conf.chandef.chan->center_freq;
+ pe.freq = ch->center_freq;
pe.width = width;
pe.rssi = rssi;
-
+ pe.chirp = (MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP) != 0);
ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"dfs add pulse freq: %d, width: %d, rssi %d, tsf: %llX\n",
pe.freq, pe.width, pe.rssi, pe.ts);
@@ -2614,6 +2498,7 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
return;
}
+radar_detected:
ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs radar detected\n");
ATH10K_DFS_STAT_INC(ar, radar_detected);
@@ -2872,7 +2757,43 @@ void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb)
{
- ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n");
+ struct wmi_roam_ev_arg arg = {};
+ int ret;
+ u32 vdev_id;
+ u32 reason;
+ s32 rssi;
+
+ ret = ath10k_wmi_pull_roam_ev(ar, skb, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to parse roam event: %d\n", ret);
+ return;
+ }
+
+ vdev_id = __le32_to_cpu(arg.vdev_id);
+ reason = __le32_to_cpu(arg.reason);
+ rssi = __le32_to_cpu(arg.rssi);
+ rssi += WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi roam event vdev %u reason 0x%08x rssi %d\n",
+ vdev_id, reason, rssi);
+
+ if (reason >= WMI_ROAM_REASON_MAX)
+ ath10k_warn(ar, "ignoring unknown roam event reason %d on vdev %i\n",
+ reason, vdev_id);
+
+ switch (reason) {
+ case WMI_ROAM_REASON_BEACON_MISS:
+ ath10k_mac_handle_beacon_miss(ar, vdev_id);
+ break;
+ case WMI_ROAM_REASON_BETTER_AP:
+ case WMI_ROAM_REASON_LOW_RSSI:
+ case WMI_ROAM_REASON_SUITABLE_AP_FOUND:
+ case WMI_ROAM_REASON_HO_FAILED:
+ ath10k_warn(ar, "ignoring not implemented roam event reason %d on vdev %i\n",
+ reason, vdev_id);
+ break;
+ }
}
void ath10k_wmi_event_profile_match(struct ath10k *ar, struct sk_buff *skb)
@@ -2942,7 +2863,19 @@ void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, struct sk_buff *skb)
void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, struct sk_buff *skb)
{
- ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n");
+ struct wmi_wow_ev_arg ev = {};
+ int ret;
+
+ complete(&ar->wow.wakeup_completed);
+
+ ret = ath10k_wmi_pull_wow_event(ar, skb, &ev);
+ if (ret) {
+ ath10k_warn(ar, "failed to parse wow wakeup event: %d\n", ret);
+ return;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wow wakeup host reason %s\n",
+ wow_reason(ev.wake_reason));
}
void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb)
@@ -3231,6 +3164,21 @@ static int ath10k_wmi_op_pull_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
return 0;
}
+static int ath10k_wmi_op_pull_roam_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_roam_ev_arg *arg)
+{
+ struct wmi_roam_ev *ev = (void *)skb->data;
+
+ if (skb->len < sizeof(*ev))
+ return -EPROTO;
+
+ skb_pull(skb, sizeof(*ev));
+ arg->vdev_id = ev->vdev_id;
+ arg->reason = ev->reason;
+
+ return 0;
+}
+
int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_rdy_ev_arg arg = {};
@@ -3275,7 +3223,7 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
- return;
+ goto out;
trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
@@ -3379,6 +3327,7 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
break;
}
+out:
dev_kfree_skb(skb);
}
@@ -3392,7 +3341,7 @@ static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb)
id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
- return;
+ goto out;
trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
@@ -3515,7 +3464,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
- return;
+ goto out;
trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
@@ -3623,6 +3572,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
break;
}
+out:
dev_kfree_skb(skb);
}
@@ -3989,6 +3939,8 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
cmd = (struct wmi_init_cmd_10_2 *)buf->data;
features = WMI_10_2_RX_BATCH_MODE;
+ if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map))
+ features |= WMI_10_2_COEX_GPIO;
cmd->resource_config.feature_mask = __cpu_to_le32(features);
memcpy(&cmd->resource_config.common, &config, sizeof(config));
@@ -4315,8 +4267,6 @@ ath10k_wmi_op_gen_vdev_start(struct ath10k *ar,
const char *cmdname;
u32 flags = 0;
- if (WARN_ON(arg->ssid && arg->ssid_len == 0))
- return ERR_PTR(-EINVAL);
if (WARN_ON(arg->hidden_ssid && !arg->ssid))
return ERR_PTR(-EINVAL);
if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid)))
@@ -4539,7 +4489,8 @@ ath10k_wmi_op_gen_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id,
static struct sk_buff *
ath10k_wmi_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
- const u8 peer_addr[ETH_ALEN])
+ const u8 peer_addr[ETH_ALEN],
+ enum wmi_peer_type peer_type)
{
struct wmi_peer_create_cmd *cmd;
struct sk_buff *skb;
@@ -5223,6 +5174,7 @@ static const struct wmi_ops wmi_ops = {
.pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev,
.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
.pull_fw_stats = ath10k_wmi_main_op_pull_fw_stats,
+ .pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
@@ -5268,6 +5220,7 @@ static const struct wmi_ops wmi_ops = {
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
+ /* .gen_adaptive_qcs not implemented */
};
static const struct wmi_ops wmi_10_1_ops = {
@@ -5290,6 +5243,7 @@ static const struct wmi_ops wmi_10_1_ops = {
.pull_swba = ath10k_wmi_op_pull_swba_ev,
.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
+ .pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
@@ -5330,6 +5284,7 @@ static const struct wmi_ops wmi_10_1_ops = {
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
+ /* .gen_adaptive_qcs not implemented */
};
static const struct wmi_ops wmi_10_2_ops = {
@@ -5353,6 +5308,7 @@ static const struct wmi_ops wmi_10_2_ops = {
.pull_swba = ath10k_wmi_op_pull_swba_ev,
.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
+ .pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
@@ -5413,6 +5369,7 @@ static const struct wmi_ops wmi_10_2_4_ops = {
.pull_swba = ath10k_wmi_op_pull_swba_ev,
.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
+ .pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
@@ -5452,6 +5409,7 @@ static const struct wmi_ops wmi_10_2_4_ops = {
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
+ /* .gen_adaptive_qcs not implemented */
};
int ath10k_wmi_attach(struct ath10k *ar)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index adf935bf0580..cf44a3d080a3 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -148,6 +148,8 @@ enum wmi_service {
WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
WMI_SERVICE_MDNS_OFFLOAD,
WMI_SERVICE_SAP_AUTH_OFFLOAD,
+ WMI_SERVICE_ATF,
+ WMI_SERVICE_COEX_GPIO,
/* keep last */
WMI_SERVICE_MAX,
@@ -177,6 +179,8 @@ enum wmi_10x_service {
WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT,
WMI_10X_SERVICE_FORCE_FW_HANG,
WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+ WMI_10X_SERVICE_ATF,
+ WMI_10X_SERVICE_COEX_GPIO,
};
enum wmi_main_service {
@@ -293,6 +297,8 @@ static inline char *wmi_service_name(int service_id)
SVCSTR(WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT);
SVCSTR(WMI_SERVICE_MDNS_OFFLOAD);
SVCSTR(WMI_SERVICE_SAP_AUTH_OFFLOAD);
+ SVCSTR(WMI_SERVICE_ATF);
+ SVCSTR(WMI_SERVICE_COEX_GPIO);
default:
return NULL;
}
@@ -356,6 +362,10 @@ static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out,
WMI_SERVICE_FORCE_FW_HANG, len);
SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT, len);
+ SVCMAP(WMI_10X_SERVICE_ATF,
+ WMI_SERVICE_ATF, len);
+ SVCMAP(WMI_10X_SERVICE_COEX_GPIO,
+ WMI_SERVICE_COEX_GPIO, len);
}
static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out,
@@ -552,6 +562,9 @@ struct wmi_cmd_map {
u32 gpio_output_cmdid;
u32 pdev_get_temperature_cmdid;
u32 vdev_set_wmm_params_cmdid;
+ u32 tdls_set_state_cmdid;
+ u32 tdls_peer_update_cmdid;
+ u32 adaptive_qcs_cmdid;
};
/*
@@ -1952,6 +1965,7 @@ struct wmi_resource_config_10x {
enum wmi_10_2_feature_mask {
WMI_10_2_RX_BATCH_MODE = BIT(0),
WMI_10_2_ATF_CONFIG = BIT(1),
+ WMI_10_2_COEX_GPIO = BIT(3),
};
struct wmi_resource_config_10_2 {
@@ -2166,6 +2180,7 @@ struct wmi_start_scan_arg {
u32 max_scan_time;
u32 probe_delay;
u32 scan_ctrl_flags;
+ u32 burst_duration_ms;
u32 ie_len;
u32 n_channels;
@@ -4333,6 +4348,12 @@ struct wmi_peer_create_cmd {
struct wmi_mac_addr peer_macaddr;
} __packed;
+enum wmi_peer_type {
+ WMI_PEER_TYPE_DEFAULT = 0,
+ WMI_PEER_TYPE_BSS = 1,
+ WMI_PEER_TYPE_TDLS = 2,
+};
+
struct wmi_peer_delete_cmd {
__le32 vdev_id;
struct wmi_mac_addr peer_macaddr;
@@ -4645,9 +4666,6 @@ struct wmi_peer_sta_kickout_event {
#define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0)
-/* FIXME: empirically extrapolated */
-#define WMI_CHAN_INFO_MSEC(x) ((x) / 76595)
-
/* Beacon filter wmi command info */
#define BCN_FLT_MAX_SUPPORTED_IES 256
#define BCN_FLT_MAX_ELEMS_IE_LIST (BCN_FLT_MAX_SUPPORTED_IES / 32)
@@ -4769,6 +4787,22 @@ struct wmi_dbglog_cfg_cmd {
__le32 config_valid;
} __packed;
+enum wmi_roam_reason {
+ WMI_ROAM_REASON_BETTER_AP = 1,
+ WMI_ROAM_REASON_BEACON_MISS = 2,
+ WMI_ROAM_REASON_LOW_RSSI = 3,
+ WMI_ROAM_REASON_SUITABLE_AP_FOUND = 4,
+ WMI_ROAM_REASON_HO_FAILED = 5,
+
+ /* keep last */
+ WMI_ROAM_REASON_MAX,
+};
+
+struct wmi_roam_ev {
+ __le32 vdev_id;
+ __le32 reason;
+} __packed;
+
#define ATH10K_FRAGMT_THRESHOLD_MIN 540
#define ATH10K_FRAGMT_THRESHOLD_MAX 2346
@@ -4857,11 +4891,200 @@ struct wmi_rdy_ev_arg {
const u8 *mac_addr;
};
+struct wmi_roam_ev_arg {
+ __le32 vdev_id;
+ __le32 reason;
+ __le32 rssi;
+};
+
struct wmi_pdev_temperature_event {
/* temperature value in Celcius degree */
__le32 temperature;
} __packed;
+/* WOW structures */
+enum wmi_wow_wakeup_event {
+ WOW_BMISS_EVENT = 0,
+ WOW_BETTER_AP_EVENT,
+ WOW_DEAUTH_RECVD_EVENT,
+ WOW_MAGIC_PKT_RECVD_EVENT,
+ WOW_GTK_ERR_EVENT,
+ WOW_FOURWAY_HSHAKE_EVENT,
+ WOW_EAPOL_RECVD_EVENT,
+ WOW_NLO_DETECTED_EVENT,
+ WOW_DISASSOC_RECVD_EVENT,
+ WOW_PATTERN_MATCH_EVENT,
+ WOW_CSA_IE_EVENT,
+ WOW_PROBE_REQ_WPS_IE_EVENT,
+ WOW_AUTH_REQ_EVENT,
+ WOW_ASSOC_REQ_EVENT,
+ WOW_HTT_EVENT,
+ WOW_RA_MATCH_EVENT,
+ WOW_HOST_AUTO_SHUTDOWN_EVENT,
+ WOW_IOAC_MAGIC_EVENT,
+ WOW_IOAC_SHORT_EVENT,
+ WOW_IOAC_EXTEND_EVENT,
+ WOW_IOAC_TIMER_EVENT,
+ WOW_DFS_PHYERR_RADAR_EVENT,
+ WOW_BEACON_EVENT,
+ WOW_CLIENT_KICKOUT_EVENT,
+ WOW_EVENT_MAX,
+};
+
+#define C2S(x) case x: return #x
+
+static inline const char *wow_wakeup_event(enum wmi_wow_wakeup_event ev)
+{
+ switch (ev) {
+ C2S(WOW_BMISS_EVENT);
+ C2S(WOW_BETTER_AP_EVENT);
+ C2S(WOW_DEAUTH_RECVD_EVENT);
+ C2S(WOW_MAGIC_PKT_RECVD_EVENT);
+ C2S(WOW_GTK_ERR_EVENT);
+ C2S(WOW_FOURWAY_HSHAKE_EVENT);
+ C2S(WOW_EAPOL_RECVD_EVENT);
+ C2S(WOW_NLO_DETECTED_EVENT);
+ C2S(WOW_DISASSOC_RECVD_EVENT);
+ C2S(WOW_PATTERN_MATCH_EVENT);
+ C2S(WOW_CSA_IE_EVENT);
+ C2S(WOW_PROBE_REQ_WPS_IE_EVENT);
+ C2S(WOW_AUTH_REQ_EVENT);
+ C2S(WOW_ASSOC_REQ_EVENT);
+ C2S(WOW_HTT_EVENT);
+ C2S(WOW_RA_MATCH_EVENT);
+ C2S(WOW_HOST_AUTO_SHUTDOWN_EVENT);
+ C2S(WOW_IOAC_MAGIC_EVENT);
+ C2S(WOW_IOAC_SHORT_EVENT);
+ C2S(WOW_IOAC_EXTEND_EVENT);
+ C2S(WOW_IOAC_TIMER_EVENT);
+ C2S(WOW_DFS_PHYERR_RADAR_EVENT);
+ C2S(WOW_BEACON_EVENT);
+ C2S(WOW_CLIENT_KICKOUT_EVENT);
+ C2S(WOW_EVENT_MAX);
+ default:
+ return NULL;
+ }
+}
+
+enum wmi_wow_wake_reason {
+ WOW_REASON_UNSPECIFIED = -1,
+ WOW_REASON_NLOD = 0,
+ WOW_REASON_AP_ASSOC_LOST,
+ WOW_REASON_LOW_RSSI,
+ WOW_REASON_DEAUTH_RECVD,
+ WOW_REASON_DISASSOC_RECVD,
+ WOW_REASON_GTK_HS_ERR,
+ WOW_REASON_EAP_REQ,
+ WOW_REASON_FOURWAY_HS_RECV,
+ WOW_REASON_TIMER_INTR_RECV,
+ WOW_REASON_PATTERN_MATCH_FOUND,
+ WOW_REASON_RECV_MAGIC_PATTERN,
+ WOW_REASON_P2P_DISC,
+ WOW_REASON_WLAN_HB,
+ WOW_REASON_CSA_EVENT,
+ WOW_REASON_PROBE_REQ_WPS_IE_RECV,
+ WOW_REASON_AUTH_REQ_RECV,
+ WOW_REASON_ASSOC_REQ_RECV,
+ WOW_REASON_HTT_EVENT,
+ WOW_REASON_RA_MATCH,
+ WOW_REASON_HOST_AUTO_SHUTDOWN,
+ WOW_REASON_IOAC_MAGIC_EVENT,
+ WOW_REASON_IOAC_SHORT_EVENT,
+ WOW_REASON_IOAC_EXTEND_EVENT,
+ WOW_REASON_IOAC_TIMER_EVENT,
+ WOW_REASON_ROAM_HO,
+ WOW_REASON_DFS_PHYERR_RADADR_EVENT,
+ WOW_REASON_BEACON_RECV,
+ WOW_REASON_CLIENT_KICKOUT_EVENT,
+ WOW_REASON_DEBUG_TEST = 0xFF,
+};
+
+static inline const char *wow_reason(enum wmi_wow_wake_reason reason)
+{
+ switch (reason) {
+ C2S(WOW_REASON_UNSPECIFIED);
+ C2S(WOW_REASON_NLOD);
+ C2S(WOW_REASON_AP_ASSOC_LOST);
+ C2S(WOW_REASON_LOW_RSSI);
+ C2S(WOW_REASON_DEAUTH_RECVD);
+ C2S(WOW_REASON_DISASSOC_RECVD);
+ C2S(WOW_REASON_GTK_HS_ERR);
+ C2S(WOW_REASON_EAP_REQ);
+ C2S(WOW_REASON_FOURWAY_HS_RECV);
+ C2S(WOW_REASON_TIMER_INTR_RECV);
+ C2S(WOW_REASON_PATTERN_MATCH_FOUND);
+ C2S(WOW_REASON_RECV_MAGIC_PATTERN);
+ C2S(WOW_REASON_P2P_DISC);
+ C2S(WOW_REASON_WLAN_HB);
+ C2S(WOW_REASON_CSA_EVENT);
+ C2S(WOW_REASON_PROBE_REQ_WPS_IE_RECV);
+ C2S(WOW_REASON_AUTH_REQ_RECV);
+ C2S(WOW_REASON_ASSOC_REQ_RECV);
+ C2S(WOW_REASON_HTT_EVENT);
+ C2S(WOW_REASON_RA_MATCH);
+ C2S(WOW_REASON_HOST_AUTO_SHUTDOWN);
+ C2S(WOW_REASON_IOAC_MAGIC_EVENT);
+ C2S(WOW_REASON_IOAC_SHORT_EVENT);
+ C2S(WOW_REASON_IOAC_EXTEND_EVENT);
+ C2S(WOW_REASON_IOAC_TIMER_EVENT);
+ C2S(WOW_REASON_ROAM_HO);
+ C2S(WOW_REASON_DFS_PHYERR_RADADR_EVENT);
+ C2S(WOW_REASON_BEACON_RECV);
+ C2S(WOW_REASON_CLIENT_KICKOUT_EVENT);
+ C2S(WOW_REASON_DEBUG_TEST);
+ default:
+ return NULL;
+ }
+}
+
+#undef C2S
+
+struct wmi_wow_ev_arg {
+ u32 vdev_id;
+ u32 flag;
+ enum wmi_wow_wake_reason wake_reason;
+ u32 data_len;
+};
+
+#define WOW_MIN_PATTERN_SIZE 1
+#define WOW_MAX_PATTERN_SIZE 148
+#define WOW_MAX_PKT_OFFSET 128
+
+enum wmi_tdls_state {
+ WMI_TDLS_DISABLE,
+ WMI_TDLS_ENABLE_PASSIVE,
+ WMI_TDLS_ENABLE_ACTIVE,
+};
+
+enum wmi_tdls_peer_state {
+ WMI_TDLS_PEER_STATE_PEERING,
+ WMI_TDLS_PEER_STATE_CONNECTED,
+ WMI_TDLS_PEER_STATE_TEARDOWN,
+};
+
+struct wmi_tdls_peer_update_cmd_arg {
+ u32 vdev_id;
+ enum wmi_tdls_peer_state peer_state;
+ u8 addr[ETH_ALEN];
+};
+
+#define WMI_TDLS_MAX_SUPP_OPER_CLASSES 32
+
+struct wmi_tdls_peer_capab_arg {
+ u8 peer_uapsd_queues;
+ u8 peer_max_sp;
+ u32 buff_sta_support;
+ u32 off_chan_support;
+ u32 peer_curr_operclass;
+ u32 self_curr_operclass;
+ u32 peer_chan_len;
+ u32 peer_operclass_len;
+ u8 peer_operclass[WMI_TDLS_MAX_SUPP_OPER_CLASSES];
+ u32 is_peer_responder;
+ u32 pref_offchan_num;
+ u32 pref_offchan_bw;
+};
+
struct ath10k;
struct ath10k_vif;
struct ath10k_fw_stats_pdev;
diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c
new file mode 100644
index 000000000000..a68d8fd853a3
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/wow.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2015 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "mac.h"
+
+#include <net/mac80211.h>
+#include "hif.h"
+#include "core.h"
+#include "debug.h"
+#include "wmi.h"
+#include "wmi-ops.h"
+
+static const struct wiphy_wowlan_support ath10k_wowlan_support = {
+ .flags = WIPHY_WOWLAN_DISCONNECT |
+ WIPHY_WOWLAN_MAGIC_PKT,
+ .pattern_min_len = WOW_MIN_PATTERN_SIZE,
+ .pattern_max_len = WOW_MAX_PATTERN_SIZE,
+ .max_pkt_offset = WOW_MAX_PKT_OFFSET,
+};
+
+static int ath10k_wow_vif_cleanup(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+ int i, ret;
+
+ for (i = 0; i < WOW_EVENT_MAX; i++) {
+ ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 0);
+ if (ret) {
+ ath10k_warn(ar, "failed to issue wow wakeup for event %s on vdev %i: %d\n",
+ wow_wakeup_event(i), arvif->vdev_id, ret);
+ return ret;
+ }
+ }
+
+ for (i = 0; i < ar->wow.max_num_patterns; i++) {
+ ret = ath10k_wmi_wow_del_pattern(ar, arvif->vdev_id, i);
+ if (ret) {
+ ath10k_warn(ar, "failed to delete wow pattern %d for vdev %i: %d\n",
+ i, arvif->vdev_id, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ath10k_wow_cleanup(struct ath10k *ar)
+{
+ struct ath10k_vif *arvif;
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ ret = ath10k_wow_vif_cleanup(arvif);
+ if (ret) {
+ ath10k_warn(ar, "failed to clean wow wakeups on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif,
+ struct cfg80211_wowlan *wowlan)
+{
+ int ret, i;
+ unsigned long wow_mask = 0;
+ struct ath10k *ar = arvif->ar;
+ const struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
+ int pattern_id = 0;
+
+ /* Setup requested WOW features */
+ switch (arvif->vdev_type) {
+ case WMI_VDEV_TYPE_IBSS:
+ __set_bit(WOW_BEACON_EVENT, &wow_mask);
+ /* fall through */
+ case WMI_VDEV_TYPE_AP:
+ __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);
+ __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);
+ __set_bit(WOW_PROBE_REQ_WPS_IE_EVENT, &wow_mask);
+ __set_bit(WOW_AUTH_REQ_EVENT, &wow_mask);
+ __set_bit(WOW_ASSOC_REQ_EVENT, &wow_mask);
+ __set_bit(WOW_HTT_EVENT, &wow_mask);
+ __set_bit(WOW_RA_MATCH_EVENT, &wow_mask);
+ break;
+ case WMI_VDEV_TYPE_STA:
+ if (wowlan->disconnect) {
+ __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);
+ __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);
+ __set_bit(WOW_BMISS_EVENT, &wow_mask);
+ __set_bit(WOW_CSA_IE_EVENT, &wow_mask);
+ }
+
+ if (wowlan->magic_pkt)
+ __set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask);
+ break;
+ default:
+ break;
+ }
+
+ for (i = 0; i < wowlan->n_patterns; i++) {
+ u8 bitmask[WOW_MAX_PATTERN_SIZE] = {};
+ int j;
+
+ if (patterns[i].pattern_len > WOW_MAX_PATTERN_SIZE)
+ continue;
+
+ /* convert bytemask to bitmask */
+ for (j = 0; j < patterns[i].pattern_len; j++)
+ if (patterns[i].mask[j / 8] & BIT(j % 8))
+ bitmask[j] = 0xff;
+
+ ret = ath10k_wmi_wow_add_pattern(ar, arvif->vdev_id,
+ pattern_id,
+ patterns[i].pattern,
+ bitmask,
+ patterns[i].pattern_len,
+ patterns[i].pkt_offset);
+ if (ret) {
+ ath10k_warn(ar, "failed to add pattern %i to vdev %i: %d\n",
+ pattern_id,
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ pattern_id++;
+ __set_bit(WOW_PATTERN_MATCH_EVENT, &wow_mask);
+ }
+
+ for (i = 0; i < WOW_EVENT_MAX; i++) {
+ if (!test_bit(i, &wow_mask))
+ continue;
+ ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 1);
+ if (ret) {
+ ath10k_warn(ar, "failed to enable wakeup event %s on vdev %i: %d\n",
+ wow_wakeup_event(i), arvif->vdev_id, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ath10k_wow_set_wakeups(struct ath10k *ar,
+ struct cfg80211_wowlan *wowlan)
+{
+ struct ath10k_vif *arvif;
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ ret = ath10k_vif_wow_set_wakeups(arvif, wowlan);
+ if (ret) {
+ ath10k_warn(ar, "failed to set wow wakeups on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ath10k_wow_enable(struct ath10k *ar)
+{
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ reinit_completion(&ar->target_suspend);
+
+ ret = ath10k_wmi_wow_enable(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to issue wow enable: %d\n", ret);
+ return ret;
+ }
+
+ ret = wait_for_completion_timeout(&ar->target_suspend, 3 * HZ);
+ if (ret == 0) {
+ ath10k_warn(ar, "timed out while waiting for suspend completion\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int ath10k_wow_wakeup(struct ath10k *ar)
+{
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ reinit_completion(&ar->wow.wakeup_completed);
+
+ ret = ath10k_wmi_wow_host_wakeup_ind(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to send wow wakeup indication: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = wait_for_completion_timeout(&ar->wow.wakeup_completed, 3 * HZ);
+ if (ret == 0) {
+ ath10k_warn(ar, "timed out while waiting for wow wakeup completion\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
+ struct cfg80211_wowlan *wowlan)
+{
+ struct ath10k *ar = hw->priv;
+ int ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
+ ar->fw_features))) {
+ ret = 1;
+ goto exit;
+ }
+
+ ret = ath10k_wow_cleanup(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to clear wow wakeup events: %d\n",
+ ret);
+ goto exit;
+ }
+
+ ret = ath10k_wow_set_wakeups(ar, wowlan);
+ if (ret) {
+ ath10k_warn(ar, "failed to set wow wakeup events: %d\n",
+ ret);
+ goto cleanup;
+ }
+
+ ret = ath10k_wow_enable(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to start wow: %d\n", ret);
+ goto cleanup;
+ }
+
+ ret = ath10k_hif_suspend(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to suspend hif: %d\n", ret);
+ goto wakeup;
+ }
+
+ goto exit;
+
+wakeup:
+ ath10k_wow_wakeup(ar);
+
+cleanup:
+ ath10k_wow_cleanup(ar);
+
+exit:
+ mutex_unlock(&ar->conf_mutex);
+ return ret ? 1 : 0;
+}
+
+int ath10k_wow_op_resume(struct ieee80211_hw *hw)
+{
+ struct ath10k *ar = hw->priv;
+ int ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
+ ar->fw_features))) {
+ ret = 1;
+ goto exit;
+ }
+
+ ret = ath10k_hif_resume(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to resume hif: %d\n", ret);
+ goto exit;
+ }
+
+ ret = ath10k_wow_wakeup(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to wakeup from wow: %d\n", ret);
+
+exit:
+ mutex_unlock(&ar->conf_mutex);
+ return ret ? 1 : 0;
+}
+
+int ath10k_wow_init(struct ath10k *ar)
+{
+ if (!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, ar->fw_features))
+ return 0;
+
+ if (WARN_ON(!test_bit(WMI_SERVICE_WOW, ar->wmi.svc_map)))
+ return -EINVAL;
+
+ ar->wow.wowlan_support = ath10k_wowlan_support;
+ ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns;
+ ar->hw->wiphy->wowlan = &ar->wow.wowlan_support;
+
+ return 0;
+}
diff --git a/drivers/net/wireless/ath/ath10k/wow.h b/drivers/net/wireless/ath/ath10k/wow.h
new file mode 100644
index 000000000000..abbb04b6d1bd
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/wow.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _WOW_H_
+#define _WOW_H_
+
+struct ath10k_wow {
+ u32 max_num_patterns;
+ struct completion wakeup_completed;
+ struct wiphy_wowlan_support wowlan_support;
+};
+
+#ifdef CONFIG_PM
+
+int ath10k_wow_init(struct ath10k *ar);
+int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
+ struct cfg80211_wowlan *wowlan);
+int ath10k_wow_op_resume(struct ieee80211_hw *hw);
+
+#else
+
+static inline int ath10k_wow_init(struct ath10k *ar)
+{
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+#endif /* _WOW_H_ */
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 7ca0d6f930fd..e22b0e778927 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -1280,7 +1280,6 @@ struct ath5k_hw {
DECLARE_BITMAP(status, 4);
#define ATH_STAT_INVALID 0 /* disable hardware accesses */
-#define ATH_STAT_PROMISC 1
#define ATH_STAT_LEDSOFT 2 /* enable LED gpio status */
#define ATH_STAT_STARTED 3 /* opened & irqs enabled */
#define ATH_STAT_RESET 4 /* hw reset */
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index a6131825c9f6..23552f43d125 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -2537,12 +2537,12 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
/* Initialize driver private data */
SET_IEEE80211_DEV(hw, ah->dev);
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_MFP_CAPABLE |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_SUPPORTS_RC_TABLE;
+ ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
index ca4b7ccd697f..803030fd17d3 100644
--- a/drivers/net/wireless/ath/ath5k/led.c
+++ b/drivers/net/wireless/ath/ath5k/led.c
@@ -124,7 +124,7 @@ ath5k_led_brightness_set(struct led_classdev *led_dev,
static int
ath5k_register_led(struct ath5k_hw *ah, struct ath5k_led *led,
- const char *name, char *trigger)
+ const char *name, const char *trigger)
{
int err;
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 3b4a6463d87a..dc44cfef7517 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -369,7 +369,7 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
unsigned int *new_flags, u64 multicast)
{
#define SUPPORTED_FIF_FLAGS \
- (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \
+ (FIF_ALLMULTI | FIF_FCSFAIL | \
FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
FIF_BCN_PRBRESP_PROMISC)
@@ -393,16 +393,6 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
(AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
AR5K_RX_FILTER_MCAST);
- if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
- if (*new_flags & FIF_PROMISC_IN_BSS)
- __set_bit(ATH_STAT_PROMISC, ah->status);
- else
- __clear_bit(ATH_STAT_PROMISC, ah->status);
- }
-
- if (test_bit(ATH_STAT_PROMISC, ah->status))
- rfilt |= AR5K_RX_FILTER_PROM;
-
/* Note, AR5K_RX_FILTER_MCAST is already enabled */
if (*new_flags & FIF_ALLMULTI) {
mfilt[0] = ~0;
@@ -418,8 +408,7 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (ah->nvifs > 1))
rfilt |= AR5K_RX_FILTER_BEACON;
- /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
- * set we should only pass on control frames for this
+ /* FIF_CONTROL doc says we should only pass on control frames for this
* station. This needs testing. I believe right now this
* enables *all* control frames, which is OK.. but
* but we should see if we can improve on granularity */
@@ -809,7 +798,6 @@ const struct ieee80211_ops ath5k_hw_ops = {
.sw_scan_start = ath5k_sw_scan_start,
.sw_scan_complete = ath5k_sw_scan_complete,
.get_stats = ath5k_get_stats,
- /* .get_tkip_seq = not implemented */
/* .set_frag_threshold = not implemented */
/* .set_rts_threshold = not implemented */
/* .sta_add = not implemented */
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index cce4625a53ad..a511ef3614b9 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -889,7 +889,7 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
GFP_KERNEL);
} else if (vif->sme_state == SME_CONNECTED) {
cfg80211_disconnected(vif->ndev, proto_reason,
- NULL, 0, GFP_KERNEL);
+ NULL, 0, false, GFP_KERNEL);
}
vif->sme_state = SME_DISCONNECTED;
@@ -3467,7 +3467,7 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
GFP_KERNEL);
break;
case SME_CONNECTED:
- cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
+ cfg80211_disconnected(vif->ndev, 0, NULL, 0, true, GFP_KERNEL);
break;
}
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 19f88b4a24fb..05d25a94c781 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -1527,8 +1527,8 @@ struct wmi_connect_event {
__le32 nw_type;
} sta;
struct {
- u8 phymode;
u8 aid;
+ u8 phymode;
u8 mac_addr[ETH_ALEN];
u8 auth;
u8 keymgmt;
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index 6c23d279525f..8f8793004b9f 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -254,86 +254,25 @@ static int ar5008_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
return 0;
}
-/**
- * ar5008_hw_spur_mitigate - convert baseband spur frequency for external radios
- * @ah: atheros hardware structure
- * @chan:
- *
- * For non single-chip solutions. Converts to baseband spur frequency given the
- * input channel frequency and compute register settings below.
- */
-static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
- struct ath9k_channel *chan)
+void ar5008_hw_cmn_spur_mitigate(struct ath_hw *ah,
+ struct ath9k_channel *chan, int bin)
{
- int bb_spur = AR_NO_SPUR;
- int bin, cur_bin;
- int spur_freq_sd;
- int spur_delta_phase;
- int denominator;
+ int cur_bin;
int upper, lower, cur_vit_mask;
- int tmp, new;
int i;
- static int pilot_mask_reg[4] = {
+ int8_t mask_m[123];
+ int8_t mask_p[123];
+ int8_t mask_amt;
+ int tmp_mask;
+ static const int pilot_mask_reg[4] = {
AR_PHY_TIMING7, AR_PHY_TIMING8,
AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
};
- static int chan_mask_reg[4] = {
+ static const int chan_mask_reg[4] = {
AR_PHY_TIMING9, AR_PHY_TIMING10,
AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
};
- static int inc[4] = { 0, 100, 0, 0 };
-
- int8_t mask_m[123];
- int8_t mask_p[123];
- int8_t mask_amt;
- int tmp_mask;
- int cur_bb_spur;
- bool is2GHz = IS_CHAN_2GHZ(chan);
-
- memset(&mask_m, 0, sizeof(int8_t) * 123);
- memset(&mask_p, 0, sizeof(int8_t) * 123);
-
- for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
- cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
- if (AR_NO_SPUR == cur_bb_spur)
- break;
- cur_bb_spur = cur_bb_spur - (chan->channel * 10);
- if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) {
- bb_spur = cur_bb_spur;
- break;
- }
- }
-
- if (AR_NO_SPUR == bb_spur)
- return;
-
- bin = bb_spur * 32;
-
- tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
- new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
- AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
- AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
- AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
-
- REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new);
-
- new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
- AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
- AR_PHY_SPUR_REG_MASK_RATE_SELECT |
- AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
- SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
- REG_WRITE(ah, AR_PHY_SPUR_REG, new);
-
- spur_delta_phase = ((bb_spur * 524288) / 100) &
- AR_PHY_TIMING11_SPUR_DELTA_PHASE;
-
- denominator = IS_CHAN_2GHZ(chan) ? 440 : 400;
- spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff;
-
- new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
- SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
- SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
- REG_WRITE(ah, AR_PHY_TIMING11, new);
+ static const int inc[4] = { 0, 100, 0, 0 };
cur_bin = -6000;
upper = bin + 100;
@@ -343,6 +282,7 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
int pilot_mask = 0;
int chan_mask = 0;
int bp = 0;
+
for (bp = 0; bp < 30; bp++) {
if ((cur_bin > lower) && (cur_bin < upper)) {
pilot_mask = pilot_mask | 0x1 << bp;
@@ -361,7 +301,6 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
for (i = 0; i < 123; i++) {
if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
-
/* workaround for gcc bug #37014 */
volatile int tmp_v = abs(cur_vit_mask - bin);
@@ -467,6 +406,78 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
}
/**
+ * ar5008_hw_spur_mitigate - convert baseband spur frequency for external radios
+ * @ah: atheros hardware structure
+ * @chan:
+ *
+ * For non single-chip solutions. Converts to baseband spur frequency given the
+ * input channel frequency and compute register settings below.
+ */
+static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ int bb_spur = AR_NO_SPUR;
+ int bin;
+ int spur_freq_sd;
+ int spur_delta_phase;
+ int denominator;
+ int tmp, new;
+ int i;
+
+ int8_t mask_m[123];
+ int8_t mask_p[123];
+ int cur_bb_spur;
+ bool is2GHz = IS_CHAN_2GHZ(chan);
+
+ memset(&mask_m, 0, sizeof(int8_t) * 123);
+ memset(&mask_p, 0, sizeof(int8_t) * 123);
+
+ for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+ cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
+ if (AR_NO_SPUR == cur_bb_spur)
+ break;
+ cur_bb_spur = cur_bb_spur - (chan->channel * 10);
+ if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) {
+ bb_spur = cur_bb_spur;
+ break;
+ }
+ }
+
+ if (AR_NO_SPUR == bb_spur)
+ return;
+
+ bin = bb_spur * 32;
+
+ tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
+ new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
+ AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
+ AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
+ AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
+
+ REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new);
+
+ new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
+ AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
+ AR_PHY_SPUR_REG_MASK_RATE_SELECT |
+ AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
+ SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
+ REG_WRITE(ah, AR_PHY_SPUR_REG, new);
+
+ spur_delta_phase = ((bb_spur * 524288) / 100) &
+ AR_PHY_TIMING11_SPUR_DELTA_PHASE;
+
+ denominator = IS_CHAN_2GHZ(chan) ? 440 : 400;
+ spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff;
+
+ new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
+ SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
+ SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
+ REG_WRITE(ah, AR_PHY_TIMING11, new);
+
+ ar5008_hw_cmn_spur_mitigate(ah, chan, bin);
+}
+
+/**
* ar5008_hw_rf_alloc_ext_banks - allocates banks for external radio programming
* @ah: atheros hardware structure
*
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index fc08162b5820..db6624527d99 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -169,29 +169,17 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
{
int bb_spur = AR_NO_SPUR;
int freq;
- int bin, cur_bin;
+ int bin;
int bb_spur_off, spur_subchannel_sd;
int spur_freq_sd;
int spur_delta_phase;
int denominator;
- int upper, lower, cur_vit_mask;
int tmp, newVal;
int i;
- static const int pilot_mask_reg[4] = {
- AR_PHY_TIMING7, AR_PHY_TIMING8,
- AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
- };
- static const int chan_mask_reg[4] = {
- AR_PHY_TIMING9, AR_PHY_TIMING10,
- AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
- };
- static const int inc[4] = { 0, 100, 0, 0 };
struct chan_centers centers;
int8_t mask_m[123];
int8_t mask_p[123];
- int8_t mask_amt;
- int tmp_mask;
int cur_bb_spur;
bool is2GHz = IS_CHAN_2GHZ(chan);
@@ -288,135 +276,7 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S;
REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal);
- cur_bin = -6000;
- upper = bin + 100;
- lower = bin - 100;
-
- for (i = 0; i < 4; i++) {
- int pilot_mask = 0;
- int chan_mask = 0;
- int bp = 0;
- for (bp = 0; bp < 30; bp++) {
- if ((cur_bin > lower) && (cur_bin < upper)) {
- pilot_mask = pilot_mask | 0x1 << bp;
- chan_mask = chan_mask | 0x1 << bp;
- }
- cur_bin += 100;
- }
- cur_bin += inc[i];
- REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
- REG_WRITE(ah, chan_mask_reg[i], chan_mask);
- }
-
- cur_vit_mask = 6100;
- upper = bin + 120;
- lower = bin - 120;
-
- for (i = 0; i < 123; i++) {
- if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
-
- /* workaround for gcc bug #37014 */
- volatile int tmp_v = abs(cur_vit_mask - bin);
-
- if (tmp_v < 75)
- mask_amt = 1;
- else
- mask_amt = 0;
- if (cur_vit_mask < 0)
- mask_m[abs(cur_vit_mask / 100)] = mask_amt;
- else
- mask_p[cur_vit_mask / 100] = mask_amt;
- }
- cur_vit_mask -= 100;
- }
-
- tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
- | (mask_m[48] << 26) | (mask_m[49] << 24)
- | (mask_m[50] << 22) | (mask_m[51] << 20)
- | (mask_m[52] << 18) | (mask_m[53] << 16)
- | (mask_m[54] << 14) | (mask_m[55] << 12)
- | (mask_m[56] << 10) | (mask_m[57] << 8)
- | (mask_m[58] << 6) | (mask_m[59] << 4)
- | (mask_m[60] << 2) | (mask_m[61] << 0);
- REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
- REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
-
- tmp_mask = (mask_m[31] << 28)
- | (mask_m[32] << 26) | (mask_m[33] << 24)
- | (mask_m[34] << 22) | (mask_m[35] << 20)
- | (mask_m[36] << 18) | (mask_m[37] << 16)
- | (mask_m[48] << 14) | (mask_m[39] << 12)
- | (mask_m[40] << 10) | (mask_m[41] << 8)
- | (mask_m[42] << 6) | (mask_m[43] << 4)
- | (mask_m[44] << 2) | (mask_m[45] << 0);
- REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
- REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
-
- tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
- | (mask_m[18] << 26) | (mask_m[18] << 24)
- | (mask_m[20] << 22) | (mask_m[20] << 20)
- | (mask_m[22] << 18) | (mask_m[22] << 16)
- | (mask_m[24] << 14) | (mask_m[24] << 12)
- | (mask_m[25] << 10) | (mask_m[26] << 8)
- | (mask_m[27] << 6) | (mask_m[28] << 4)
- | (mask_m[29] << 2) | (mask_m[30] << 0);
- REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
- REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
-
- tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
- | (mask_m[2] << 26) | (mask_m[3] << 24)
- | (mask_m[4] << 22) | (mask_m[5] << 20)
- | (mask_m[6] << 18) | (mask_m[7] << 16)
- | (mask_m[8] << 14) | (mask_m[9] << 12)
- | (mask_m[10] << 10) | (mask_m[11] << 8)
- | (mask_m[12] << 6) | (mask_m[13] << 4)
- | (mask_m[14] << 2) | (mask_m[15] << 0);
- REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
- REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
-
- tmp_mask = (mask_p[15] << 28)
- | (mask_p[14] << 26) | (mask_p[13] << 24)
- | (mask_p[12] << 22) | (mask_p[11] << 20)
- | (mask_p[10] << 18) | (mask_p[9] << 16)
- | (mask_p[8] << 14) | (mask_p[7] << 12)
- | (mask_p[6] << 10) | (mask_p[5] << 8)
- | (mask_p[4] << 6) | (mask_p[3] << 4)
- | (mask_p[2] << 2) | (mask_p[1] << 0);
- REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
- REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
-
- tmp_mask = (mask_p[30] << 28)
- | (mask_p[29] << 26) | (mask_p[28] << 24)
- | (mask_p[27] << 22) | (mask_p[26] << 20)
- | (mask_p[25] << 18) | (mask_p[24] << 16)
- | (mask_p[23] << 14) | (mask_p[22] << 12)
- | (mask_p[21] << 10) | (mask_p[20] << 8)
- | (mask_p[19] << 6) | (mask_p[18] << 4)
- | (mask_p[17] << 2) | (mask_p[16] << 0);
- REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
- REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
-
- tmp_mask = (mask_p[45] << 28)
- | (mask_p[44] << 26) | (mask_p[43] << 24)
- | (mask_p[42] << 22) | (mask_p[41] << 20)
- | (mask_p[40] << 18) | (mask_p[39] << 16)
- | (mask_p[38] << 14) | (mask_p[37] << 12)
- | (mask_p[36] << 10) | (mask_p[35] << 8)
- | (mask_p[34] << 6) | (mask_p[33] << 4)
- | (mask_p[32] << 2) | (mask_p[31] << 0);
- REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
- REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
-
- tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
- | (mask_p[59] << 26) | (mask_p[58] << 24)
- | (mask_p[57] << 22) | (mask_p[56] << 20)
- | (mask_p[55] << 18) | (mask_p[54] << 16)
- | (mask_p[53] << 14) | (mask_p[52] << 12)
- | (mask_p[51] << 10) | (mask_p[50] << 8)
- | (mask_p[49] << 6) | (mask_p[48] << 4)
- | (mask_p[47] << 2) | (mask_p[46] << 0);
- REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
- REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
+ ar5008_hw_cmn_spur_mitigate(ah, chan, bin);
REGWRITE_BUFFER_FLUSH(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 5cee231cca1f..a8762711ad74 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -15,6 +15,7 @@
*/
#include <linux/relay.h>
+#include <linux/random.h>
#include "ath9k.h"
static s8 fix_rssi_inv_only(u8 rssi_val)
@@ -36,21 +37,480 @@ static void ath_debug_send_fft_sample(struct ath_spec_scan_priv *spec_priv,
relay_write(spec_priv->rfs_chan_spec_scan, fft_sample_tlv, length);
}
+typedef int (ath_cmn_fft_idx_validator) (u8 *sample_end, int bytes_read);
+
+static int
+ath_cmn_max_idx_verify_ht20_fft(u8 *sample_end, int bytes_read)
+{
+ struct ath_ht20_mag_info *mag_info;
+ u8 *sample;
+ u16 max_magnitude;
+ u8 max_index;
+ u8 max_exp;
+
+ /* Sanity check so that we don't read outside the read
+ * buffer
+ */
+ if (bytes_read < SPECTRAL_HT20_SAMPLE_LEN - 1)
+ return -1;
+
+ mag_info = (struct ath_ht20_mag_info *) (sample_end -
+ sizeof(struct ath_ht20_mag_info) + 1);
+
+ sample = sample_end - SPECTRAL_HT20_SAMPLE_LEN + 1;
+
+ max_index = spectral_max_index(mag_info->all_bins,
+ SPECTRAL_HT20_NUM_BINS);
+ max_magnitude = spectral_max_magnitude(mag_info->all_bins);
+
+ max_exp = mag_info->max_exp & 0xf;
+
+ /* Don't try to read something outside the read buffer
+ * in case of a missing byte (so bins[0] will be outside
+ * the read buffer)
+ */
+ if (bytes_read < SPECTRAL_HT20_SAMPLE_LEN && max_index < 1)
+ return -1;
+
+ if (sample[max_index] != (max_magnitude >> max_exp))
+ return -1;
+ else
+ return 0;
+}
+
+static int
+ath_cmn_max_idx_verify_ht20_40_fft(u8 *sample_end, int bytes_read)
+{
+ struct ath_ht20_40_mag_info *mag_info;
+ u8 *sample;
+ u16 lower_mag, upper_mag;
+ u8 lower_max_index, upper_max_index;
+ u8 max_exp;
+ int dc_pos = SPECTRAL_HT20_40_NUM_BINS / 2;
+
+ /* Sanity check so that we don't read outside the read
+ * buffer
+ */
+ if (bytes_read < SPECTRAL_HT20_40_SAMPLE_LEN - 1)
+ return -1;
+
+ mag_info = (struct ath_ht20_40_mag_info *) (sample_end -
+ sizeof(struct ath_ht20_40_mag_info) + 1);
+
+ sample = sample_end - SPECTRAL_HT20_40_SAMPLE_LEN + 1;
+
+ lower_mag = spectral_max_magnitude(mag_info->lower_bins);
+ lower_max_index = spectral_max_index(mag_info->lower_bins,
+ SPECTRAL_HT20_40_NUM_BINS);
+
+ upper_mag = spectral_max_magnitude(mag_info->upper_bins);
+ upper_max_index = spectral_max_index(mag_info->upper_bins,
+ SPECTRAL_HT20_40_NUM_BINS);
+
+ max_exp = mag_info->max_exp & 0xf;
+
+ /* Don't try to read something outside the read buffer
+ * in case of a missing byte (so bins[0] will be outside
+ * the read buffer)
+ */
+ if (bytes_read < SPECTRAL_HT20_40_SAMPLE_LEN &&
+ ((upper_max_index < 1) || (lower_max_index < 1)))
+ return -1;
+
+ /* Some time hardware messes up the index and adds
+ * the index of the middle point (dc_pos). Try to fix it.
+ */
+ if ((upper_max_index - dc_pos > 0) &&
+ (sample[upper_max_index] == (upper_mag >> max_exp)))
+ upper_max_index -= dc_pos;
+
+ if ((lower_max_index - dc_pos > 0) &&
+ (sample[lower_max_index - dc_pos] == (lower_mag >> max_exp)))
+ lower_max_index -= dc_pos;
+
+ if ((sample[upper_max_index + dc_pos] != (upper_mag >> max_exp)) ||
+ (sample[lower_max_index] != (lower_mag >> max_exp)))
+ return -1;
+ else
+ return 0;
+}
+
+typedef int (ath_cmn_fft_sample_handler) (struct ath_rx_status *rs,
+ struct ath_spec_scan_priv *spec_priv,
+ u8 *sample_buf, u64 tsf, u16 freq, int chan_type);
+
+static int
+ath_cmn_process_ht20_fft(struct ath_rx_status *rs,
+ struct ath_spec_scan_priv *spec_priv,
+ u8 *sample_buf,
+ u64 tsf, u16 freq, int chan_type)
+{
+ struct fft_sample_ht20 fft_sample_20;
+ struct ath_common *common = ath9k_hw_common(spec_priv->ah);
+ struct ath_hw *ah = spec_priv->ah;
+ struct ath_ht20_mag_info *mag_info;
+ struct fft_sample_tlv *tlv;
+ int i = 0;
+ int ret = 0;
+ int dc_pos = SPECTRAL_HT20_NUM_BINS / 2;
+ u16 magnitude, tmp_mag, length;
+ u8 max_index, bitmap_w, max_exp;
+
+ length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv);
+ fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20;
+ fft_sample_20.tlv.length = __cpu_to_be16(length);
+ fft_sample_20.freq = __cpu_to_be16(freq);
+ fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
+ fft_sample_20.noise = ah->noise;
+
+ mag_info = (struct ath_ht20_mag_info *) (sample_buf +
+ SPECTRAL_HT20_NUM_BINS);
+
+ magnitude = spectral_max_magnitude(mag_info->all_bins);
+ fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
+
+ max_index = spectral_max_index(mag_info->all_bins,
+ SPECTRAL_HT20_NUM_BINS);
+ fft_sample_20.max_index = max_index;
+
+ bitmap_w = spectral_bitmap_weight(mag_info->all_bins);
+ fft_sample_20.bitmap_weight = bitmap_w;
+
+ max_exp = mag_info->max_exp & 0xf;
+ fft_sample_20.max_exp = max_exp;
+
+ fft_sample_20.tsf = __cpu_to_be64(tsf);
+
+ memcpy(fft_sample_20.data, sample_buf, SPECTRAL_HT20_NUM_BINS);
+
+ ath_dbg(common, SPECTRAL_SCAN, "FFT HT20 frame: max mag 0x%X,"
+ "max_mag_idx %i\n",
+ magnitude >> max_exp,
+ max_index);
+
+ if (fft_sample_20.data[max_index] != (magnitude >> max_exp)) {
+ ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n");
+ ret = -1;
+ }
+
+ /* DC value (value in the middle) is the blind spot of the spectral
+ * sample and invalid, interpolate it.
+ */
+ fft_sample_20.data[dc_pos] = (fft_sample_20.data[dc_pos + 1] +
+ fft_sample_20.data[dc_pos - 1]) / 2;
+
+ /* Check if the maximum magnitude is indeed maximum,
+ * also if the maximum value was at dc_pos, calculate
+ * a new one (since value at dc_pos is invalid).
+ */
+ if (max_index == dc_pos) {
+ tmp_mag = 0;
+ for (i = 0; i < dc_pos; i++) {
+ if (fft_sample_20.data[i] > tmp_mag) {
+ tmp_mag = fft_sample_20.data[i];
+ fft_sample_20.max_index = i;
+ }
+ }
+
+ magnitude = tmp_mag << max_exp;
+ fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
+
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Calculated new lower max 0x%X at %i\n",
+ tmp_mag, fft_sample_20.max_index);
+ } else
+ for (i = 0; i < SPECTRAL_HT20_NUM_BINS; i++) {
+ if (fft_sample_20.data[i] == (magnitude >> max_exp))
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Got max: 0x%X at index %i\n",
+ fft_sample_20.data[i], i);
+
+ if (fft_sample_20.data[i] > (magnitude >> max_exp)) {
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Got bin %i greater than max: 0x%X\n",
+ i, fft_sample_20.data[i]);
+ ret = -1;
+ }
+ }
+
+ if (ret < 0)
+ return ret;
+
+ tlv = (struct fft_sample_tlv *)&fft_sample_20;
+
+ ath_debug_send_fft_sample(spec_priv, tlv);
+
+ return 0;
+}
+
+static int
+ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs,
+ struct ath_spec_scan_priv *spec_priv,
+ u8 *sample_buf,
+ u64 tsf, u16 freq, int chan_type)
+{
+ struct fft_sample_ht20_40 fft_sample_40;
+ struct ath_common *common = ath9k_hw_common(spec_priv->ah);
+ struct ath_hw *ah = spec_priv->ah;
+ struct ath9k_hw_cal_data *caldata = ah->caldata;
+ struct ath_ht20_40_mag_info *mag_info;
+ struct fft_sample_tlv *tlv;
+ int dc_pos = SPECTRAL_HT20_40_NUM_BINS / 2;
+ int i = 0;
+ int ret = 0;
+ s16 ext_nf;
+ u16 lower_mag, upper_mag, tmp_mag, length;
+ s8 lower_rssi, upper_rssi;
+ u8 lower_max_index, upper_max_index;
+ u8 lower_bitmap_w, upper_bitmap_w, max_exp;
+
+ if (caldata)
+ ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan,
+ caldata->nfCalHist[3].privNF);
+ else
+ ext_nf = ATH_DEFAULT_NOISE_FLOOR;
+
+ length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv);
+ fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40;
+ fft_sample_40.tlv.length = __cpu_to_be16(length);
+ fft_sample_40.freq = __cpu_to_be16(freq);
+ fft_sample_40.channel_type = chan_type;
+
+ if (chan_type == NL80211_CHAN_HT40PLUS) {
+ lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
+ upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
+
+ fft_sample_40.lower_noise = ah->noise;
+ fft_sample_40.upper_noise = ext_nf;
+ } else {
+ lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
+ upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
+
+ fft_sample_40.lower_noise = ext_nf;
+ fft_sample_40.upper_noise = ah->noise;
+ }
+
+ fft_sample_40.lower_rssi = lower_rssi;
+ fft_sample_40.upper_rssi = upper_rssi;
+
+ mag_info = (struct ath_ht20_40_mag_info *) (sample_buf +
+ SPECTRAL_HT20_40_NUM_BINS);
+
+ lower_mag = spectral_max_magnitude(mag_info->lower_bins);
+ fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
+
+ upper_mag = spectral_max_magnitude(mag_info->upper_bins);
+ fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
+
+ lower_max_index = spectral_max_index(mag_info->lower_bins,
+ SPECTRAL_HT20_40_NUM_BINS);
+ fft_sample_40.lower_max_index = lower_max_index;
+
+ upper_max_index = spectral_max_index(mag_info->upper_bins,
+ SPECTRAL_HT20_40_NUM_BINS);
+ fft_sample_40.upper_max_index = upper_max_index;
+
+ lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins);
+ fft_sample_40.lower_bitmap_weight = lower_bitmap_w;
+
+ upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins);
+ fft_sample_40.upper_bitmap_weight = upper_bitmap_w;
+
+ max_exp = mag_info->max_exp & 0xf;
+ fft_sample_40.max_exp = max_exp;
+
+ fft_sample_40.tsf = __cpu_to_be64(tsf);
+
+ memcpy(fft_sample_40.data, sample_buf, SPECTRAL_HT20_40_NUM_BINS);
+
+ ath_dbg(common, SPECTRAL_SCAN, "FFT HT20/40 frame: lower mag 0x%X,"
+ "lower_mag_idx %i, upper mag 0x%X,"
+ "upper_mag_idx %i\n",
+ lower_mag >> max_exp,
+ lower_max_index,
+ upper_mag >> max_exp,
+ upper_max_index);
+
+ /* Some time hardware messes up the index and adds
+ * the index of the middle point (dc_pos). Try to fix it.
+ */
+ if ((upper_max_index - dc_pos > 0) &&
+ (fft_sample_40.data[upper_max_index] == (upper_mag >> max_exp))) {
+ upper_max_index -= dc_pos;
+ fft_sample_40.upper_max_index = upper_max_index;
+ }
+
+ if ((lower_max_index - dc_pos > 0) &&
+ (fft_sample_40.data[lower_max_index - dc_pos] ==
+ (lower_mag >> max_exp))) {
+ lower_max_index -= dc_pos;
+ fft_sample_40.lower_max_index = lower_max_index;
+ }
+
+ /* Check if we got the expected magnitude values at
+ * the expected bins
+ */
+ if ((fft_sample_40.data[upper_max_index + dc_pos]
+ != (upper_mag >> max_exp)) ||
+ (fft_sample_40.data[lower_max_index]
+ != (lower_mag >> max_exp))) {
+ ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n");
+ ret = -1;
+ }
+
+ /* DC value (value in the middle) is the blind spot of the spectral
+ * sample and invalid, interpolate it.
+ */
+ fft_sample_40.data[dc_pos] = (fft_sample_40.data[dc_pos + 1] +
+ fft_sample_40.data[dc_pos - 1]) / 2;
+
+ /* Check if the maximum magnitudes are indeed maximum,
+ * also if the maximum value was at dc_pos, calculate
+ * a new one (since value at dc_pos is invalid).
+ */
+ if (lower_max_index == dc_pos) {
+ tmp_mag = 0;
+ for (i = 0; i < dc_pos; i++) {
+ if (fft_sample_40.data[i] > tmp_mag) {
+ tmp_mag = fft_sample_40.data[i];
+ fft_sample_40.lower_max_index = i;
+ }
+ }
+
+ lower_mag = tmp_mag << max_exp;
+ fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
+
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Calculated new lower max 0x%X at %i\n",
+ tmp_mag, fft_sample_40.lower_max_index);
+ } else
+ for (i = 0; i < dc_pos; i++) {
+ if (fft_sample_40.data[i] == (lower_mag >> max_exp))
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Got lower mag: 0x%X at index %i\n",
+ fft_sample_40.data[i], i);
+
+ if (fft_sample_40.data[i] > (lower_mag >> max_exp)) {
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Got lower bin %i higher than max: 0x%X\n",
+ i, fft_sample_40.data[i]);
+ ret = -1;
+ }
+ }
+
+ if (upper_max_index == dc_pos) {
+ tmp_mag = 0;
+ for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) {
+ if (fft_sample_40.data[i] > tmp_mag) {
+ tmp_mag = fft_sample_40.data[i];
+ fft_sample_40.upper_max_index = i;
+ }
+ }
+ upper_mag = tmp_mag << max_exp;
+ fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
+
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Calculated new upper max 0x%X at %i\n",
+ tmp_mag, i);
+ } else
+ for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) {
+ if (fft_sample_40.data[i] == (upper_mag >> max_exp))
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Got upper mag: 0x%X at index %i\n",
+ fft_sample_40.data[i], i);
+
+ if (fft_sample_40.data[i] > (upper_mag >> max_exp)) {
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Got upper bin %i higher than max: 0x%X\n",
+ i, fft_sample_40.data[i]);
+
+ ret = -1;
+ }
+ }
+
+ if (ret < 0)
+ return ret;
+
+ tlv = (struct fft_sample_tlv *)&fft_sample_40;
+
+ ath_debug_send_fft_sample(spec_priv, tlv);
+
+ return 0;
+}
+
+static inline void
+ath_cmn_copy_fft_frame(u8 *in, u8 *out, int sample_len, int sample_bytes)
+{
+ switch (sample_bytes - sample_len) {
+ case -1:
+ /* First byte missing */
+ memcpy(&out[1], in,
+ sample_len - 1);
+ break;
+ case 0:
+ /* Length correct, nothing to do. */
+ memcpy(out, in, sample_len);
+ break;
+ case 1:
+ /* MAC added 2 extra bytes AND first byte
+ * is missing.
+ */
+ memcpy(&out[1], in, 30);
+ out[31] = in[31];
+ memcpy(&out[32], &in[33],
+ sample_len - 32);
+ break;
+ case 2:
+ /* MAC added 2 extra bytes at bin 30 and 32,
+ * remove them.
+ */
+ memcpy(out, in, 30);
+ out[30] = in[31];
+ memcpy(&out[31], &in[33],
+ sample_len - 31);
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv *spec_priv)
+{
+ int i = 0;
+ int ret = 0;
+ struct rchan *rc = spec_priv->rfs_chan_spec_scan;
+
+ for_each_online_cpu(i)
+ ret += relay_buf_full(rc->buf[i]);
+
+ i = num_online_cpus();
+
+ if (ret == i)
+ return 1;
+ else
+ return 0;
+}
+
/* returns 1 if this was a spectral frame, even if not handled. */
int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_hdr *hdr,
struct ath_rx_status *rs, u64 tsf)
{
+ u8 sample_buf[SPECTRAL_SAMPLE_MAX_LEN] = {0};
struct ath_hw *ah = spec_priv->ah;
struct ath_common *common = ath9k_hw_common(spec_priv->ah);
- u8 num_bins, *bins, *vdata = (u8 *)hdr;
- struct fft_sample_ht20 fft_sample_20;
- struct fft_sample_ht20_40 fft_sample_40;
- struct fft_sample_tlv *tlv;
+ u8 num_bins, *vdata = (u8 *)hdr;
struct ath_radar_info *radar_info;
int len = rs->rs_datalen;
- int dc_pos;
- u16 fft_len, length, freq = ah->curchan->chan->center_freq;
+ int i;
+ int got_slen = 0;
+ u8 *sample_start;
+ int sample_bytes = 0;
+ int ret = 0;
+ u16 fft_len, sample_len, freq = ah->curchan->chan->center_freq;
enum nl80211_channel_type chan_type;
+ ath_cmn_fft_idx_validator *fft_idx_validator;
+ ath_cmn_fft_sample_handler *fft_handler;
/* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
* via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
@@ -68,140 +528,170 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
return 0;
+ /* Output buffers are full, no need to process anything
+ * since there is no space to put the result anyway
+ */
+ ret = ath_cmn_is_fft_buf_full(spec_priv);
+ if (ret == 1) {
+ ath_dbg(common, SPECTRAL_SCAN, "FFT report ignored, no space "
+ "left on output buffers\n");
+ return 1;
+ }
+
chan_type = cfg80211_get_chandef_type(&common->hw->conf.chandef);
if ((chan_type == NL80211_CHAN_HT40MINUS) ||
(chan_type == NL80211_CHAN_HT40PLUS)) {
fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN;
+ sample_len = SPECTRAL_HT20_40_SAMPLE_LEN;
num_bins = SPECTRAL_HT20_40_NUM_BINS;
- bins = (u8 *)fft_sample_40.data;
+ fft_idx_validator = &ath_cmn_max_idx_verify_ht20_40_fft;
+ fft_handler = &ath_cmn_process_ht20_40_fft;
} else {
fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN;
+ sample_len = SPECTRAL_HT20_SAMPLE_LEN;
num_bins = SPECTRAL_HT20_NUM_BINS;
- bins = (u8 *)fft_sample_20.data;
- }
-
- /* Variation in the data length is possible and will be fixed later */
- if ((len > fft_len + 2) || (len < fft_len - 1))
- return 1;
-
- switch (len - fft_len) {
- case 0:
- /* length correct, nothing to do. */
- memcpy(bins, vdata, num_bins);
- break;
- case -1:
- /* first byte missing, duplicate it. */
- memcpy(&bins[1], vdata, num_bins - 1);
- bins[0] = vdata[0];
- break;
- case 2:
- /* MAC added 2 extra bytes at bin 30 and 32, remove them. */
- memcpy(bins, vdata, 30);
- bins[30] = vdata[31];
- memcpy(&bins[31], &vdata[33], num_bins - 31);
- break;
- case 1:
- /* MAC added 2 extra bytes AND first byte is missing. */
- bins[0] = vdata[0];
- memcpy(&bins[1], vdata, 30);
- bins[31] = vdata[31];
- memcpy(&bins[32], &vdata[33], num_bins - 32);
- break;
- default:
- return 1;
+ fft_idx_validator = ath_cmn_max_idx_verify_ht20_fft;
+ fft_handler = &ath_cmn_process_ht20_fft;
}
- /* DC value (value in the middle) is the blind spot of the spectral
- * sample and invalid, interpolate it.
- */
- dc_pos = num_bins / 2;
- bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
-
- if ((chan_type == NL80211_CHAN_HT40MINUS) ||
- (chan_type == NL80211_CHAN_HT40PLUS)) {
- s8 lower_rssi, upper_rssi;
- s16 ext_nf;
- u8 lower_max_index, upper_max_index;
- u8 lower_bitmap_w, upper_bitmap_w;
- u16 lower_mag, upper_mag;
- struct ath9k_hw_cal_data *caldata = ah->caldata;
- struct ath_ht20_40_mag_info *mag_info;
-
- if (caldata)
- ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan,
- caldata->nfCalHist[3].privNF);
- else
- ext_nf = ATH_DEFAULT_NOISE_FLOOR;
-
- length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv);
- fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40;
- fft_sample_40.tlv.length = __cpu_to_be16(length);
- fft_sample_40.freq = __cpu_to_be16(freq);
- fft_sample_40.channel_type = chan_type;
-
- if (chan_type == NL80211_CHAN_HT40PLUS) {
- lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
- upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
-
- fft_sample_40.lower_noise = ah->noise;
- fft_sample_40.upper_noise = ext_nf;
- } else {
- lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
- upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
-
- fft_sample_40.lower_noise = ext_nf;
- fft_sample_40.upper_noise = ah->noise;
+ ath_dbg(common, SPECTRAL_SCAN, "Got radar dump bw_info: 0x%X,"
+ "len: %i fft_len: %i\n",
+ radar_info->pulse_bw_info,
+ len,
+ fft_len);
+ sample_start = vdata;
+ for (i = 0; i < len - 2; i++) {
+ sample_bytes++;
+
+ /* Only a single sample received, no need to look
+ * for the sample's end, do the correction based
+ * on the packet's length instead. Note that hw
+ * will always put the radar_info structure on
+ * the end.
+ */
+ if (len <= fft_len + 2) {
+ sample_bytes = len - sizeof(struct ath_radar_info);
+ got_slen = 1;
}
- fft_sample_40.lower_rssi = lower_rssi;
- fft_sample_40.upper_rssi = upper_rssi;
-
- mag_info = ((struct ath_ht20_40_mag_info *)radar_info) - 1;
- lower_mag = spectral_max_magnitude(mag_info->lower_bins);
- upper_mag = spectral_max_magnitude(mag_info->upper_bins);
- fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
- fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
- lower_max_index = spectral_max_index(mag_info->lower_bins);
- upper_max_index = spectral_max_index(mag_info->upper_bins);
- fft_sample_40.lower_max_index = lower_max_index;
- fft_sample_40.upper_max_index = upper_max_index;
- lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins);
- upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins);
- fft_sample_40.lower_bitmap_weight = lower_bitmap_w;
- fft_sample_40.upper_bitmap_weight = upper_bitmap_w;
- fft_sample_40.max_exp = mag_info->max_exp & 0xf;
- fft_sample_40.tsf = __cpu_to_be64(tsf);
-
- tlv = (struct fft_sample_tlv *)&fft_sample_40;
- } else {
- u8 max_index, bitmap_w;
- u16 magnitude;
- struct ath_ht20_mag_info *mag_info;
-
- length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv);
- fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20;
- fft_sample_20.tlv.length = __cpu_to_be16(length);
- fft_sample_20.freq = __cpu_to_be16(freq);
-
- fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
- fft_sample_20.noise = ah->noise;
-
- mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
- magnitude = spectral_max_magnitude(mag_info->all_bins);
- fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
- max_index = spectral_max_index(mag_info->all_bins);
- fft_sample_20.max_index = max_index;
- bitmap_w = spectral_bitmap_weight(mag_info->all_bins);
- fft_sample_20.bitmap_weight = bitmap_w;
- fft_sample_20.max_exp = mag_info->max_exp & 0xf;
-
- fft_sample_20.tsf = __cpu_to_be64(tsf);
+ /* Search for the end of the FFT frame between
+ * sample_len - 1 and sample_len + 2. exp_max is 3
+ * bits long and it's the only value on the last
+ * byte of the frame so since it'll be smaller than
+ * the next byte (the first bin of the next sample)
+ * 90% of the time, we can use it as a separator.
+ */
+ if (vdata[i] <= 0x7 && sample_bytes >= sample_len - 1) {
+
+ /* Got a frame length within boundaries, there are
+ * four scenarios here:
+ *
+ * a) sample_len -> We got the correct length
+ * b) sample_len + 2 -> 2 bytes added around bin[31]
+ * c) sample_len - 1 -> The first byte is missing
+ * d) sample_len + 1 -> b + c at the same time
+ *
+ * When MAC adds 2 extra bytes, bin[31] and bin[32]
+ * have the same value, so we can use that for further
+ * verification in cases b and d.
+ */
+
+ /* Did we go too far ? If so we couldn't determine
+ * this sample's boundaries, discard any further
+ * data
+ */
+ if ((sample_bytes > sample_len + 2) ||
+ ((sample_bytes > sample_len) &&
+ (sample_start[31] != sample_start[32])))
+ break;
+
+ /* See if we got a valid frame by checking the
+ * consistency of mag_info fields. This is to
+ * prevent from "fixing" a correct frame.
+ * Failure is non-fatal, later frames may
+ * be valid.
+ */
+ if (!fft_idx_validator(&vdata[i], i)) {
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Found valid fft frame at %i\n", i);
+ got_slen = 1;
+ }
+
+ /* We expect 1 - 2 more bytes */
+ else if ((sample_start[31] == sample_start[32]) &&
+ (sample_bytes >= sample_len) &&
+ (sample_bytes < sample_len + 2) &&
+ (vdata[i + 1] <= 0x7))
+ continue;
+
+ /* Try to distinguish cases a and c */
+ else if ((sample_bytes == sample_len - 1) &&
+ (vdata[i + 1] <= 0x7))
+ continue;
+
+ got_slen = 1;
+ }
- tlv = (struct fft_sample_tlv *)&fft_sample_20;
+ if (got_slen) {
+ ath_dbg(common, SPECTRAL_SCAN, "FFT frame len: %i\n",
+ sample_bytes);
+
+ /* Only try to fix a frame if it's the only one
+ * on the report, else just skip it.
+ */
+ if (sample_bytes != sample_len && len <= fft_len + 2) {
+ ath_cmn_copy_fft_frame(sample_start,
+ sample_buf, sample_len,
+ sample_bytes);
+
+ fft_handler(rs, spec_priv, sample_buf,
+ tsf, freq, chan_type);
+
+ memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
+
+ /* Mix the received bins to the /dev/random
+ * pool
+ */
+ add_device_randomness(sample_buf, num_bins);
+ }
+
+ /* Process a normal frame */
+ if (sample_bytes == sample_len) {
+ ret = fft_handler(rs, spec_priv, sample_start,
+ tsf, freq, chan_type);
+
+ /* Mix the received bins to the /dev/random
+ * pool
+ */
+ add_device_randomness(sample_start, num_bins);
+ }
+
+ /* Short report processed, break out of the
+ * loop.
+ */
+ if (len <= fft_len + 2)
+ break;
+
+ sample_start = &vdata[i + 1];
+
+ /* -1 to grab sample_len -1, -2 since
+ * they 'll get increased by one. In case
+ * of failure try to recover by going byte
+ * by byte instead.
+ */
+ if (ret == 0) {
+ i += num_bins - 2;
+ sample_bytes = num_bins - 2;
+ }
+ got_slen = 0;
+ }
}
- ath_debug_send_fft_sample(spec_priv, tlv);
-
+ i -= num_bins - 2;
+ if (len - i != sizeof(struct ath_radar_info))
+ ath_dbg(common, SPECTRAL_SCAN, "FFT report truncated"
+ "(bytes left: %i)\n",
+ len - i);
return 1;
}
EXPORT_SYMBOL(ath_cmn_process_fft);
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.h b/drivers/net/wireless/ath/ath9k/common-spectral.h
index 82d9dd29652c..998743be9c67 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.h
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.h
@@ -66,6 +66,8 @@ struct ath_ht20_fft_packet {
} __packed;
#define SPECTRAL_HT20_TOTAL_DATA_LEN (sizeof(struct ath_ht20_fft_packet))
+#define SPECTRAL_HT20_SAMPLE_LEN (sizeof(struct ath_ht20_mag_info) +\
+ SPECTRAL_HT20_NUM_BINS)
/* Dynamic 20/40 mode:
*
@@ -101,6 +103,10 @@ struct ath_spec_scan_priv {
};
#define SPECTRAL_HT20_40_TOTAL_DATA_LEN (sizeof(struct ath_ht20_40_fft_packet))
+#define SPECTRAL_HT20_40_SAMPLE_LEN (sizeof(struct ath_ht20_40_mag_info) +\
+ SPECTRAL_HT20_40_NUM_BINS)
+
+#define SPECTRAL_SAMPLE_MAX_LEN SPECTRAL_HT20_40_SAMPLE_LEN
/* grabs the max magnitude from the all/upper/lower bins */
static inline u16 spectral_max_magnitude(u8 *bins)
@@ -111,17 +117,32 @@ static inline u16 spectral_max_magnitude(u8 *bins)
}
/* return the max magnitude from the all/upper/lower bins */
-static inline u8 spectral_max_index(u8 *bins)
+static inline u8 spectral_max_index(u8 *bins, int num_bins)
{
s8 m = (bins[2] & 0xfc) >> 2;
-
- /* TODO: this still doesn't always report the right values ... */
- if (m > 32)
+ u8 zero_idx = num_bins / 2;
+
+ /* It's a 5 bit signed int, remove its sign and use one's
+ * complement interpretation to add the sign back to the 8
+ * bit int
+ */
+ if (m & 0x20) {
+ m &= ~0x20;
m |= 0xe0;
- else
- m &= ~0xe0;
+ }
+
+ /* Bring the zero point to the beginning
+ * instead of the middle so that we can use
+ * it for array lookup and that we don't deal
+ * with negative values later
+ */
+ m += zero_idx;
+
+ /* Sanity check to make sure index is within bounds */
+ if (m < 0 || m > num_bins - 1)
+ m = 0;
- return m + 29;
+ return m;
}
/* return the bitmap weight from the all/upper/lower bins */
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index e82a0d4ce23f..16dff4b89a86 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -440,9 +440,9 @@ static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv)
}
#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
-#define OP_BT_PRIORITY_DETECTED BIT(3)
-#define OP_BT_SCAN BIT(4)
-#define OP_TSF_RESET BIT(6)
+#define OP_BT_PRIORITY_DETECTED 3
+#define OP_BT_SCAN 4
+#define OP_TSF_RESET 6
enum htc_op_flags {
HTC_FWFLAG_NO_RMW,
@@ -531,6 +531,7 @@ struct ath9k_htc_priv {
struct ath9k_debug debug;
#endif
struct mutex mutex;
+ struct ieee80211_vif *csa_vif;
};
static inline void ath_read_cachesize(struct ath_common *common, int *csz)
@@ -584,6 +585,7 @@ void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv);
void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event);
void ath9k_tx_failed_tasklet(unsigned long data);
void ath9k_htc_tx_cleanup_timer(unsigned long data);
+bool ath9k_htc_csa_is_finished(struct ath9k_htc_priv *priv);
int ath9k_rx_init(struct ath9k_htc_priv *priv);
void ath9k_rx_cleanup(struct ath9k_htc_priv *priv);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index e8b6ec3c1dbb..e6bcb4c90fa0 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -257,6 +257,8 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
}
spin_unlock_bh(&priv->beacon_lock);
+
+ ath9k_htc_csa_is_finished(priv);
}
static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv,
@@ -503,3 +505,20 @@ void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv)
return;
}
}
+
+bool ath9k_htc_csa_is_finished(struct ath9k_htc_priv *priv)
+{
+ struct ieee80211_vif *vif;
+
+ vif = priv->csa_vif;
+ if (!vif || !vif->csa_active)
+ return false;
+
+ if (!ieee80211_csa_is_complete(vif))
+ return false;
+
+ ieee80211_csa_finish(vif);
+
+ priv->csa_vif = NULL;
+ return true;
+}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index d7beefe60683..39eaf9b6e9b4 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -594,7 +594,7 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv)
priv->spec_priv.ah = priv->ah;
priv->spec_priv.spec_config.enabled = 0;
- priv->spec_priv.spec_config.short_repeat = false;
+ priv->spec_priv.spec_config.short_repeat = true;
priv->spec_priv.spec_config.count = 8;
priv->spec_priv.spec_config.endless = false;
priv->spec_priv.spec_config.period = 0x12;
@@ -717,18 +717,18 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
struct ath_common *common = ath9k_hw_common(priv->ah);
struct base_eep_header *pBase;
- hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_HAS_RATE_CONTROL |
- IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_PS_NULLFUNC_STACK |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_MFP_CAPABLE |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
if (ath9k_ps_enable)
- hw->flags |= IEEE80211_HW_SUPPORTS_PS;
+ ieee80211_hw_set(hw, SUPPORTS_PS);
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
@@ -744,7 +744,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN |
- WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+ WIPHY_FLAG_HAS_CHANNEL_SWITCH;
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 564923c0df87..dab1323dfec7 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1134,6 +1134,9 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
priv->nvifs--;
priv->vif_slot &= ~(1 << avp->index);
+ if (priv->csa_vif == vif)
+ priv->csa_vif = NULL;
+
ath9k_htc_remove_station(priv, vif, NULL);
DEC_VIF(priv, vif->type);
@@ -1238,8 +1241,7 @@ out:
}
#define SUPPORTED_FILTERS \
- (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | \
+ (FIF_ALLMULTI | \
FIF_CONTROL | \
FIF_PSPOLL | \
FIF_OTHER_BSS | \
@@ -1842,6 +1844,19 @@ static int ath9k_htc_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant,
return 0;
}
+static void ath9k_htc_channel_switch_beacon(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_chan_def *chandef)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+
+ /* mac80211 does not support CSA in multi-if cases (yet) */
+ if (WARN_ON(priv->csa_vif))
+ return;
+
+ priv->csa_vif = vif;
+}
+
struct ieee80211_ops ath9k_htc_ops = {
.tx = ath9k_htc_tx,
.start = ath9k_htc_start,
@@ -1868,6 +1883,7 @@ struct ieee80211_ops ath9k_htc_ops = {
.set_bitrate_mask = ath9k_htc_set_bitrate_mask,
.get_stats = ath9k_htc_get_stats,
.get_antenna = ath9k_htc_get_antenna,
+ .channel_switch_beacon = ath9k_htc_channel_switch_beacon,
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
.get_et_sset_count = ath9k_htc_get_et_sset_count,
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index a0f58e2aa553..cc9648f844ae 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -872,14 +872,7 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
if (priv->rxfilter & FIF_PROBE_REQ)
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
- /*
- * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
- * mode interface or when in monitor mode. AP mode does not need this
- * since it receives all in-BSS frames anyway.
- */
- if (((ah->opmode != NL80211_IFTYPE_AP) &&
- (priv->rxfilter & FIF_PROMISC_IN_BSS)) ||
- ah->is_monitoring)
+ if (ah->is_monitoring)
rfilt |= ATH9K_RX_FILTER_PROM;
if (priv->rxfilter & FIF_CONTROL)
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index c1d2d0340feb..e8454db17634 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -1119,6 +1119,8 @@ bool ar9003_is_paprd_enabled(struct ath_hw *ah);
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
void ar9003_hw_init_rate_txpower(struct ath_hw *ah, u8 *rate_array,
struct ath9k_channel *chan);
+void ar5008_hw_cmn_spur_mitigate(struct ath_hw *ah,
+ struct ath9k_channel *chan, int bin);
void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array,
struct ath9k_channel *chan, int ht40_delta);
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index f8d11efa7b0f..eff0e5325e6a 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -796,7 +796,7 @@ static void ath9k_set_mcc_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
if (!ath9k_is_chanctx_enabled())
return;
- hw->flags |= IEEE80211_HW_QUEUE_CONTROL;
+ ieee80211_hw_set(hw, QUEUE_CONTROL);
hw->queues = ATH9K_NUM_TX_QUEUES;
hw->offchannel_tx_hw_queue = hw->queues - 1;
hw->wiphy->interface_modes &= ~ BIT(NL80211_IFTYPE_WDS);
@@ -818,20 +818,20 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_PS_NULLFUNC_STACK |
- IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_SUPPORTS_RC_TABLE |
- IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
+ ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
+ ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
if (ath9k_ps_enable)
- hw->flags |= IEEE80211_HW_SUPPORTS_PS;
+ ieee80211_hw_set(hw, SUPPORTS_PS);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
- hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
if (AR_SREV_9280_20_OR_LATER(ah))
hw->radiotap_mcs_details |=
@@ -839,7 +839,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
}
if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt)
- hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+ ieee80211_hw_set(hw, MFP_CAPABLE);
hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index b0badef71ce7..cfd45cb8ccfc 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -216,11 +216,13 @@ static bool ath_prepare_reset(struct ath_softc *sc)
ath_stop_ani(sc);
ath9k_hw_disable_interrupts(ah);
- if (!ath_drain_all_txq(sc))
- ret = false;
-
- if (!ath_stoprecv(sc))
- ret = false;
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
+ ret &= ath_stoprecv(sc);
+ ret &= ath_drain_all_txq(sc);
+ } else {
+ ret &= ath_drain_all_txq(sc);
+ ret &= ath_stoprecv(sc);
+ }
return ret;
}
@@ -1442,8 +1444,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
#define SUPPORTED_FILTERS \
- (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | \
+ (FIF_ALLMULTI | \
FIF_CONTROL | \
FIF_PSPOLL | \
FIF_OTHER_BSS | \
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 6fb40ef86fd6..6c75fb1ab77d 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -392,11 +392,6 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (sc->cur_chan->rxfilter & FIF_PROBE_REQ)
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
- /*
- * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
- * mode interface or when in monitor mode. AP mode does not need this
- * since it receives all in-BSS frames anyway.
- */
if (sc->sc_ah->is_monitoring)
rfilt |= ATH9K_RX_FILTER_PROM;
diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c
index 47d5c2e910ad..88045f93a76c 100644
--- a/drivers/net/wireless/ath/carl9170/fw.c
+++ b/drivers/net/wireless/ath/carl9170/fw.c
@@ -286,7 +286,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
}
if (SUPP(CARL9170FW_PSM) && SUPP(CARL9170FW_FIXED_5GHZ_PSM))
- ar->hw->flags |= IEEE80211_HW_SUPPORTS_PS;
+ ieee80211_hw_set(ar->hw, SUPPORTS_PS);
if (!SUPP(CARL9170FW_USB_INIT_FIRMWARE)) {
dev_err(&ar->udev->dev, "firmware does not provide "
@@ -310,8 +310,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
if (SUPP(CARL9170FW_RX_FILTER)) {
ar->fw.rx_filter = true;
ar->rx_filter_caps = FIF_FCSFAIL | FIF_PLCPFAIL |
- FIF_CONTROL | FIF_PSPOLL | FIF_OTHER_BSS |
- FIF_PROMISC_IN_BSS;
+ FIF_CONTROL | FIF_PSPOLL | FIF_OTHER_BSS;
}
if (SUPP(CARL9170FW_HW_COUNTERS))
diff --git a/drivers/net/wireless/ath/carl9170/led.c b/drivers/net/wireless/ath/carl9170/led.c
index 78dadc797558..2c74425f5059 100644
--- a/drivers/net/wireless/ath/carl9170/led.c
+++ b/drivers/net/wireless/ath/carl9170/led.c
@@ -122,7 +122,7 @@ static void carl9170_led_set_brightness(struct led_classdev *led,
}
static int carl9170_led_register_led(struct ar9170 *ar, int i, char *name,
- char *trigger)
+ const char *trigger)
{
int err;
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index f1455a04cb62..170c209f99b8 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1011,9 +1011,8 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw,
if (multicast != ar->cur_mc_hash)
WARN_ON(carl9170_update_multicast(ar, multicast));
- if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
- ar->sniffer_enabled = !!(*new_flags &
- (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS));
+ if (changed_flags & FIF_OTHER_BSS) {
+ ar->sniffer_enabled = !!(*new_flags & FIF_OTHER_BSS);
WARN_ON(carl9170_set_operating_mode(ar));
}
@@ -1033,7 +1032,7 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw,
if (!(*new_flags & FIF_PSPOLL))
rx_filter |= CARL9170_RX_FILTER_CTL_PSPOLL;
- if (!(*new_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))) {
+ if (!(*new_flags & FIF_OTHER_BSS)) {
rx_filter |= CARL9170_RX_FILTER_OTHER_RA;
rx_filter |= CARL9170_RX_FILTER_DECRY_FAIL;
}
@@ -1845,22 +1844,22 @@ void *carl9170_alloc(size_t priv_size)
/* firmware decides which modes we support */
hw->wiphy->interface_modes = 0;
- hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_MFP_CAPABLE |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK |
- IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
- IEEE80211_HW_SUPPORTS_RC_TABLE |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+ ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC);
+ ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
if (!modparam_noht) {
/*
* see the comment above, why we allow the user
* to disable HT by a module parameter.
*/
- hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
}
hw->extra_tx_headroom = sizeof(struct _carl9170_tx_superframe);
diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c
index c9f93310c0d6..76842e6ca38e 100644
--- a/drivers/net/wireless/ath/carl9170/usb.c
+++ b/drivers/net/wireless/ath/carl9170/usb.c
@@ -651,6 +651,7 @@ int carl9170_exec_cmd(struct ar9170 *ar, const enum carl9170_cmd_oids cmd,
unsigned int plen, void *payload, unsigned int outlen, void *out)
{
int err = -ENOMEM;
+ unsigned long time_left;
if (!IS_ACCEPTING_CMD(ar))
return -EIO;
@@ -672,8 +673,8 @@ int carl9170_exec_cmd(struct ar9170 *ar, const enum carl9170_cmd_oids cmd,
err = __carl9170_exec_cmd(ar, &ar->cmd, false);
if (!(cmd & CARL9170_CMD_ASYNC_FLAG)) {
- err = wait_for_completion_timeout(&ar->cmd_wait, HZ);
- if (err == 0) {
+ time_left = wait_for_completion_timeout(&ar->cmd_wait, HZ);
+ if (time_left == 0) {
err = -ETIMEDOUT;
goto err_unbuf;
}
diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c
index c657ca26a71a..656ce42b339a 100644
--- a/drivers/net/wireless/ath/dfs_pattern_detector.c
+++ b/drivers/net/wireless/ath/dfs_pattern_detector.c
@@ -41,30 +41,31 @@ struct radar_types {
/* percentage on ppb threshold to trigger detection */
#define MIN_PPB_THRESH 50
-#define PPB_THRESH(PPB) ((PPB * MIN_PPB_THRESH + 50) / 100)
+#define PPB_THRESH_RATE(PPB, RATE) ((PPB * RATE + 100 - RATE) / 100)
+#define PPB_THRESH(PPB) PPB_THRESH_RATE(PPB, MIN_PPB_THRESH)
#define PRF2PRI(PRF) ((1000000 + PRF / 2) / PRF)
/* percentage of pulse width tolerance */
#define WIDTH_TOLERANCE 5
#define WIDTH_LOWER(X) ((X*(100-WIDTH_TOLERANCE)+50)/100)
#define WIDTH_UPPER(X) ((X*(100+WIDTH_TOLERANCE)+50)/100)
-#define ETSI_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB) \
+#define ETSI_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB, CHIRP) \
{ \
ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \
(PRF2PRI(PMAX) - PRI_TOLERANCE), \
(PRF2PRI(PMIN) * PRF + PRI_TOLERANCE), PRF, PPB * PRF, \
- PPB_THRESH(PPB), PRI_TOLERANCE, \
+ PPB_THRESH(PPB), PRI_TOLERANCE, CHIRP \
}
/* radar types as defined by ETSI EN-301-893 v1.5.1 */
static const struct radar_detector_specs etsi_radar_ref_types_v15[] = {
- ETSI_PATTERN(0, 0, 1, 700, 700, 1, 18),
- ETSI_PATTERN(1, 0, 5, 200, 1000, 1, 10),
- ETSI_PATTERN(2, 0, 15, 200, 1600, 1, 15),
- ETSI_PATTERN(3, 0, 15, 2300, 4000, 1, 25),
- ETSI_PATTERN(4, 20, 30, 2000, 4000, 1, 20),
- ETSI_PATTERN(5, 0, 2, 300, 400, 3, 10),
- ETSI_PATTERN(6, 0, 2, 400, 1200, 3, 15),
+ ETSI_PATTERN(0, 0, 1, 700, 700, 1, 18, false),
+ ETSI_PATTERN(1, 0, 5, 200, 1000, 1, 10, false),
+ ETSI_PATTERN(2, 0, 15, 200, 1600, 1, 15, false),
+ ETSI_PATTERN(3, 0, 15, 2300, 4000, 1, 25, false),
+ ETSI_PATTERN(4, 20, 30, 2000, 4000, 1, 20, false),
+ ETSI_PATTERN(5, 0, 2, 300, 400, 3, 10, false),
+ ETSI_PATTERN(6, 0, 2, 400, 1200, 3, 15, false),
};
static const struct radar_types etsi_radar_types_v15 = {
@@ -73,21 +74,30 @@ static const struct radar_types etsi_radar_types_v15 = {
.radar_types = etsi_radar_ref_types_v15,
};
-#define FCC_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB) \
+#define FCC_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB, CHIRP) \
{ \
ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \
PMIN - PRI_TOLERANCE, \
PMAX * PRF + PRI_TOLERANCE, PRF, PPB * PRF, \
- PPB_THRESH(PPB), PRI_TOLERANCE, \
+ PPB_THRESH(PPB), PRI_TOLERANCE, CHIRP \
}
+/* radar types released on August 14, 2014
+ * type 1 PRI values randomly selected within the range of 518 and 3066.
+ * divide it to 3 groups is good enough for both of radar detection and
+ * avoiding false detection based on practical test results
+ * collected for more than a year.
+ */
static const struct radar_detector_specs fcc_radar_ref_types[] = {
- FCC_PATTERN(0, 0, 1, 1428, 1428, 1, 18),
- FCC_PATTERN(1, 0, 5, 150, 230, 1, 23),
- FCC_PATTERN(2, 6, 10, 200, 500, 1, 16),
- FCC_PATTERN(3, 11, 20, 200, 500, 1, 12),
- FCC_PATTERN(4, 50, 100, 1000, 2000, 1, 1),
- FCC_PATTERN(5, 0, 1, 333, 333, 1, 9),
+ FCC_PATTERN(0, 0, 1, 1428, 1428, 1, 18, false),
+ FCC_PATTERN(101, 0, 1, 518, 938, 1, 57, false),
+ FCC_PATTERN(102, 0, 1, 938, 2000, 1, 27, false),
+ FCC_PATTERN(103, 0, 1, 2000, 3066, 1, 18, false),
+ FCC_PATTERN(2, 0, 5, 150, 230, 1, 23, false),
+ FCC_PATTERN(3, 6, 10, 200, 500, 1, 16, false),
+ FCC_PATTERN(4, 11, 20, 200, 500, 1, 12, false),
+ FCC_PATTERN(5, 50, 100, 1000, 2000, 1, 1, true),
+ FCC_PATTERN(6, 0, 1, 333, 333, 1, 9, false),
};
static const struct radar_types fcc_radar_types = {
@@ -96,17 +106,23 @@ static const struct radar_types fcc_radar_types = {
.radar_types = fcc_radar_ref_types,
};
-#define JP_PATTERN FCC_PATTERN
+#define JP_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB, RATE, CHIRP) \
+{ \
+ ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \
+ PMIN - PRI_TOLERANCE, \
+ PMAX * PRF + PRI_TOLERANCE, PRF, PPB * PRF, \
+ PPB_THRESH_RATE(PPB, RATE), PRI_TOLERANCE, CHIRP \
+}
static const struct radar_detector_specs jp_radar_ref_types[] = {
- JP_PATTERN(0, 0, 1, 1428, 1428, 1, 18),
- JP_PATTERN(1, 2, 3, 3846, 3846, 1, 18),
- JP_PATTERN(2, 0, 1, 1388, 1388, 1, 18),
- JP_PATTERN(3, 1, 2, 4000, 4000, 1, 18),
- JP_PATTERN(4, 0, 5, 150, 230, 1, 23),
- JP_PATTERN(5, 6, 10, 200, 500, 1, 16),
- JP_PATTERN(6, 11, 20, 200, 500, 1, 12),
- JP_PATTERN(7, 50, 100, 1000, 2000, 1, 20),
- JP_PATTERN(5, 0, 1, 333, 333, 1, 9),
+ JP_PATTERN(0, 0, 1, 1428, 1428, 1, 18, 29, false),
+ JP_PATTERN(1, 2, 3, 3846, 3846, 1, 18, 29, false),
+ JP_PATTERN(2, 0, 1, 1388, 1388, 1, 18, 50, false),
+ JP_PATTERN(3, 1, 2, 4000, 4000, 1, 18, 50, false),
+ JP_PATTERN(4, 0, 5, 150, 230, 1, 23, 50, false),
+ JP_PATTERN(5, 6, 10, 200, 500, 1, 16, 50, false),
+ JP_PATTERN(6, 11, 20, 200, 500, 1, 12, 50, false),
+ JP_PATTERN(7, 50, 100, 1000, 2000, 1, 20, 50, false),
+ JP_PATTERN(5, 0, 1, 333, 333, 1, 9, 50, false),
};
static const struct radar_types jp_radar_types = {
diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.h b/drivers/net/wireless/ath/dfs_pattern_detector.h
index dde2652b787c..25a43d632f90 100644
--- a/drivers/net/wireless/ath/dfs_pattern_detector.h
+++ b/drivers/net/wireless/ath/dfs_pattern_detector.h
@@ -40,12 +40,14 @@ struct ath_dfs_pool_stats {
* @freq: channel frequency in MHz
* @width: pulse duration in us
* @rssi: rssi of radar event
+ * @chirp: chirp detected in pulse
*/
struct pulse_event {
u64 ts;
u16 freq;
u8 width;
u8 rssi;
+ bool chirp;
};
/**
@@ -59,6 +61,7 @@ struct pulse_event {
* @ppb: pulses per bursts for this type
* @ppb_thresh: number of pulses required to trigger detection
* @max_pri_tolerance: pulse time stamp tolerance on both sides [us]
+ * @chirp: chirp required for the radar pattern
*/
struct radar_detector_specs {
u8 type_id;
@@ -70,6 +73,7 @@ struct radar_detector_specs {
u8 ppb;
u8 ppb_thresh;
u8 max_pri_tolerance;
+ bool chirp;
};
/**
diff --git a/drivers/net/wireless/ath/dfs_pri_detector.c b/drivers/net/wireless/ath/dfs_pri_detector.c
index 43b608178884..1b5ad1965607 100644
--- a/drivers/net/wireless/ath/dfs_pri_detector.c
+++ b/drivers/net/wireless/ath/dfs_pri_detector.c
@@ -390,6 +390,10 @@ static struct pri_sequence *pri_detector_add_pulse(struct pri_detector *de,
if ((ts - de->last_ts) < rs->max_pri_tolerance)
/* if delta to last pulse is too short, don't use this pulse */
return NULL;
+ /* radar detector spec needs chirp, but not detected */
+ if (rs->chirp && rs->chirp != event->chirp)
+ return NULL;
+
de->last_ts = ts;
max_updated_seq = pseq_handler_add_to_existing_seqs(de, ts);
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index 0783d2ed8238..900e72a089d8 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -944,12 +944,12 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
WLAN_CIPHER_SUITE_CCMP,
};
- wcn->hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_HAS_RATE_CONTROL |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_CONNECTION_MONITOR |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_TIMING_BEACON_ONLY;
+ ieee80211_hw_set(wcn->hw, TIMING_BEACON_ONLY);
+ ieee80211_hw_set(wcn->hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(wcn->hw, CONNECTION_MONITOR);
+ ieee80211_hw_set(wcn->hw, SUPPORTS_PS);
+ ieee80211_hw_set(wcn->hw, SIGNAL_DBM);
+ ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL);
wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index dbd894428be6..c9263e1c75d4 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -216,9 +216,7 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
memcpy(&sta_params->bssid, vif->addr, ETH_ALEN);
sta_params->encrypt_type = priv_vif->encrypt_type;
- sta_params->short_preamble_supported =
- !(WCN36XX_FLAGS(wcn) &
- IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE);
+ sta_params->short_preamble_supported = true;
sta_params->rifs_mode = 0;
sta_params->rmf = 0;
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
index caa717bf52f3..050506f842e9 100644
--- a/drivers/net/wireless/ath/wil6210/Makefile
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -12,6 +12,7 @@ wil6210-y += debug.o
wil6210-y += rx_reorder.o
wil6210-y += ioctl.o
wil6210-y += fw.o
+wil6210-y += pmc.o
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
wil6210-y += wil_platform.o
wil6210-y += ethtool.o
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index b97172667bc7..c79cfe02ec80 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -289,6 +289,26 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
}
wil_dbg_misc(wil, "Start scan_request 0x%p\n", request);
+ wil_dbg_misc(wil, "SSID count: %d", request->n_ssids);
+
+ for (i = 0; i < request->n_ssids; i++) {
+ wil_dbg_misc(wil, "SSID[%d]", i);
+ print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
+ request->ssids[i].ssid,
+ request->ssids[i].ssid_len);
+ }
+
+ if (request->n_ssids)
+ rc = wmi_set_ssid(wil, request->ssids[0].ssid_len,
+ request->ssids[0].ssid);
+ else
+ rc = wmi_set_ssid(wil, 0, NULL);
+
+ if (rc) {
+ wil_err(wil, "set SSID for scan request failed: %d\n", rc);
+ return rc;
+ }
+
wil->scan_request = request;
mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO);
@@ -402,11 +422,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
rsn_eid = sme->ie ?
cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
NULL;
-
- if (sme->privacy && !rsn_eid) {
- wil_err(wil, "Missing RSN IE for secure connection\n");
- return -EINVAL;
- }
+ if (sme->privacy && !rsn_eid)
+ wil_info(wil, "WSC connection\n");
bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
sme->ssid, sme->ssid_len,
@@ -425,10 +442,17 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
wil->privacy = sme->privacy;
if (wil->privacy) {
- /* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */
- rc = wmi_del_cipher_key(wil, 0, bss->bssid);
+ /* For secure assoc, remove old keys */
+ rc = wmi_del_cipher_key(wil, 0, bss->bssid,
+ WMI_KEY_USE_PAIRWISE);
+ if (rc) {
+ wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(PTK) failed\n");
+ goto out;
+ }
+ rc = wmi_del_cipher_key(wil, 0, bss->bssid,
+ WMI_KEY_USE_RX_GROUP);
if (rc) {
- wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n");
+ wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(GTK) failed\n");
goto out;
}
}
@@ -458,11 +482,18 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
goto out;
}
if (wil->privacy) {
- conn.dot11_auth_mode = WMI_AUTH11_SHARED;
- conn.auth_mode = WMI_AUTH_WPA2_PSK;
- conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP;
- conn.pairwise_crypto_len = 16;
- } else {
+ if (rsn_eid) { /* regular secure connection */
+ conn.dot11_auth_mode = WMI_AUTH11_SHARED;
+ conn.auth_mode = WMI_AUTH_WPA2_PSK;
+ conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP;
+ conn.pairwise_crypto_len = 16;
+ conn.group_crypto_type = WMI_CRYPT_AES_GCMP;
+ conn.group_crypto_len = 16;
+ } else { /* WSC */
+ conn.dot11_auth_mode = WMI_AUTH11_WSC;
+ conn.auth_mode = WMI_AUTH_NONE;
+ }
+ } else { /* insecure connection */
conn.dot11_auth_mode = WMI_AUTH11_OPEN;
conn.auth_mode = WMI_AUTH_NONE;
}
@@ -507,6 +538,8 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
int rc;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ wil_dbg_misc(wil, "%s(reason=%d)\n", __func__, reason_code);
+
rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
return rc;
@@ -561,6 +594,39 @@ static int wil_cfg80211_set_channel(struct wiphy *wiphy,
return 0;
}
+static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil,
+ bool pairwise)
+{
+ struct wireless_dev *wdev = wil->wdev;
+ enum wmi_key_usage rc;
+ static const char * const key_usage_str[] = {
+ [WMI_KEY_USE_PAIRWISE] = "WMI_KEY_USE_PAIRWISE",
+ [WMI_KEY_USE_RX_GROUP] = "WMI_KEY_USE_RX_GROUP",
+ [WMI_KEY_USE_TX_GROUP] = "WMI_KEY_USE_TX_GROUP",
+ };
+
+ if (pairwise) {
+ rc = WMI_KEY_USE_PAIRWISE;
+ } else {
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_STATION:
+ rc = WMI_KEY_USE_RX_GROUP;
+ break;
+ case NL80211_IFTYPE_AP:
+ rc = WMI_KEY_USE_TX_GROUP;
+ break;
+ default:
+ /* TODO: Rx GTK or Tx GTK? */
+ wil_err(wil, "Can't determine GTK type\n");
+ rc = WMI_KEY_USE_RX_GROUP;
+ break;
+ }
+ }
+ wil_dbg_misc(wil, "%s() -> %s\n", __func__, key_usage_str[rc]);
+
+ return rc;
+}
+
static int wil_cfg80211_add_key(struct wiphy *wiphy,
struct net_device *ndev,
u8 key_index, bool pairwise,
@@ -568,13 +634,13 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
struct key_params *params)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);
- /* group key is not used */
- if (!pairwise)
- return 0;
+ wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index,
+ pairwise ? "PTK" : "GTK");
- return wmi_add_cipher_key(wil, key_index, mac_addr,
- params->key_len, params->key);
+ return wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len,
+ params->key, key_usage);
}
static int wil_cfg80211_del_key(struct wiphy *wiphy,
@@ -583,12 +649,12 @@ static int wil_cfg80211_del_key(struct wiphy *wiphy,
const u8 *mac_addr)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);
- /* group key is not used */
- if (!pairwise)
- return 0;
+ wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index,
+ pairwise ? "PTK" : "GTK");
- return wmi_del_cipher_key(wil, key_index, mac_addr);
+ return wmi_del_cipher_key(wil, key_index, mac_addr, key_usage);
}
/* Need to be present or wiphy_new() will WARN */
@@ -661,11 +727,6 @@ static int wil_fix_bcon(struct wil6210_priv *wil,
if (bcon->probe_resp_len <= hlen)
return 0;
- if (!bcon->proberesp_ies) {
- bcon->proberesp_ies = f->u.probe_resp.variable;
- bcon->proberesp_ies_len = bcon->probe_resp_len - hlen;
- rc = 1;
- }
if (!bcon->assocresp_ies) {
bcon->assocresp_ies = f->u.probe_resp.variable;
bcon->assocresp_ies_len = bcon->probe_resp_len - hlen;
@@ -680,9 +741,19 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
struct cfg80211_beacon_data *bcon)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp;
+ size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+ const u8 *pr_ies = NULL;
+ size_t pr_ies_len = 0;
int rc;
wil_dbg_misc(wil, "%s()\n", __func__);
+ wil_print_bcon_data(bcon);
+
+ if (bcon->probe_resp_len > hlen) {
+ pr_ies = f->u.probe_resp.variable;
+ pr_ies_len = bcon->probe_resp_len - hlen;
+ }
if (wil_fix_bcon(wil, bcon)) {
wil_dbg_misc(wil, "Fixed bcon\n");
@@ -695,9 +766,7 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
* wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
* bcon->beacon_ies);
*/
- rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
- bcon->proberesp_ies_len,
- bcon->proberesp_ies);
+ rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies);
if (rc) {
wil_err(wil, "set_ie(PROBE_RESP) failed\n");
return rc;
@@ -725,6 +794,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
struct cfg80211_beacon_data *bcon = &info->beacon;
struct cfg80211_crypto_settings *crypto = &info->crypto;
u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
+ struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp;
+ size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+ const u8 *pr_ies = NULL;
+ size_t pr_ies_len = 0;
+ u8 hidden_ssid;
wil_dbg_misc(wil, "%s()\n", __func__);
@@ -737,6 +811,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
channel->center_freq, info->privacy ? "secure" : "open");
wil_dbg_misc(wil, "Privacy: %d auth_type %d\n",
info->privacy, info->auth_type);
+ wil_dbg_misc(wil, "Hidden SSID mode: %d\n",
+ info->hidden_ssid);
wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval,
info->dtim_period);
print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
@@ -744,6 +820,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
wil_print_bcon_data(bcon);
wil_print_crypto(wil, crypto);
+ if (bcon->probe_resp_len > hlen) {
+ pr_ies = f->u.probe_resp.variable;
+ pr_ies_len = bcon->probe_resp_len - hlen;
+ }
+
if (wil_fix_bcon(wil, bcon)) {
wil_dbg_misc(wil, "Fixed bcon\n");
wil_print_bcon_data(bcon);
@@ -771,17 +852,34 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
* wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
* bcon->beacon_ies);
*/
- wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len,
- bcon->proberesp_ies);
+ wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies);
wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len,
bcon->assocresp_ies);
wil->privacy = info->privacy;
+ switch (info->hidden_ssid) {
+ case NL80211_HIDDEN_SSID_NOT_IN_USE:
+ hidden_ssid = WMI_HIDDEN_SSID_DISABLED;
+ break;
+
+ case NL80211_HIDDEN_SSID_ZERO_LEN:
+ hidden_ssid = WMI_HIDDEN_SSID_SEND_EMPTY;
+ break;
+
+ case NL80211_HIDDEN_SSID_ZERO_CONTENTS:
+ hidden_ssid = WMI_HIDDEN_SSID_CLEAR;
+ break;
+
+ default:
+ rc = -EOPNOTSUPP;
+ goto out;
+ }
+
netif_carrier_on(ndev);
rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype,
- channel->hw_value);
+ channel->hw_value, hidden_ssid);
if (rc)
goto err_pcp_start;
@@ -814,13 +912,9 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
wmi_pcp_stop(wil);
__wil_down(wil);
- __wil_up(wil);
mutex_unlock(&wil->mutex);
- /* some functions above might fail (e.g. __wil_up). Nevertheless, we
- * return success because AP has stopped
- */
return 0;
}
@@ -830,6 +924,9 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy,
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ wil_dbg_misc(wil, "%s(%pM, reason=%d)\n", __func__, params->mac,
+ params->reason_code);
+
mutex_lock(&wil->mutex);
wil6210_disconnect(wil, params->mac, params->reason_code, false);
mutex_unlock(&wil->mutex);
@@ -967,8 +1064,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {
static void wil_wiphy_init(struct wiphy *wiphy)
{
- /* TODO: set real value */
- wiphy->max_scan_ssids = 10;
+ wiphy->max_scan_ssids = 1;
wiphy->max_scan_ie_len = WMI_MAX_IE_LEN;
wiphy->max_num_pmkids = 0 /* TODO: */;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index bbc22d88f78f..75219a1b8805 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -24,6 +24,7 @@
#include "wil6210.h"
#include "wmi.h"
#include "txrx.h"
+#include "pmc.h"
/* Nasty hack. Better have per device instances */
static u32 mem_addr;
@@ -123,15 +124,17 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
if (cid < WIL6210_MAX_CID)
seq_printf(s,
- "\n%pM CID %d TID %d BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
+ "\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
wil->sta[cid].addr, cid, tid,
+ txdata->dot1x_open ? "+" : "-",
txdata->agg_wsize,
txdata->agg_timeout,
txdata->agg_amsdu ? "+" : "-",
used, avail, sidle);
else
seq_printf(s,
- "\nBroadcast [%3d|%3d] idle %s\n",
+ "\nBroadcast 1x%s [%3d|%3d] idle %s\n",
+ txdata->dot1x_open ? "+" : "-",
used, avail, sidle);
wil_print_vring(s, wil, name, vring, '_', 'H');
@@ -702,6 +705,89 @@ static const struct file_operations fops_back = {
.open = simple_open,
};
+/* pmc control, write:
+ * - "alloc <num descriptors> <descriptor_size>" to allocate PMC
+ * - "free" to release memory allocated for PMC
+ */
+static ssize_t wil_write_pmccfg(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ struct wil6210_priv *wil = file->private_data;
+ int rc;
+ char *kbuf = kmalloc(len + 1, GFP_KERNEL);
+ char cmd[9];
+ int num_descs, desc_size;
+
+ if (!kbuf)
+ return -ENOMEM;
+
+ rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
+ if (rc != len) {
+ kfree(kbuf);
+ return rc >= 0 ? -EIO : rc;
+ }
+
+ kbuf[len] = '\0';
+ rc = sscanf(kbuf, "%8s %d %d", cmd, &num_descs, &desc_size);
+ kfree(kbuf);
+
+ if (rc < 0)
+ return rc;
+
+ if (rc < 1) {
+ wil_err(wil, "pmccfg: no params given\n");
+ return -EINVAL;
+ }
+
+ if (0 == strcmp(cmd, "alloc")) {
+ if (rc != 3) {
+ wil_err(wil, "pmccfg: alloc requires 2 params\n");
+ return -EINVAL;
+ }
+ wil_pmc_alloc(wil, num_descs, desc_size);
+ } else if (0 == strcmp(cmd, "free")) {
+ if (rc != 1) {
+ wil_err(wil, "pmccfg: free does not have any params\n");
+ return -EINVAL;
+ }
+ wil_pmc_free(wil, true);
+ } else {
+ wil_err(wil, "pmccfg: Unrecognized command \"%s\"\n", cmd);
+ return -EINVAL;
+ }
+
+ return len;
+}
+
+static ssize_t wil_read_pmccfg(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wil6210_priv *wil = file->private_data;
+ char text[256];
+ char help[] = "pmc control, write:\n"
+ " - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n"
+ " - \"free\" to free memory allocated for pmc\n";
+
+ sprintf(text, "Last command status: %d\n\n%s",
+ wil_pmc_last_cmd_status(wil),
+ help);
+
+ return simple_read_from_buffer(user_buf, count, ppos, text,
+ strlen(text) + 1);
+}
+
+static const struct file_operations fops_pmccfg = {
+ .read = wil_read_pmccfg,
+ .write = wil_write_pmccfg,
+ .open = simple_open,
+};
+
+static const struct file_operations fops_pmcdata = {
+ .open = simple_open,
+ .read = wil_pmc_read,
+ .llseek = wil_pmc_llseek,
+};
+
/*---tx_mgmt---*/
/* Write mgmt frame to this file to send it */
static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
@@ -1111,8 +1197,7 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
status = "connected";
break;
}
- seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
- (p->data_port_open ? " data_port_open" : ""));
+ seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
if (p->status == wil_sta_connected) {
rc = wil_cid_fill_sinfo(wil, i, &sinfo);
@@ -1275,7 +1360,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
{
struct wil6210_priv *wil = s->private;
- int i, tid;
+ int i, tid, mcs;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i];
@@ -1292,8 +1377,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
status = "connected";
break;
}
- seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
- (p->data_port_open ? " data_port_open" : ""));
+ seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
if (p->status == wil_sta_connected) {
spin_lock_bh(&p->tid_rx_lock);
@@ -1306,6 +1390,12 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
}
}
spin_unlock_bh(&p->tid_rx_lock);
+ seq_puts(s, "Rx/MCS:");
+ for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs);
+ mcs++)
+ seq_printf(s, " %lld",
+ p->stats.rx_per_mcs[mcs]);
+ seq_puts(s, "\n");
}
}
@@ -1363,6 +1453,8 @@ static const struct {
{"tx_mgmt", S_IWUSR, &fops_txmgmt},
{"wmi_send", S_IWUSR, &fops_wmi},
{"back", S_IRUGO | S_IWUSR, &fops_back},
+ {"pmccfg", S_IRUGO | S_IWUSR, &fops_pmccfg},
+ {"pmcdata", S_IRUGO, &fops_pmcdata},
{"temp", S_IRUGO, &fops_temp},
{"freq", S_IRUGO, &fops_freq},
{"link", S_IRUGO, &fops_link},
@@ -1440,6 +1532,8 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
if (IS_ERR_OR_NULL(dbg))
return -ENODEV;
+ wil_pmc_init(wil);
+
wil6210_debugfs_init_files(wil, dbg);
wil6210_debugfs_init_isr(wil, dbg);
wil6210_debugfs_init_blobs(wil, dbg);
@@ -1459,4 +1553,9 @@ void wil6210_debugfs_remove(struct wil6210_priv *wil)
{
debugfs_remove_recursive(wil->debug);
wil->debug = NULL;
+
+ /* free pmc memory without sending command to fw, as it will
+ * be reset on the way down anyway
+ */
+ wil_pmc_free(wil, false);
}
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index c2a238426425..b9febab89167 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -25,6 +25,10 @@
#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
+bool debug_fw; /* = false; */
+module_param(debug_fw, bool, S_IRUGO);
+MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");
+
bool no_fw_recovery;
module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery");
@@ -96,6 +100,8 @@ module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, S_IRUGO);
MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order");
module_param_cb(tx_ring_order, &ring_order_ops, &tx_ring_order, S_IRUGO);
MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order");
+module_param_cb(bcast_ring_order, &ring_order_ops, &bcast_ring_order, S_IRUGO);
+MODULE_PARM_DESC(bcast_ring_order, " Bcast ring order; size = 1 << order");
#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
#define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
@@ -146,7 +152,6 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
sta->status);
- sta->data_port_open = false;
if (sta->status != wil_sta_unused) {
if (!from_event)
wmi_disconnect_sta(wil, sta->addr, reason_code);
@@ -224,7 +229,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
if (test_bit(wil_status_fwconnected, wil->status)) {
clear_bit(wil_status_fwconnected, wil->status);
cfg80211_disconnected(ndev, reason_code,
- NULL, 0, GFP_KERNEL);
+ NULL, 0, false, GFP_KERNEL);
} else if (test_bit(wil_status_fwconnecting, wil->status)) {
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
@@ -373,9 +378,10 @@ int wil_bcast_init(struct wil6210_priv *wil)
if (ri < 0)
return ri;
+ wil->bcast_vring = ri;
rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order);
- if (rc == 0)
- wil->bcast_vring = ri;
+ if (rc)
+ wil->bcast_vring = -1;
return rc;
}
@@ -547,7 +553,7 @@ static inline void wil_release_cpu(struct wil6210_priv *wil)
static int wil_target_reset(struct wil6210_priv *wil)
{
int delay = 0;
- u32 x;
+ u32 x, x1 = 0;
wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name);
@@ -602,12 +608,16 @@ static int wil_target_reset(struct wil6210_priv *wil)
do {
msleep(RST_DELAY);
x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready));
+ if (x1 != x) {
+ wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x);
+ x1 = x;
+ }
if (delay++ > RST_COUNT) {
wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
x);
return -ETIME;
}
- } while (!(x & BIT_BL_READY));
+ } while (x != BIT_BL_READY);
C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
@@ -686,6 +696,17 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
WARN_ON(!mutex_is_locked(&wil->mutex));
WARN_ON(test_bit(wil_status_napi_en, wil->status));
+ if (debug_fw) {
+ static const u8 mac[ETH_ALEN] = {
+ 0x00, 0xde, 0xad, 0x12, 0x34, 0x56,
+ };
+ struct net_device *ndev = wil_to_ndev(wil);
+
+ ether_addr_copy(ndev->perm_addr, mac);
+ ether_addr_copy(ndev->dev_addr, ndev->perm_addr);
+ return 0;
+ }
+
cancel_work_sync(&wil->disconnect_worker);
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
wil_bcast_fini(wil);
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index f2f7ea29558e..8ef18ace110f 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -24,6 +24,11 @@ static int wil_open(struct net_device *ndev)
wil_dbg_misc(wil, "%s()\n", __func__);
+ if (debug_fw) {
+ wil_err(wil, "%s() while in debug_fw mode\n", __func__);
+ return -EINVAL;
+ }
+
return wil_up(wil);
}
@@ -127,7 +132,7 @@ static void wil_dev_setup(struct net_device *dev)
dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT;
}
-void *wil_if_alloc(struct device *dev, void __iomem *csr)
+void *wil_if_alloc(struct device *dev)
{
struct net_device *ndev;
struct wireless_dev *wdev;
@@ -142,7 +147,6 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
}
wil = wdev_to_wil(wdev);
- wil->csr = csr;
wil->wdev = wdev;
wil_dbg_misc(wil, "%s()\n", __func__);
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 109986114abf..aa3ecc607ca3 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -27,10 +27,6 @@ MODULE_PARM_DESC(use_msi,
" Use MSI interrupt: "
"0 - don't, 1 - (default) - single, or 3");
-static bool debug_fw; /* = false; */
-module_param(debug_fw, bool, S_IRUGO);
-MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug");
-
static
void wil_set_capabilities(struct wil6210_priv *wil)
{
@@ -133,8 +129,6 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
mutex_lock(&wil->mutex);
rc = wil_reset(wil, false);
mutex_unlock(&wil->mutex);
- if (debug_fw)
- rc = 0;
if (rc)
goto release_irq;
@@ -169,7 +163,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct wil6210_priv *wil;
struct device *dev = &pdev->dev;
- void __iomem *csr;
int rc;
/* check HW */
@@ -184,9 +177,28 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENODEV;
}
+ wil = wil_if_alloc(dev);
+ if (IS_ERR(wil)) {
+ rc = (int)PTR_ERR(wil);
+ dev_err(dev, "wil_if_alloc failed: %d\n", rc);
+ return rc;
+ }
+ wil->pdev = pdev;
+ pci_set_drvdata(pdev, wil);
+ /* rollback to if_free */
+
+ wil->platform_handle =
+ wil_platform_init(&pdev->dev, &wil->platform_ops);
+ if (!wil->platform_handle) {
+ rc = -ENODEV;
+ wil_err(wil, "wil_platform_init failed\n");
+ goto if_free;
+ }
+ /* rollback to err_plat */
+
rc = pci_enable_device(pdev);
if (rc) {
- dev_err(&pdev->dev,
+ wil_err(wil,
"pci_enable_device failed, retry with MSI only\n");
/* Work around for platforms that can't allocate IRQ:
* retry with MSI only
@@ -194,47 +206,37 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pdev->msi_enabled = 1;
rc = pci_enable_device(pdev);
}
- if (rc)
- return -ENODEV;
+ if (rc) {
+ wil_err(wil,
+ "pci_enable_device failed, even with MSI only\n");
+ goto err_plat;
+ }
/* rollback to err_disable_pdev */
rc = pci_request_region(pdev, 0, WIL_NAME);
if (rc) {
- dev_err(&pdev->dev, "pci_request_region failed\n");
+ wil_err(wil, "pci_request_region failed\n");
goto err_disable_pdev;
}
/* rollback to err_release_reg */
- csr = pci_ioremap_bar(pdev, 0);
- if (!csr) {
- dev_err(&pdev->dev, "pci_ioremap_bar failed\n");
+ wil->csr = pci_ioremap_bar(pdev, 0);
+ if (!wil->csr) {
+ wil_err(wil, "pci_ioremap_bar failed\n");
rc = -ENODEV;
goto err_release_reg;
}
/* rollback to err_iounmap */
- dev_info(&pdev->dev, "CSR at %pR -> 0x%p\n", &pdev->resource[0], csr);
-
- wil = wil_if_alloc(dev, csr);
- if (IS_ERR(wil)) {
- rc = (int)PTR_ERR(wil);
- dev_err(dev, "wil_if_alloc failed: %d\n", rc);
- goto err_iounmap;
- }
- /* rollback to if_free */
+ wil_info(wil, "CSR at %pR -> 0x%p\n", &pdev->resource[0], wil->csr);
- pci_set_drvdata(pdev, wil);
- wil->pdev = pdev;
wil_set_capabilities(wil);
wil6210_clear_irq(wil);
- wil->platform_handle =
- wil_platform_init(&pdev->dev, &wil->platform_ops);
-
/* FW should raise IRQ when ready */
rc = wil_if_pcie_enable(wil);
if (rc) {
wil_err(wil, "Enable device failed\n");
- goto if_free;
+ goto err_iounmap;
}
/* rollback to bus_disable */
@@ -249,18 +251,19 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
- bus_disable:
+bus_disable:
wil_if_pcie_disable(wil);
- if_free:
+err_iounmap:
+ pci_iounmap(pdev, wil->csr);
+err_release_reg:
+ pci_release_region(pdev, 0);
+err_disable_pdev:
+ pci_disable_device(pdev);
+err_plat:
if (wil->platform_ops.uninit)
wil->platform_ops.uninit(wil->platform_handle);
+if_free:
wil_if_free(wil);
- err_iounmap:
- pci_iounmap(pdev, csr);
- err_release_reg:
- pci_release_region(pdev, 0);
- err_disable_pdev:
- pci_disable_device(pdev);
return rc;
}
@@ -275,12 +278,12 @@ static void wil_pcie_remove(struct pci_dev *pdev)
wil6210_debugfs_remove(wil);
wil_if_remove(wil);
wil_if_pcie_disable(wil);
- if (wil->platform_ops.uninit)
- wil->platform_ops.uninit(wil->platform_handle);
- wil_if_free(wil);
pci_iounmap(pdev, csr);
pci_release_region(pdev, 0);
pci_disable_device(pdev);
+ if (wil->platform_ops.uninit)
+ wil->platform_ops.uninit(wil->platform_handle);
+ wil_if_free(wil);
}
static const struct pci_device_id wil6210_pcie_ids[] = {
@@ -297,7 +300,27 @@ static struct pci_driver wil6210_driver = {
.name = WIL_NAME,
};
-module_pci_driver(wil6210_driver);
+static int __init wil6210_driver_init(void)
+{
+ int rc;
+
+ rc = wil_platform_modinit();
+ if (rc)
+ return rc;
+
+ rc = pci_register_driver(&wil6210_driver);
+ if (rc)
+ wil_platform_modexit();
+ return rc;
+}
+module_init(wil6210_driver_init);
+
+static void __exit wil6210_driver_exit(void)
+{
+ pci_unregister_driver(&wil6210_driver);
+ wil_platform_modexit();
+}
+module_exit(wil6210_driver_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>");
diff --git a/drivers/net/wireless/ath/wil6210/pmc.c b/drivers/net/wireless/ath/wil6210/pmc.c
new file mode 100644
index 000000000000..8a8cdc61b25b
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/pmc.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include "wmi.h"
+#include "wil6210.h"
+#include "txrx.h"
+#include "pmc.h"
+
+struct desc_alloc_info {
+ dma_addr_t pa;
+ void *va;
+};
+
+static int wil_is_pmc_allocated(struct pmc_ctx *pmc)
+{
+ return !!pmc->pring_va;
+}
+
+void wil_pmc_init(struct wil6210_priv *wil)
+{
+ memset(&wil->pmc, 0, sizeof(struct pmc_ctx));
+ mutex_init(&wil->pmc.lock);
+}
+
+/**
+ * Allocate the physical ring (p-ring) and the required
+ * number of descriptors of required size.
+ * Initialize the descriptors as required by pmc dma.
+ * The descriptors' buffers dwords are initialized to hold
+ * dword's serial number in the lsw and reserved value
+ * PCM_DATA_INVALID_DW_VAL in the msw.
+ */
+void wil_pmc_alloc(struct wil6210_priv *wil,
+ int num_descriptors,
+ int descriptor_size)
+{
+ u32 i;
+ struct pmc_ctx *pmc = &wil->pmc;
+ struct device *dev = wil_to_dev(wil);
+ struct wmi_pmc_cmd pmc_cmd = {0};
+
+ mutex_lock(&pmc->lock);
+
+ if (wil_is_pmc_allocated(pmc)) {
+ /* sanity check */
+ wil_err(wil, "%s: ERROR pmc is already allocated\n", __func__);
+ goto no_release_err;
+ }
+
+ pmc->num_descriptors = num_descriptors;
+ pmc->descriptor_size = descriptor_size;
+
+ wil_dbg_misc(wil, "%s: %d descriptors x %d bytes each\n",
+ __func__, num_descriptors, descriptor_size);
+
+ /* allocate descriptors info list in pmc context*/
+ pmc->descriptors = kcalloc(num_descriptors,
+ sizeof(struct desc_alloc_info),
+ GFP_KERNEL);
+ if (!pmc->descriptors) {
+ wil_err(wil, "%s: ERROR allocating pmc skb list\n", __func__);
+ goto no_release_err;
+ }
+
+ wil_dbg_misc(wil,
+ "%s: allocated descriptors info list %p\n",
+ __func__, pmc->descriptors);
+
+ /* Allocate pring buffer and descriptors.
+ * vring->va should be aligned on its size rounded up to power of 2
+ * This is granted by the dma_alloc_coherent
+ */
+ pmc->pring_va = dma_alloc_coherent(dev,
+ sizeof(struct vring_tx_desc) * num_descriptors,
+ &pmc->pring_pa,
+ GFP_KERNEL);
+
+ wil_dbg_misc(wil,
+ "%s: allocated pring %p => %pad. %zd x %d = total %zd bytes\n",
+ __func__,
+ pmc->pring_va, &pmc->pring_pa,
+ sizeof(struct vring_tx_desc),
+ num_descriptors,
+ sizeof(struct vring_tx_desc) * num_descriptors);
+
+ if (!pmc->pring_va) {
+ wil_err(wil, "%s: ERROR allocating pmc pring\n", __func__);
+ goto release_pmc_skb_list;
+ }
+
+ /* initially, all descriptors are SW owned
+ * For Tx, Rx, and PMC, ownership bit is at the same location, thus
+ * we can use any
+ */
+ for (i = 0; i < num_descriptors; i++) {
+ struct vring_tx_desc *_d = &pmc->pring_va[i];
+ struct vring_tx_desc dd, *d = &dd;
+ int j = 0;
+
+ pmc->descriptors[i].va = dma_alloc_coherent(dev,
+ descriptor_size,
+ &pmc->descriptors[i].pa,
+ GFP_KERNEL);
+
+ if (unlikely(!pmc->descriptors[i].va)) {
+ wil_err(wil,
+ "%s: ERROR allocating pmc descriptor %d",
+ __func__, i);
+ goto release_pmc_skbs;
+ }
+
+ for (j = 0; j < descriptor_size / sizeof(u32); j++) {
+ u32 *p = (u32 *)pmc->descriptors[i].va + j;
+ *p = PCM_DATA_INVALID_DW_VAL | j;
+ }
+
+ /* configure dma descriptor */
+ d->dma.addr.addr_low =
+ cpu_to_le32(lower_32_bits(pmc->descriptors[i].pa));
+ d->dma.addr.addr_high =
+ cpu_to_le16((u16)upper_32_bits(pmc->descriptors[i].pa));
+ d->dma.status = 0; /* 0 = HW_OWNED */
+ d->dma.length = cpu_to_le16(descriptor_size);
+ d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT;
+ *_d = *d;
+ }
+
+ wil_dbg_misc(wil, "%s: allocated successfully\n", __func__);
+
+ pmc_cmd.op = WMI_PMC_ALLOCATE;
+ pmc_cmd.ring_size = cpu_to_le16(pmc->num_descriptors);
+ pmc_cmd.mem_base = cpu_to_le64(pmc->pring_pa);
+
+ wil_dbg_misc(wil, "%s: send WMI_PMC_CMD with ALLOCATE op\n", __func__);
+ pmc->last_cmd_status = wmi_send(wil,
+ WMI_PMC_CMDID,
+ &pmc_cmd,
+ sizeof(pmc_cmd));
+ if (pmc->last_cmd_status) {
+ wil_err(wil,
+ "%s: WMI_PMC_CMD with ALLOCATE op failed with status %d",
+ __func__, pmc->last_cmd_status);
+ goto release_pmc_skbs;
+ }
+
+ mutex_unlock(&pmc->lock);
+
+ return;
+
+release_pmc_skbs:
+ wil_err(wil, "%s: exit on error: Releasing skbs...\n", __func__);
+ for (i = 0; pmc->descriptors[i].va && i < num_descriptors; i++) {
+ dma_free_coherent(dev,
+ descriptor_size,
+ pmc->descriptors[i].va,
+ pmc->descriptors[i].pa);
+
+ pmc->descriptors[i].va = NULL;
+ }
+ wil_err(wil, "%s: exit on error: Releasing pring...\n", __func__);
+
+ dma_free_coherent(dev,
+ sizeof(struct vring_tx_desc) * num_descriptors,
+ pmc->pring_va,
+ pmc->pring_pa);
+
+ pmc->pring_va = NULL;
+
+release_pmc_skb_list:
+ wil_err(wil, "%s: exit on error: Releasing descriptors info list...\n",
+ __func__);
+ kfree(pmc->descriptors);
+ pmc->descriptors = NULL;
+
+no_release_err:
+ pmc->last_cmd_status = -ENOMEM;
+ mutex_unlock(&pmc->lock);
+}
+
+/**
+ * Traverse the p-ring and release all buffers.
+ * At the end release the p-ring memory
+ */
+void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd)
+{
+ struct pmc_ctx *pmc = &wil->pmc;
+ struct device *dev = wil_to_dev(wil);
+ struct wmi_pmc_cmd pmc_cmd = {0};
+
+ mutex_lock(&pmc->lock);
+
+ pmc->last_cmd_status = 0;
+
+ if (!wil_is_pmc_allocated(pmc)) {
+ wil_dbg_misc(wil, "%s: Error, can't free - not allocated\n",
+ __func__);
+ pmc->last_cmd_status = -EPERM;
+ mutex_unlock(&pmc->lock);
+ return;
+ }
+
+ if (send_pmc_cmd) {
+ wil_dbg_misc(wil, "%s: send WMI_PMC_CMD with RELEASE op\n",
+ __func__);
+ pmc_cmd.op = WMI_PMC_RELEASE;
+ pmc->last_cmd_status =
+ wmi_send(wil, WMI_PMC_CMDID, &pmc_cmd,
+ sizeof(pmc_cmd));
+ if (pmc->last_cmd_status) {
+ wil_err(wil,
+ "%s WMI_PMC_CMD with RELEASE op failed, status %d",
+ __func__, pmc->last_cmd_status);
+ /* There's nothing we can do with this error.
+ * Normally, it should never occur.
+ * Continue to freeing all memory allocated for pmc.
+ */
+ }
+ }
+
+ if (pmc->pring_va) {
+ size_t buf_size = sizeof(struct vring_tx_desc) *
+ pmc->num_descriptors;
+
+ wil_dbg_misc(wil, "%s: free pring va %p\n",
+ __func__, pmc->pring_va);
+ dma_free_coherent(dev, buf_size, pmc->pring_va, pmc->pring_pa);
+
+ pmc->pring_va = NULL;
+ } else {
+ pmc->last_cmd_status = -ENOENT;
+ }
+
+ if (pmc->descriptors) {
+ int i;
+
+ for (i = 0;
+ pmc->descriptors[i].va && i < pmc->num_descriptors; i++) {
+ dma_free_coherent(dev,
+ pmc->descriptor_size,
+ pmc->descriptors[i].va,
+ pmc->descriptors[i].pa);
+ pmc->descriptors[i].va = NULL;
+ }
+ wil_dbg_misc(wil, "%s: free descriptor info %d/%d\n",
+ __func__, i, pmc->num_descriptors);
+ wil_dbg_misc(wil,
+ "%s: free pmc descriptors info list %p\n",
+ __func__, pmc->descriptors);
+ kfree(pmc->descriptors);
+ pmc->descriptors = NULL;
+ } else {
+ pmc->last_cmd_status = -ENOENT;
+ }
+
+ mutex_unlock(&pmc->lock);
+}
+
+/**
+ * Status of the last operation requested via debugfs: alloc/free/read.
+ * 0 - success or negative errno
+ */
+int wil_pmc_last_cmd_status(struct wil6210_priv *wil)
+{
+ wil_dbg_misc(wil, "%s: status %d\n", __func__,
+ wil->pmc.last_cmd_status);
+
+ return wil->pmc.last_cmd_status;
+}
+
+/**
+ * Read from required position up to the end of current descriptor,
+ * depends on descriptor size configured during alloc request.
+ */
+ssize_t wil_pmc_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *f_pos)
+{
+ struct wil6210_priv *wil = filp->private_data;
+ struct pmc_ctx *pmc = &wil->pmc;
+ size_t retval = 0;
+ unsigned long long idx;
+ loff_t offset;
+ size_t pmc_size = pmc->descriptor_size * pmc->num_descriptors;
+
+ mutex_lock(&pmc->lock);
+
+ if (!wil_is_pmc_allocated(pmc)) {
+ wil_err(wil, "%s: error, pmc is not allocated!\n", __func__);
+ pmc->last_cmd_status = -EPERM;
+ mutex_unlock(&pmc->lock);
+ return -EPERM;
+ }
+
+ wil_dbg_misc(wil,
+ "%s: size %u, pos %lld\n",
+ __func__, (unsigned)count, *f_pos);
+
+ pmc->last_cmd_status = 0;
+
+ idx = *f_pos;
+ do_div(idx, pmc->descriptor_size);
+ offset = *f_pos - (idx * pmc->descriptor_size);
+
+ if (*f_pos >= pmc_size) {
+ wil_dbg_misc(wil, "%s: reached end of pmc buf: %lld >= %u\n",
+ __func__, *f_pos, (unsigned)pmc_size);
+ pmc->last_cmd_status = -ERANGE;
+ goto out;
+ }
+
+ wil_dbg_misc(wil,
+ "%s: read from pos %lld (descriptor %llu, offset %llu) %zu bytes\n",
+ __func__, *f_pos, idx, offset, count);
+
+ /* if no errors, return the copied byte count */
+ retval = simple_read_from_buffer(buf,
+ count,
+ &offset,
+ pmc->descriptors[idx].va,
+ pmc->descriptor_size);
+ *f_pos += retval;
+out:
+ mutex_unlock(&pmc->lock);
+
+ return retval;
+}
+
+loff_t wil_pmc_llseek(struct file *filp, loff_t off, int whence)
+{
+ loff_t newpos;
+ struct wil6210_priv *wil = filp->private_data;
+ struct pmc_ctx *pmc = &wil->pmc;
+ size_t pmc_size = pmc->descriptor_size * pmc->num_descriptors;
+
+ switch (whence) {
+ case 0: /* SEEK_SET */
+ newpos = off;
+ break;
+
+ case 1: /* SEEK_CUR */
+ newpos = filp->f_pos + off;
+ break;
+
+ case 2: /* SEEK_END */
+ newpos = pmc_size;
+ break;
+
+ default: /* can't happen */
+ return -EINVAL;
+ }
+
+ if (newpos < 0)
+ return -EINVAL;
+ if (newpos > pmc_size)
+ newpos = pmc_size;
+
+ filp->f_pos = newpos;
+
+ return newpos;
+}
diff --git a/drivers/net/wireless/ath/wil6210/pmc.h b/drivers/net/wireless/ath/wil6210/pmc.h
new file mode 100644
index 000000000000..bebc8d52e1e6
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/pmc.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/types.h>
+
+#define PCM_DATA_INVALID_DW_VAL (0xB0BA0000)
+
+void wil_pmc_init(struct wil6210_priv *wil);
+void wil_pmc_alloc(struct wil6210_priv *wil,
+ int num_descriptors, int descriptor_size);
+void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd);
+int wil_pmc_last_cmd_status(struct wil6210_priv *wil);
+ssize_t wil_pmc_read(struct file *, char __user *, size_t, loff_t *);
+loff_t wil_pmc_llseek(struct file *filp, loff_t off, int whence);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index e8bd512d81a9..aa20af86e1d6 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -236,7 +236,7 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
return -ENOMEM;
}
- d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT;
+ d->dma.d0 = RX_DMA_D0_CMD_DMA_RT | RX_DMA_D0_CMD_DMA_IT;
wil_desc_addr_set(&d->dma.addr, pa);
/* ip_length don't care */
/* b11 don't care */
@@ -427,6 +427,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
cid = wil_rxdesc_cid(d);
stats = &wil->sta[cid].stats;
stats->last_mcs_rx = wil_rxdesc_mcs(d);
+ if (stats->last_mcs_rx < ARRAY_SIZE(stats->rx_per_mcs))
+ stats->rx_per_mcs[stats->last_mcs_rx]++;
/* use radiotap header only if required */
if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
@@ -724,6 +726,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
+ if (!wil->privacy)
+ txdata->dot1x_open = true;
rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd),
WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
if (rc)
@@ -738,11 +742,13 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
txdata->enabled = 1;
- if (wil->sta[cid].data_port_open && (agg_wsize >= 0))
+ if (txdata->dot1x_open && (agg_wsize >= 0))
wil_addba_tx_request(wil, id, agg_wsize);
return 0;
out_free:
+ txdata->dot1x_open = false;
+ txdata->enabled = 0;
wil_vring_free(wil, vring, 1);
out:
@@ -792,6 +798,8 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
+ if (!wil->privacy)
+ txdata->dot1x_open = true;
rc = wmi_call(wil, WMI_BCAST_VRING_CFG_CMDID, &cmd, sizeof(cmd),
WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
if (rc)
@@ -809,6 +817,8 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
return 0;
out_free:
+ txdata->enabled = 0;
+ txdata->dot1x_open = false;
wil_vring_free(wil, vring, 1);
out:
@@ -828,6 +838,7 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
wil_dbg_misc(wil, "%s() id=%d\n", __func__, id);
spin_lock_bh(&txdata->lock);
+ txdata->dot1x_open = false;
txdata->enabled = 0; /* no Tx can be in progress or start anew */
spin_unlock_bh(&txdata->lock);
/* make sure NAPI won't touch this vring */
@@ -848,12 +859,11 @@ static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
if (cid < 0)
return NULL;
- if (!wil->sta[cid].data_port_open &&
- (skb->protocol != cpu_to_be16(ETH_P_PAE)))
- return NULL;
-
/* TODO: fix for multiple TID */
for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
+ if (!wil->vring_tx_data[i].dot1x_open &&
+ (skb->protocol != cpu_to_be16(ETH_P_PAE)))
+ continue;
if (wil->vring2cid_tid[i][0] == cid) {
struct vring *v = &wil->vring_tx[i];
@@ -883,7 +893,7 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
/* In the STA mode, it is expected to have only 1 VRING
* for the AP we connected to.
- * find 1-st vring and see whether it is eligible for data
+ * find 1-st vring eligible for this skb and use it.
*/
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
v = &wil->vring_tx[i];
@@ -894,9 +904,9 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
if (cid >= WIL6210_MAX_CID) /* skip BCAST */
continue;
- if (!wil->sta[cid].data_port_open &&
+ if (!wil->vring_tx_data[i].dot1x_open &&
(skb->protocol != cpu_to_be16(ETH_P_PAE)))
- break;
+ continue;
wil_dbg_txrx(wil, "Tx -> ring %d\n", i);
@@ -918,7 +928,6 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
* in all cases override dest address to unicast peer's address
* Use old strategy when new is not supported yet:
* - for PBSS
- * - for secure link
*/
static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
struct sk_buff *skb)
@@ -931,6 +940,9 @@ static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
v = &wil->vring_tx[i];
if (!v->va)
return NULL;
+ if (!wil->vring_tx_data[i].dot1x_open &&
+ (skb->protocol != cpu_to_be16(ETH_P_PAE)))
+ return NULL;
return v;
}
@@ -963,7 +975,8 @@ static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
cid = wil->vring2cid_tid[i][0];
if (cid >= WIL6210_MAX_CID) /* skip BCAST */
continue;
- if (!wil->sta[cid].data_port_open)
+ if (!wil->vring_tx_data[i].dot1x_open &&
+ (skb->protocol != cpu_to_be16(ETH_P_PAE)))
continue;
/* don't Tx back to source when re-routing Rx->Tx at the AP */
@@ -989,7 +1002,8 @@ found:
cid = wil->vring2cid_tid[i][0];
if (cid >= WIL6210_MAX_CID) /* skip BCAST */
continue;
- if (!wil->sta[cid].data_port_open)
+ if (!wil->vring_tx_data[i].dot1x_open &&
+ (skb->protocol != cpu_to_be16(ETH_P_PAE)))
continue;
if (0 == memcmp(wil->sta[cid].addr, src, ETH_ALEN))
@@ -1016,9 +1030,6 @@ static struct vring *wil_find_tx_bcast(struct wil6210_priv *wil,
if (wdev->iftype != NL80211_IFTYPE_AP)
return wil_find_tx_bcast_2(wil, skb);
- if (wil->privacy)
- return wil_find_tx_bcast_2(wil, skb);
-
return wil_find_tx_bcast_1(wil, skb);
}
@@ -1144,13 +1155,8 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
wil_tx_desc_map(d, pa, len, vring_index);
if (unlikely(mcast)) {
d->mac.d[0] |= BIT(MAC_CFG_DESC_TX_0_MCS_EN_POS); /* MCS 0 */
- if (unlikely(len > WIL_BCAST_MCS0_LIMIT)) {
- /* set MCS 1 */
+ if (unlikely(len > WIL_BCAST_MCS0_LIMIT)) /* set MCS 1 */
d->mac.d[0] |= (1 << MAC_CFG_DESC_TX_0_MCS_INDEX_POS);
- /* packet mode 2 */
- d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_PKT_MODE_EN_POS) |
- (2 << MAC_CFG_DESC_TX_1_PKT_MODE_POS);
- }
}
/* Process TCP/UDP checksum offloading */
if (unlikely(wil_tx_desc_offload_cksum_set(wil, d, skb))) {
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index d90c8aa20c15..0c4638487c74 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -384,19 +384,27 @@ struct vring_rx_mac {
* [word 7] length
*/
-#define RX_DMA_D0_CMD_DMA_IT BIT(10)
-
-/* Error field, offload bits */
-#define RX_DMA_ERROR_L3_ERR BIT(4)
-#define RX_DMA_ERROR_L4_ERR BIT(5)
+#define RX_DMA_D0_CMD_DMA_EOP BIT(8)
+#define RX_DMA_D0_CMD_DMA_RT BIT(9) /* always 1 */
+#define RX_DMA_D0_CMD_DMA_IT BIT(10) /* interrupt */
+
+/* Error field */
+#define RX_DMA_ERROR_FCS BIT(0)
+#define RX_DMA_ERROR_MIC BIT(1)
+#define RX_DMA_ERROR_KEY BIT(2) /* Key missing */
+#define RX_DMA_ERROR_REPLAY BIT(3)
+#define RX_DMA_ERROR_L3_ERR BIT(4)
+#define RX_DMA_ERROR_L4_ERR BIT(5)
/* Status field */
-#define RX_DMA_STATUS_DU BIT(0)
-#define RX_DMA_STATUS_ERROR BIT(2)
-
+#define RX_DMA_STATUS_DU BIT(0)
+#define RX_DMA_STATUS_EOP BIT(1)
+#define RX_DMA_STATUS_ERROR BIT(2)
+#define RX_DMA_STATUS_MI BIT(3) /* MAC Interrupt is asserted */
#define RX_DMA_STATUS_L3I BIT(4)
#define RX_DMA_STATUS_L4I BIT(5)
#define RX_DMA_STATUS_PHY_INFO BIT(6)
+#define RX_DMA_STATUS_FFM BIT(7) /* EtherType Flex Filter Match */
struct vring_rx_dma {
u32 d0;
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 4310972c9e16..275355d46a36 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -21,6 +21,7 @@
#include <linux/wireless.h>
#include <net/cfg80211.h>
#include <linux/timex.h>
+#include <linux/types.h>
#include "wil_platform.h"
extern bool no_fw_recovery;
@@ -29,10 +30,11 @@ extern unsigned short rx_ring_overflow_thrsh;
extern int agg_wsize;
extern u32 vring_idle_trsh;
extern bool rx_align_2;
+extern bool debug_fw;
#define WIL_NAME "wil6210"
#define WIL_FW_NAME "wil6210.fw" /* code */
-#define WIL_FW2_NAME "wil6210.board" /* board & radio parameters */
+#define WIL_FW2_NAME "wil6210.brd" /* board & radio parameters */
#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
@@ -279,7 +281,7 @@ struct fw_map {
};
/* array size should be in sync with actual definition in the wmi.c */
-extern const struct fw_map fw_mapping[7];
+extern const struct fw_map fw_mapping[8];
/**
* mk_cidxtid - construct @cidxtid field
@@ -396,6 +398,7 @@ struct vring {
* Additional data for Tx Vring
*/
struct vring_tx_data {
+ bool dot1x_open;
int enabled;
cycles_t idle, last_idle, begin;
u8 agg_wsize; /* agreed aggregation window, 0 - no agg */
@@ -461,6 +464,7 @@ enum wil_sta_status {
};
#define WIL_STA_TID_NUM (16)
+#define WIL_MCS_MAX (12) /* Maximum MCS supported */
struct wil_net_stats {
unsigned long rx_packets;
@@ -470,6 +474,7 @@ struct wil_net_stats {
unsigned long tx_errors;
unsigned long rx_dropped;
u16 last_mcs_rx;
+ u64 rx_per_mcs[WIL_MCS_MAX + 1];
};
/**
@@ -484,7 +489,6 @@ struct wil_sta_info {
u8 addr[ETH_ALEN];
enum wil_sta_status status;
struct wil_net_stats stats;
- bool data_port_open; /* can send any data, not only EAPOL */
/* Rx BACK */
struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM];
spinlock_t tid_rx_lock; /* guarding tid_rx array */
@@ -526,6 +530,17 @@ struct wil_probe_client_req {
u8 cid;
};
+struct pmc_ctx {
+ /* alloc, free, and read operations must own the lock */
+ struct mutex lock;
+ struct vring_tx_desc *pring_va;
+ dma_addr_t pring_pa;
+ struct desc_alloc_info *descriptors;
+ int last_cmd_status;
+ int num_descriptors;
+ int descriptor_size;
+};
+
struct wil6210_priv {
struct pci_dev *pdev;
int n_msi;
@@ -610,6 +625,8 @@ struct wil6210_priv {
void *platform_handle;
struct wil_platform_ops platform_ops;
+
+ struct pmc_ctx pmc;
};
#define wil_to_wiphy(i) (i->wdev->wiphy)
@@ -669,7 +686,7 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
size_t count);
-void *wil_if_alloc(struct device *dev, void __iomem *csr);
+void *wil_if_alloc(struct device *dev);
void wil_if_free(struct wil6210_priv *wil);
int wil_if_add(struct wil6210_priv *wil);
void wil_if_remove(struct wil6210_priv *wil);
@@ -701,9 +718,10 @@ int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid);
int wmi_set_channel(struct wil6210_priv *wil, int channel);
int wmi_get_channel(struct wil6210_priv *wil, int *channel);
int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
- const void *mac_addr);
+ const void *mac_addr, int key_usage);
int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
- const void *mac_addr, int key_len, const void *key);
+ const void *mac_addr, int key_len, const void *key,
+ int key_usage);
int wmi_echo(struct wil6210_priv *wil);
int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
@@ -746,7 +764,8 @@ struct wireless_dev *wil_cfg80211_init(struct device *dev);
void wil_wdev_free(struct wil6210_priv *wil);
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
-int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan);
+int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
+ u8 chan, u8 hidden_ssid);
int wmi_pcp_stop(struct wil6210_priv *wil);
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
u16 reason_code, bool from_event);
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c
index 976a071ba74e..de15f1422fe9 100644
--- a/drivers/net/wireless/ath/wil6210/wil_platform.c
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.c
@@ -17,6 +17,15 @@
#include "linux/device.h"
#include "wil_platform.h"
+int __init wil_platform_modinit(void)
+{
+ return 0;
+}
+
+void wil_platform_modexit(void)
+{
+}
+
/**
* wil_platform_init() - wil6210 platform module init
*
@@ -26,10 +35,11 @@
*/
void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops)
{
- void *handle = NULL;
+ void *handle = ops; /* to return some non-NULL for 'void' impl. */
if (!ops) {
- dev_err(dev, "Invalid parameter. Cannot init platform module\n");
+ dev_err(dev,
+ "Invalid parameter. Cannot init platform module\n");
return NULL;
}
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h
index 158c73b049a9..d7fa19b7886d 100644
--- a/drivers/net/wireless/ath/wil6210/wil_platform.h
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.h
@@ -31,4 +31,7 @@ struct wil_platform_ops {
void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops);
+int __init wil_platform_modinit(void);
+void wil_platform_modexit(void);
+
#endif /* __WIL_PLATFORM_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 9fe2085be2c5..c759759afbb2 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -85,6 +85,7 @@ const struct fw_map fw_mapping[] = {
{0x880000, 0x88a000, 0x880000, "rgf"}, /* various RGF 40k */
{0x88a000, 0x88b000, 0x88a000, "AGC_tbl"}, /* AGC table 4k */
{0x88b000, 0x88c000, 0x88b000, "rgf_ext"}, /* Pcie_ext_rgf 4k */
+ {0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext"}, /* mac_ext_rgf 512b */
{0x8c0000, 0x949000, 0x8c0000, "upper"}, /* upper area 548k */
/*
* 920000..930000 ucode code RAM
@@ -543,55 +544,22 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
}
}
-static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid, u16 wsize)
+static void wmi_evt_vring_en(struct wil6210_priv *wil, int id, void *d, int len)
{
- struct vring_tx_data *t;
- int i;
+ struct wmi_vring_en_event *evt = d;
+ u8 vri = evt->vring_index;
- for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
- if (cid != wil->vring2cid_tid[i][0])
- continue;
- t = &wil->vring_tx_data[i];
- if (!t->enabled)
- continue;
+ wil_dbg_wmi(wil, "Enable vring %d\n", vri);
- wil_addba_tx_request(wil, i, wsize);
- }
-}
-
-static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
-{
- struct wmi_data_port_open_event *evt = d;
- u8 cid = evt->cid;
-
- wil_dbg_wmi(wil, "Link UP for CID %d\n", cid);
-
- if (cid >= ARRAY_SIZE(wil->sta)) {
- wil_err(wil, "Link UP for invalid CID %d\n", cid);
+ if (vri >= ARRAY_SIZE(wil->vring_tx)) {
+ wil_err(wil, "Enable for invalid vring %d\n", vri);
return;
}
-
- wil->sta[cid].data_port_open = true;
- if (agg_wsize >= 0)
- wil_addba_tx_cid(wil, cid, agg_wsize);
-}
-
-static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len)
-{
- struct net_device *ndev = wil_to_ndev(wil);
- struct wmi_wbe_link_down_event *evt = d;
- u8 cid = evt->cid;
-
- wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n",
- cid, le32_to_cpu(evt->reason));
-
- if (cid >= ARRAY_SIZE(wil->sta)) {
- wil_err(wil, "Link DOWN for invalid CID %d\n", cid);
+ wil->vring_tx_data[vri].dot1x_open = true;
+ if (vri == wil->bcast_vring) /* no BA for bcast */
return;
- }
-
- wil->sta[cid].data_port_open = false;
- netif_carrier_off(ndev);
+ if (agg_wsize >= 0)
+ wil_addba_tx_request(wil, vri, agg_wsize);
}
static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
@@ -695,11 +663,10 @@ static const struct {
{WMI_CONNECT_EVENTID, wmi_evt_connect},
{WMI_DISCONNECT_EVENTID, wmi_evt_disconnect},
{WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx},
- {WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_linkup},
- {WMI_WBE_LINKDOWN_EVENTID, wmi_evt_linkdown},
{WMI_BA_STATUS_EVENTID, wmi_evt_ba_status},
{WMI_RCP_ADDBA_REQ_EVENTID, wmi_evt_addba_rx_req},
{WMI_DELBA_EVENTID, wmi_evt_delba},
+ {WMI_VRING_EN_EVENTID, wmi_evt_vring_en},
};
/*
@@ -844,7 +811,7 @@ int wmi_echo(struct wil6210_priv *wil)
};
return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd),
- WMI_ECHO_RSP_EVENTID, NULL, 0, 20);
+ WMI_ECHO_RSP_EVENTID, NULL, 0, 50);
}
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
@@ -858,7 +825,8 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
}
-int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
+int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
+ u8 chan, u8 hidden_ssid)
{
int rc;
@@ -868,6 +836,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
.disable_sec_offload = 1,
.channel = chan - 1,
.pcp_max_assoc_sta = max_assoc_sta,
+ .hidden_ssid = hidden_ssid,
};
struct {
struct wil6210_mbox_hdr_wmi wmi;
@@ -985,7 +954,7 @@ int wmi_p2p_cfg(struct wil6210_priv *wil, int channel)
}
int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
- const void *mac_addr)
+ const void *mac_addr, int key_usage)
{
struct wmi_delete_cipher_key_cmd cmd = {
.key_index = key_index,
@@ -998,11 +967,12 @@ int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
}
int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
- const void *mac_addr, int key_len, const void *key)
+ const void *mac_addr, int key_len, const void *key,
+ int key_usage)
{
struct wmi_add_cipher_key_cmd cmd = {
.key_index = key_index,
- .key_usage = WMI_KEY_USE_PAIRWISE,
+ .key_usage = key_usage,
.key_len = key_len,
};
@@ -1238,7 +1208,8 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-");
rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, &cmd, sizeof(cmd),
- WMI_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply), 100);
+ WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply),
+ 100);
if (rc)
return rc;
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index b29055315350..6e90e78f1554 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
* Copyright (c) 2006-2012 Wilocity .
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -253,8 +253,8 @@ struct wmi_set_passphrase_cmd {
*/
enum wmi_key_usage {
WMI_KEY_USE_PAIRWISE = 0,
- WMI_KEY_USE_GROUP = 1,
- WMI_KEY_USE_TX = 2, /* default Tx Key - Static WEP only */
+ WMI_KEY_USE_RX_GROUP = 1,
+ WMI_KEY_USE_TX_GROUP = 2,
};
struct wmi_add_cipher_key_cmd {
@@ -495,10 +495,18 @@ struct wmi_power_mgmt_cfg_cmd {
/*
* WMI_PCP_START_CMDID
*/
+
+enum wmi_hidden_ssid {
+ WMI_HIDDEN_SSID_DISABLED = 0,
+ WMI_HIDDEN_SSID_SEND_EMPTY = 1,
+ WMI_HIDDEN_SSID_CLEAR = 2,
+};
+
struct wmi_pcp_start_cmd {
__le16 bcon_interval;
u8 pcp_max_assoc_sta;
- u8 reserved0[9];
+ u8 hidden_ssid;
+ u8 reserved0[8];
u8 network_type;
u8 channel;
u8 disable_sec_offload;
@@ -836,6 +844,21 @@ struct wmi_temp_sense_cmd {
} __packed;
/*
+ * WMI_PMC_CMDID
+ */
+enum wmi_pmc_op_e {
+ WMI_PMC_ALLOCATE = 0,
+ WMI_PMC_RELEASE = 1,
+};
+
+struct wmi_pmc_cmd {
+ u8 op; /* enum wmi_pmc_cmd_op_type */
+ u8 reserved;
+ __le16 ring_size;
+ __le64 mem_base;
+} __packed;
+
+/*
* WMI Events
*/
@@ -870,7 +893,7 @@ enum wmi_event_id {
WMI_VRING_CFG_DONE_EVENTID = 0x1821,
WMI_BA_STATUS_EVENTID = 0x1823,
WMI_RCP_ADDBA_REQ_EVENTID = 0x1824,
- WMI_ADDBA_RESP_SENT_EVENTID = 0x1825,
+ WMI_RCP_ADDBA_RESP_SENT_EVENTID = 0x1825,
WMI_DELBA_EVENTID = 0x1826,
WMI_GET_SSID_EVENTID = 0x1828,
WMI_GET_PCP_CHANNEL_EVENTID = 0x182a,
@@ -882,7 +905,7 @@ enum wmi_event_id {
WMI_WRITE_MAC_TXQ_EVENTID = 0x1833,
WMI_WRITE_MAC_XQ_FIELD_EVENTID = 0x1834,
- WMI_BEAFORMING_MGMT_DONE_EVENTID = 0x1836,
+ WMI_BEAMFORMING_MGMT_DONE_EVENTID = 0x1836,
WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837,
WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839,
WMI_RS_MGMT_DONE_EVENTID = 0x1852,
@@ -894,11 +917,12 @@ enum wmi_event_id {
/* Performance monitoring events */
WMI_DATA_PORT_OPEN_EVENTID = 0x1860,
- WMI_WBE_LINKDOWN_EVENTID = 0x1861,
+ WMI_WBE_LINK_DOWN_EVENTID = 0x1861,
WMI_BF_CTRL_DONE_EVENTID = 0x1862,
WMI_NOTIFY_REQ_DONE_EVENTID = 0x1863,
WMI_GET_STATUS_DONE_EVENTID = 0x1864,
+ WMI_VRING_EN_EVENTID = 0x1865,
WMI_UNIT_TEST_EVENTID = 0x1900,
WMI_FLASH_READ_DONE_EVENTID = 0x1902,
@@ -1147,7 +1171,7 @@ struct wmi_vring_cfg_done_event {
} __packed;
/*
- * WMI_ADDBA_RESP_SENT_EVENTID
+ * WMI_RCP_ADDBA_RESP_SENT_EVENTID
*/
struct wmi_rcp_addba_resp_sent_event {
u8 cidxtid;
@@ -1179,7 +1203,7 @@ struct wmi_cfg_rx_chain_done_event {
} __packed;
/*
- * WMI_WBE_LINKDOWN_EVENTID
+ * WMI_WBE_LINK_DOWN_EVENTID
*/
enum wmi_wbe_link_down_event_reason {
WMI_WBE_REASON_USER_REQUEST = 0,
@@ -1202,6 +1226,14 @@ struct wmi_data_port_open_event {
} __packed;
/*
+ * WMI_VRING_EN_EVENTID
+ */
+struct wmi_vring_en_event {
+ u8 vring_index;
+ u8 reserved[3];
+} __packed;
+
+/*
* WMI_GET_PCP_CHANNEL_EVENTID
*/
struct wmi_get_pcp_channel_event {
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index b2f9521fe551..28490702124a 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -3131,8 +3131,6 @@ static void b43_adjust_opmode(struct b43_wldev *dev)
ctl |= B43_MACCTL_KEEP_BAD;
if (wl->filter_flags & FIF_PLCPFAIL)
ctl |= B43_MACCTL_KEEP_BADPLCP;
- if (wl->filter_flags & FIF_PROMISC_IN_BSS)
- ctl |= B43_MACCTL_PROMISC;
if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
ctl |= B43_MACCTL_BEACPROMISC;
@@ -4310,16 +4308,14 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw,
goto out_unlock;
}
- *fflags &= FIF_PROMISC_IN_BSS |
- FIF_ALLMULTI |
+ *fflags &= FIF_ALLMULTI |
FIF_FCSFAIL |
FIF_PLCPFAIL |
FIF_CONTROL |
FIF_OTHER_BSS |
FIF_BCN_PRBRESP_PROMISC;
- changed &= FIF_PROMISC_IN_BSS |
- FIF_ALLMULTI |
+ changed &= FIF_ALLMULTI |
FIF_FCSFAIL |
FIF_PLCPFAIL |
FIF_CONTROL |
@@ -5365,6 +5361,10 @@ static void b43_supported_bands(struct b43_wldev *dev, bool *have_2ghz_phy,
*have_5ghz_phy = true;
return;
case 0x4321: /* BCM4306 */
+ /* There are 14e4:4321 PCI devs with 2.4 GHz BCM4321 (N-PHY) */
+ if (dev->phy.type != B43_PHYTYPE_G)
+ break;
+ /* fall through */
case 0x4313: /* BCM4311 */
case 0x431a: /* BCM4318 */
case 0x432a: /* BCM4321 */
@@ -5609,8 +5609,8 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
wl = hw_to_b43_wl(hw);
/* fill hw info */
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_DBM;
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index c77b7f59505c..afc1fb3e38df 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2055,8 +2055,6 @@ static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev)
ctl |= B43legacy_MACCTL_KEEP_BAD;
if (wl->filter_flags & FIF_PLCPFAIL)
ctl |= B43legacy_MACCTL_KEEP_BADPLCP;
- if (wl->filter_flags & FIF_PROMISC_IN_BSS)
- ctl |= B43legacy_MACCTL_PROMISC;
if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
ctl |= B43legacy_MACCTL_BEACPROMISC;
@@ -2922,16 +2920,14 @@ static void b43legacy_op_configure_filter(struct ieee80211_hw *hw,
}
spin_lock_irqsave(&wl->irq_lock, flags);
- *fflags &= FIF_PROMISC_IN_BSS |
- FIF_ALLMULTI |
+ *fflags &= FIF_ALLMULTI |
FIF_FCSFAIL |
FIF_PLCPFAIL |
FIF_CONTROL |
FIF_OTHER_BSS |
FIF_BCN_PRBRESP_PROMISC;
- changed &= FIF_PROMISC_IN_BSS |
- FIF_ALLMULTI |
+ changed &= FIF_ALLMULTI |
FIF_FCSFAIL |
FIF_PLCPFAIL |
FIF_CONTROL |
@@ -3836,8 +3832,9 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
}
/* fill hw info */
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_DBM;
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index 9b508bd3b839..410a6645d316 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -33,6 +33,7 @@
#include <linux/suspend.h>
#include <linux/errno.h>
#include <linux/module.h>
+#include <linux/acpi.h>
#include <net/cfg80211.h>
#include <defs.h>
@@ -987,6 +988,7 @@ static void brcmf_sdiod_freezer_detach(struct brcmf_sdio_dev *sdiodev)
static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
{
+ sdiodev->state = BRCMF_SDIOD_DOWN;
if (sdiodev->bus) {
brcmf_sdio_remove(sdiodev->bus);
sdiodev->bus = NULL;
@@ -1011,6 +1013,14 @@ static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
return 0;
}
+static void brcmf_sdiod_host_fixup(struct mmc_host *host)
+{
+ /* runtime-pm powers off the device */
+ pm_runtime_forbid(host->parent);
+ /* avoid removal detection upon resume */
+ host->caps |= MMC_CAP_NONREMOVABLE;
+}
+
static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
{
struct sdio_func *func;
@@ -1076,7 +1086,7 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
ret = -ENODEV;
goto out;
}
- pm_runtime_forbid(host->parent);
+ brcmf_sdiod_host_fixup(host);
out:
if (ret)
brcmf_sdiod_remove(sdiodev);
@@ -1108,12 +1118,25 @@ MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata;
+static void brcmf_sdiod_acpi_set_power_manageable(struct device *dev,
+ int val)
+{
+#if IS_ENABLED(CONFIG_ACPI)
+ struct acpi_device *adev;
+
+ adev = ACPI_COMPANION(dev);
+ if (adev)
+ adev->flags.power_manageable = 0;
+#endif
+}
+
static int brcmf_ops_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
int err;
struct brcmf_sdio_dev *sdiodev;
struct brcmf_bus *bus_if;
+ struct device *dev;
brcmf_dbg(SDIO, "Enter\n");
brcmf_dbg(SDIO, "Class=%x\n", func->class);
@@ -1121,6 +1144,10 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
brcmf_dbg(SDIO, "Function#: %d\n", func->num);
+ dev = &func->dev;
+ /* prohibit ACPI power management for this device */
+ brcmf_sdiod_acpi_set_power_manageable(dev, 0);
+
/* Consume func num 1 but dont do anything with it. */
if (func->num == 1)
return 0;
@@ -1246,15 +1273,15 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
brcmf_sdiod_freezer_on(sdiodev);
brcmf_sdio_wd_timer(sdiodev->bus, 0);
+ sdio_flags = MMC_PM_KEEP_POWER;
if (sdiodev->wowl_enabled) {
- sdio_flags = MMC_PM_KEEP_POWER;
if (sdiodev->pdata->oob_irq_supported)
enable_irq_wake(sdiodev->pdata->oob_irq_nr);
else
- sdio_flags = MMC_PM_WAKE_SDIO_IRQ;
- if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags))
- brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
+ sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
}
+ if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags))
+ brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
return 0;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
index 8a15ebbce4a3..d86d1f1f1c91 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
@@ -52,8 +52,6 @@
#define BRCMF_PNO_SCAN_COMPLETE 1
#define BRCMF_PNO_SCAN_INCOMPLETE 0
-#define BRCMF_IFACE_MAX_CNT 3
-
#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
#define WPA_OUI_TYPE 1
#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
@@ -129,13 +127,47 @@ static struct ieee80211_rate __wl_rates[] = {
RATETAB_ENT(BRCM_RATE_54M, 0),
};
-#define wl_a_rates (__wl_rates + 4)
-#define wl_a_rates_size 8
#define wl_g_rates (__wl_rates + 0)
-#define wl_g_rates_size 12
+#define wl_g_rates_size ARRAY_SIZE(__wl_rates)
+#define wl_a_rates (__wl_rates + 4)
+#define wl_a_rates_size (wl_g_rates_size - 4)
+
+#define CHAN2G(_channel, _freq) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_channel), \
+ .flags = IEEE80211_CHAN_DISABLED, \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+#define CHAN5G(_channel) { \
+ .band = IEEE80211_BAND_5GHZ, \
+ .center_freq = 5000 + (5 * (_channel)), \
+ .hw_value = (_channel), \
+ .flags = IEEE80211_CHAN_DISABLED, \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+static struct ieee80211_channel __wl_2ghz_channels[] = {
+ CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
+ CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
+ CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
+ CHAN2G(13, 2472), CHAN2G(14, 2484)
+};
+
+static struct ieee80211_channel __wl_5ghz_channels[] = {
+ CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
+ CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
+ CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
+ CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
+ CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
+ CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
+};
/* Band templates duplicated per wiphy. The channel info
- * is filled in after querying the device.
+ * above is added to the band during setup.
*/
static const struct ieee80211_supported_band __wl_band_2ghz = {
.band = IEEE80211_BAND_2GHZ,
@@ -143,7 +175,7 @@ static const struct ieee80211_supported_band __wl_band_2ghz = {
.n_bitrates = wl_g_rates_size,
};
-static const struct ieee80211_supported_band __wl_band_5ghz_a = {
+static const struct ieee80211_supported_band __wl_band_5ghz = {
.band = IEEE80211_BAND_5GHZ,
.bitrates = wl_a_rates,
.n_bitrates = wl_a_rates_size,
@@ -1262,7 +1294,7 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
}
clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
- GFP_KERNEL);
+ true, GFP_KERNEL);
}
clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
@@ -1928,7 +1960,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
- cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
+ cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
scbval.val = cpu_to_le32(reason_code);
@@ -2364,27 +2396,80 @@ brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
brcmf_err("set wsec error (%d)\n", err);
}
+static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
+{
+ struct nl80211_sta_flag_update *sfu;
+
+ brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
+ si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
+ sfu = &si->sta_flags;
+ sfu->mask = BIT(NL80211_STA_FLAG_WME) |
+ BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+ BIT(NL80211_STA_FLAG_ASSOCIATED) |
+ BIT(NL80211_STA_FLAG_AUTHORIZED);
+ if (fw_sta_flags & BRCMF_STA_WME)
+ sfu->set |= BIT(NL80211_STA_FLAG_WME);
+ if (fw_sta_flags & BRCMF_STA_AUTHE)
+ sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
+ if (fw_sta_flags & BRCMF_STA_ASSOC)
+ sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
+ if (fw_sta_flags & BRCMF_STA_AUTHO)
+ sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
+}
+
+static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
+{
+ struct {
+ __le32 len;
+ struct brcmf_bss_info_le bss_le;
+ } *buf;
+ u16 capability;
+ int err;
+
+ buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
+ WL_BSS_INFO_MAX);
+ if (err) {
+ brcmf_err("Failed to get bss info (%d)\n", err);
+ return;
+ }
+ si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
+ si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
+ si->bss_param.dtim_period = buf->bss_le.dtim_period;
+ capability = le16_to_cpu(buf->bss_le.capability);
+ if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
+ si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
+ if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
+ if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
+}
+
static s32
brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
const u8 *mac, struct station_info *sinfo)
{
struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
- struct brcmf_scb_val_le scb_val;
- int rssi;
- s32 rate;
s32 err = 0;
- u8 *bssid = profile->bssid;
struct brcmf_sta_info_le sta_info_le;
- u32 beacon_period;
- u32 dtim_period;
+ u32 sta_flags;
+ u32 is_tdls_peer;
brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
if (!check_vif_up(ifp->vif))
return -EIO;
- if (brcmf_is_apmode(ifp->vif)) {
- memcpy(&sta_info_le, mac, ETH_ALEN);
+ memset(&sta_info_le, 0, sizeof(sta_info_le));
+ memcpy(&sta_info_le, mac, ETH_ALEN);
+ err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
+ &sta_info_le,
+ sizeof(sta_info_le));
+ is_tdls_peer = !err;
+ if (err) {
err = brcmf_fil_iovar_data_get(ifp, "sta_info",
&sta_info_le,
sizeof(sta_info_le));
@@ -2392,73 +2477,48 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
brcmf_err("GET STA INFO failed, %d\n", err);
goto done;
}
- sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
- sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
- if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
- sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
- sinfo->connected_time = le32_to_cpu(sta_info_le.in);
- }
- brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
- sinfo->inactive_time, sinfo->connected_time);
- } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) {
- if (memcmp(mac, bssid, ETH_ALEN)) {
- brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
- mac, bssid);
- err = -ENOENT;
- goto done;
- }
- /* Report the current tx rate */
- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
- if (err) {
- brcmf_err("Could not get rate (%d)\n", err);
- goto done;
- } else {
+ }
+ brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
+ sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
+ sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
+ sta_flags = le32_to_cpu(sta_info_le.flags);
+ brcmf_convert_sta_flags(sta_flags, sinfo);
+ sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+ if (is_tdls_peer)
+ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+ else
+ sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
+ if (sta_flags & BRCMF_STA_ASSOC) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
+ sinfo->connected_time = le32_to_cpu(sta_info_le.in);
+ brcmf_fill_bss_param(ifp, sinfo);
+ }
+ if (sta_flags & BRCMF_STA_SCBSTATS) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
+ sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
+ sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
+ sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
+ sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
+ sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
+ if (sinfo->tx_packets) {
sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
- sinfo->txrate.legacy = rate * 5;
- brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
+ sinfo->txrate.legacy = le32_to_cpu(sta_info_le.tx_rate);
+ sinfo->txrate.legacy /= 100;
}
-
- if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
- &ifp->vif->sme_state)) {
- memset(&scb_val, 0, sizeof(scb_val));
- err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
- &scb_val, sizeof(scb_val));
- if (err) {
- brcmf_err("Could not get rssi (%d)\n", err);
- goto done;
- } else {
- rssi = le32_to_cpu(scb_val.val);
- sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
- sinfo->signal = rssi;
- brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
- }
- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD,
- &beacon_period);
- if (err) {
- brcmf_err("Could not get beacon period (%d)\n",
- err);
- goto done;
- } else {
- sinfo->bss_param.beacon_interval =
- beacon_period;
- brcmf_dbg(CONN, "Beacon peroid %d\n",
- beacon_period);
- }
- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD,
- &dtim_period);
- if (err) {
- brcmf_err("Could not get DTIM period (%d)\n",
- err);
- goto done;
- } else {
- sinfo->bss_param.dtim_period = dtim_period;
- brcmf_dbg(CONN, "DTIM peroid %d\n",
- dtim_period);
- }
- sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
+ if (sinfo->rx_packets) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
+ sinfo->rxrate.legacy = le32_to_cpu(sta_info_le.rx_rate);
+ sinfo->rxrate.legacy /= 100;
}
- } else
- err = -EPERM;
+ if (le16_to_cpu(sta_info_le.ver) >= 4) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
+ sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
+ sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
+ }
+ }
done:
brcmf_dbg(TRACE, "Exit\n");
return err;
@@ -5253,40 +5313,6 @@ dongle_scantime_out:
return err;
}
-/* Filter the list of channels received from firmware counting only
- * the 20MHz channels. The wiphy band data only needs those which get
- * flagged to indicate if they can take part in higher bandwidth.
- */
-static void brcmf_count_20mhz_channels(struct brcmf_cfg80211_info *cfg,
- struct brcmf_chanspec_list *chlist,
- u32 chcnt[])
-{
- u32 total = le32_to_cpu(chlist->count);
- struct brcmu_chan ch;
- int i;
-
- for (i = 0; i < total; i++) {
- ch.chspec = (u16)le32_to_cpu(chlist->element[i]);
- cfg->d11inf.decchspec(&ch);
-
- /* Firmware gives a ordered list. We skip non-20MHz
- * channels is 2G. For 5G we can abort upon reaching
- * a non-20MHz channel in the list.
- */
- if (ch.bw != BRCMU_CHAN_BW_20) {
- if (ch.band == BRCMU_CHAN_BAND_5G)
- break;
- else
- continue;
- }
-
- if (ch.band == BRCMU_CHAN_BAND_2G)
- chcnt[0] += 1;
- else if (ch.band == BRCMU_CHAN_BAND_5G)
- chcnt[1] += 1;
- }
-}
-
static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
struct brcmu_chan *ch)
{
@@ -5322,7 +5348,6 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
u32 i, j;
u32 total;
u32 chaninfo;
- u32 chcnt[2] = { 0, 0 };
u32 index;
pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
@@ -5339,42 +5364,15 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
goto fail_pbuf;
}
- brcmf_count_20mhz_channels(cfg, list, chcnt);
wiphy = cfg_to_wiphy(cfg);
- if (chcnt[0]) {
- band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
- GFP_KERNEL);
- if (band == NULL) {
- err = -ENOMEM;
- goto fail_pbuf;
- }
- band->channels = kcalloc(chcnt[0], sizeof(*channel),
- GFP_KERNEL);
- if (band->channels == NULL) {
- kfree(band);
- err = -ENOMEM;
- goto fail_pbuf;
- }
- band->n_channels = 0;
- wiphy->bands[IEEE80211_BAND_2GHZ] = band;
- }
- if (chcnt[1]) {
- band = kmemdup(&__wl_band_5ghz_a, sizeof(__wl_band_5ghz_a),
- GFP_KERNEL);
- if (band == NULL) {
- err = -ENOMEM;
- goto fail_band2g;
- }
- band->channels = kcalloc(chcnt[1], sizeof(*channel),
- GFP_KERNEL);
- if (band->channels == NULL) {
- kfree(band);
- err = -ENOMEM;
- goto fail_band2g;
- }
- band->n_channels = 0;
- wiphy->bands[IEEE80211_BAND_5GHZ] = band;
- }
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ if (band)
+ for (i = 0; i < band->n_channels; i++)
+ band->channels[i].flags = IEEE80211_CHAN_DISABLED;
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ if (band)
+ for (i = 0; i < band->n_channels; i++)
+ band->channels[i].flags = IEEE80211_CHAN_DISABLED;
total = le32_to_cpu(list->count);
for (i = 0; i < total; i++) {
@@ -5389,6 +5387,8 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
continue;
}
+ if (!band)
+ continue;
if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
ch.bw == BRCMU_CHAN_BW_40)
continue;
@@ -5416,9 +5416,9 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
} else if (ch.bw == BRCMU_CHAN_BW_40) {
brcmf_update_bw40_channel_flag(&channel[index], &ch);
} else {
- /* disable other bandwidths for now as mentioned
- * order assure they are enabled for subsequent
- * chanspecs.
+ /* enable the channel and disable other bandwidths
+ * for now as mentioned order assure they are enabled
+ * for subsequent chanspecs.
*/
channel[index].flags = IEEE80211_CHAN_NO_HT40 |
IEEE80211_CHAN_NO_80MHZ;
@@ -5437,16 +5437,8 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
IEEE80211_CHAN_NO_IR;
}
}
- if (index == band->n_channels)
- band->n_channels++;
}
- kfree(pbuf);
- return 0;
-fail_band2g:
- kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
- kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
- wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
fail_pbuf:
kfree(pbuf);
return err;
@@ -5674,53 +5666,6 @@ static int brcmf_setup_wiphybands(struct wiphy *wiphy)
return 0;
}
-static const struct ieee80211_iface_limit brcmf_iface_limits_mbss[] = {
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC)
- },
- {
- .max = 4,
- .types = BIT(NL80211_IFTYPE_AP)
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO)
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
- }
-};
-
-static const struct ieee80211_iface_limit brcmf_iface_limits_sbss[] = {
- {
- .max = 2,
- .types = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_AP)
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO)
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
- }
-};
-static struct ieee80211_iface_combination brcmf_iface_combos[] = {
- {
- .max_interfaces = BRCMF_IFACE_MAX_CNT,
- .num_different_channels = 1,
- .n_limits = ARRAY_SIZE(brcmf_iface_limits_sbss),
- .limits = brcmf_iface_limits_sbss,
- }
-};
-
static const struct ieee80211_txrx_stypes
brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
[NL80211_IFTYPE_STATION] = {
@@ -5750,6 +5695,67 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
}
};
+static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
+{
+ struct ieee80211_iface_combination *combo = NULL;
+ struct ieee80211_iface_limit *limits = NULL;
+ int i = 0, max_iface_cnt;
+
+ combo = kzalloc(sizeof(*combo), GFP_KERNEL);
+ if (!combo)
+ goto err;
+
+ limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL);
+ if (!limits)
+ goto err;
+
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP);
+
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
+ combo->num_different_channels = 2;
+ else
+ combo->num_different_channels = 1;
+
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
+ limits[i].max = 1;
+ limits[i++].types = BIT(NL80211_IFTYPE_STATION);
+ limits[i].max = 4;
+ limits[i++].types = BIT(NL80211_IFTYPE_AP);
+ max_iface_cnt = 5;
+ } else {
+ limits[i].max = 2;
+ limits[i++].types = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP);
+ max_iface_cnt = 2;
+ }
+
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P)) {
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_DEVICE);
+ limits[i].max = 1;
+ limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO);
+ limits[i].max = 1;
+ limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
+ max_iface_cnt += 2;
+ }
+ combo->max_interfaces = max_iface_cnt;
+ combo->limits = limits;
+ combo->n_limits = i;
+
+ wiphy->iface_combinations = combo;
+ wiphy->n_iface_combinations = 1;
+ return 0;
+
+err:
+ kfree(limits);
+ kfree(combo);
+ return -ENOMEM;
+}
+
static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
{
/* scheduled scan settings */
@@ -5779,28 +5785,19 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy)
static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
{
- struct ieee80211_iface_combination ifc_combo;
+ struct ieee80211_supported_band *band;
+ __le32 bandlist[3];
+ u32 n_bands;
+ int err, i;
+
wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
- wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO) |
- BIT(NL80211_IFTYPE_P2P_DEVICE);
- /* need VSDB firmware feature for concurrent channels */
- ifc_combo = brcmf_iface_combos[0];
- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
- ifc_combo.num_different_channels = 2;
- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
- ifc_combo.n_limits = ARRAY_SIZE(brcmf_iface_limits_mbss),
- ifc_combo.limits = brcmf_iface_limits_mbss;
- }
- wiphy->iface_combinations = kmemdup(&ifc_combo,
- sizeof(ifc_combo),
- GFP_KERNEL);
- wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
+
+ err = brcmf_setup_ifmodes(wiphy, ifp);
+ if (err)
+ return err;
+
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wiphy->cipher_suites = __wl_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
@@ -5812,7 +5809,8 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
wiphy->mgmt_stypes = brcmf_txrx_stypes;
wiphy->max_remain_on_channel_duration = 5000;
- brcmf_wiphy_pno_params(wiphy);
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
+ brcmf_wiphy_pno_params(wiphy);
/* vendor commands/events support */
wiphy->vendor_commands = brcmf_vendor_cmds;
@@ -5821,7 +5819,52 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
brcmf_wiphy_wowl_params(wiphy);
- return brcmf_setup_wiphybands(wiphy);
+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
+ sizeof(bandlist));
+ if (err) {
+ brcmf_err("could not obtain band info: err=%d\n", err);
+ return err;
+ }
+ /* first entry in bandlist is number of bands */
+ n_bands = le32_to_cpu(bandlist[0]);
+ for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
+ if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
+ band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
+ GFP_KERNEL);
+ if (!band)
+ return -ENOMEM;
+
+ band->channels = kmemdup(&__wl_2ghz_channels,
+ sizeof(__wl_2ghz_channels),
+ GFP_KERNEL);
+ if (!band->channels) {
+ kfree(band);
+ return -ENOMEM;
+ }
+
+ band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
+ wiphy->bands[IEEE80211_BAND_2GHZ] = band;
+ }
+ if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
+ band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
+ GFP_KERNEL);
+ if (!band)
+ return -ENOMEM;
+
+ band->channels = kmemdup(&__wl_5ghz_channels,
+ sizeof(__wl_5ghz_channels),
+ GFP_KERNEL);
+ if (!band->channels) {
+ kfree(band);
+ return -ENOMEM;
+ }
+
+ band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
+ wiphy->bands[IEEE80211_BAND_5GHZ] = band;
+ }
+ }
+ err = brcmf_setup_wiphybands(wiphy);
+ return err;
}
static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
@@ -6007,11 +6050,20 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
memset(&ccreq, 0, sizeof(ccreq));
ccreq.rev = cpu_to_le32(-1);
memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2));
- brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
+ if (brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq))) {
+ brcmf_err("firmware rejected country setting\n");
+ return;
+ }
+ brcmf_setup_wiphybands(wiphy);
}
static void brcmf_free_wiphy(struct wiphy *wiphy)
{
+ if (!wiphy)
+ return;
+
+ if (wiphy->iface_combinations)
+ kfree(wiphy->iface_combinations->limits);
kfree(wiphy->iface_combinations);
if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
@@ -6047,6 +6099,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
brcmf_err("Could not allocate wiphy device\n");
return NULL;
}
+ memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
set_wiphy_dev(wiphy, busdev);
cfg = wiphy_priv(wiphy);
@@ -6154,10 +6207,8 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
if (!cfg)
return;
- WARN_ON(!list_empty(&cfg->vif_list));
- wiphy_unregister(cfg->wiphy);
brcmf_btcoex_detach(cfg);
- brcmf_p2p_detach(&cfg->p2p);
+ wiphy_unregister(cfg->wiphy);
wl_deinit_priv(cfg);
brcmf_free_wiphy(cfg->wiphy);
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
index ab2fac8b2760..288f8314f208 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
@@ -649,6 +649,7 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci)
case BRCM_CC_43567_CHIP_ID:
case BRCM_CC_43569_CHIP_ID:
case BRCM_CC_43570_CHIP_ID:
+ case BRCM_CC_4358_CHIP_ID:
case BRCM_CC_43602_CHIP_ID:
return 0x180000;
default:
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/commonring.c b/drivers/net/wireless/brcm80211/brcmfmac/commonring.c
index 77656c711bed..7b0e52195a85 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/commonring.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.c
@@ -22,17 +22,6 @@
#include "core.h"
#include "commonring.h"
-
-/* dma flushing needs implementation for mips and arm platforms. Should
- * be put in util. Note, this is not real flushing. It is virtual non
- * cached memory. Only write buffers should have to be drained. Though
- * this may be different depending on platform......
- * SEE ALSO msgbuf.c
- */
-#define brcmf_dma_flush(addr, len)
-#define brcmf_dma_invalidate_cache(addr, len)
-
-
void brcmf_commonring_register_cb(struct brcmf_commonring *commonring,
int (*cr_ring_bell)(void *ctx),
int (*cr_update_rptr)(void *ctx),
@@ -206,14 +195,9 @@ int brcmf_commonring_write_complete(struct brcmf_commonring *commonring)
address = commonring->buf_addr;
address += (commonring->f_ptr * commonring->item_len);
if (commonring->f_ptr > commonring->w_ptr) {
- brcmf_dma_flush(address,
- (commonring->depth - commonring->f_ptr) *
- commonring->item_len);
address = commonring->buf_addr;
commonring->f_ptr = 0;
}
- brcmf_dma_flush(address, (commonring->w_ptr - commonring->f_ptr) *
- commonring->item_len);
commonring->f_ptr = commonring->w_ptr;
@@ -239,8 +223,6 @@ void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring,
void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,
u16 *n_items)
{
- void *ret_addr;
-
if (commonring->cr_update_wptr)
commonring->cr_update_wptr(commonring->cr_ctx);
@@ -251,21 +233,18 @@ void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,
if (*n_items == 0)
return NULL;
- ret_addr = commonring->buf_addr +
- (commonring->r_ptr * commonring->item_len);
-
- commonring->r_ptr += *n_items;
- if (commonring->r_ptr == commonring->depth)
- commonring->r_ptr = 0;
-
- brcmf_dma_invalidate_cache(ret_addr, *n_ items * commonring->item_len);
-
- return ret_addr;
+ return commonring->buf_addr +
+ (commonring->r_ptr * commonring->item_len);
}
-int brcmf_commonring_read_complete(struct brcmf_commonring *commonring)
+int brcmf_commonring_read_complete(struct brcmf_commonring *commonring,
+ u16 n_items)
{
+ commonring->r_ptr += n_items;
+ if (commonring->r_ptr == commonring->depth)
+ commonring->r_ptr = 0;
+
if (commonring->cr_write_rptr)
return commonring->cr_write_rptr(commonring->cr_ctx);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
index 3d404016a92e..b85033611c8d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
@@ -62,7 +62,8 @@ void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring,
u16 n_items);
void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,
u16 *n_items);
-int brcmf_commonring_read_complete(struct brcmf_commonring *commonring);
+int brcmf_commonring_read_complete(struct brcmf_commonring *commonring,
+ u16 n_items);
#define brcmf_commonring_n_items(commonring) (commonring->depth)
#define brcmf_commonring_len_item(commonring) (commonring->item_len)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c
index f8f47dcfa886..fe9d3fbf5fe2 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -867,8 +867,6 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
}
/* unregister will take care of freeing it */
unregister_netdev(ifp->ndev);
- } else {
- kfree(ifp);
}
}
@@ -1100,6 +1098,8 @@ void brcmf_detach(struct device *dev)
/* stop firmware event handling */
brcmf_fweh_detach(drvr);
+ if (drvr->config)
+ brcmf_p2p_detach(&drvr->config->p2p);
brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/debug.c b/drivers/net/wireless/brcm80211/brcmfmac/debug.c
index 9b473d50b005..2d6d00553858 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/debug.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.c
@@ -41,15 +41,6 @@ void brcmf_debugfs_exit(void)
root_folder = NULL;
}
-static int brcmf_debugfs_chipinfo_read(struct seq_file *seq, void *data)
-{
- struct brcmf_bus *bus = dev_get_drvdata(seq->private);
-
- seq_printf(seq, "chip: %x(%u) rev %u\n",
- bus->chip, bus->chip, bus->chiprev);
- return 0;
-}
-
int brcmf_debugfs_attach(struct brcmf_pub *drvr)
{
struct device *dev = drvr->bus_if->dev;
@@ -58,7 +49,6 @@ int brcmf_debugfs_attach(struct brcmf_pub *drvr)
return -ENODEV;
drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
- brcmf_debugfs_add_entry(drvr, "chipinfo", brcmf_debugfs_chipinfo_read);
return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);
}
@@ -74,44 +64,12 @@ struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr)
return drvr->dbgfs_dir;
}
-struct brcmf_debugfs_entry {
- int (*read)(struct seq_file *seq, void *data);
- struct brcmf_pub *drvr;
-};
-
-static int brcmf_debugfs_entry_open(struct inode *inode, struct file *f)
-{
- struct brcmf_debugfs_entry *entry = inode->i_private;
-
- return single_open(f, entry->read, entry->drvr->bus_if->dev);
-}
-
-static const struct file_operations brcmf_debugfs_def_ops = {
- .owner = THIS_MODULE,
- .open = brcmf_debugfs_entry_open,
- .release = single_release,
- .read = seq_read,
- .llseek = seq_lseek
-};
-
int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
int (*read_fn)(struct seq_file *seq, void *data))
{
- struct dentry *dentry = drvr->dbgfs_dir;
- struct brcmf_debugfs_entry *entry;
-
- if (IS_ERR_OR_NULL(dentry))
- return -ENOENT;
-
- entry = devm_kzalloc(drvr->bus_if->dev, sizeof(*entry), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- entry->read = read_fn;
- entry->drvr = drvr;
-
- dentry = debugfs_create_file(fn, S_IRUGO, dentry, entry,
- &brcmf_debugfs_def_ops);
+ struct dentry *e;
- return PTR_ERR_OR_ZERO(dentry);
+ e = debugfs_create_devm_seqfile(drvr->bus_if->dev, fn,
+ drvr->dbgfs_dir, read_fn);
+ return PTR_ERR_OR_ZERO(e);
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
index 7748a1ccf14f..1e94e94e01dc 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
@@ -124,10 +124,12 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
struct brcmf_if *ifp = drvr->iflist[0];
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
+ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn");
if (drvr->bus_if->wowl_supported)
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID)
brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
+ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_P2P, "p2p");
/* set chip related quirks */
switch (drvr->bus_if->chip) {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/brcm80211/brcmfmac/feature.h
index f5832e077bb7..6b381f799f22 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.h
@@ -19,12 +19,18 @@
/*
* Features:
*
+ * MBSS: multiple BSSID support (eg. guest network in AP mode).
* MCHAN: multi-channel for concurrent P2P.
+ * PNO: preferred network offload.
+ * WOWL: Wake-On-WLAN.
+ * P2P: peer-to-peer
*/
#define BRCMF_FEAT_LIST \
BRCMF_FEAT_DEF(MBSS) \
BRCMF_FEAT_DEF(MCHAN) \
- BRCMF_FEAT_DEF(WOWL)
+ BRCMF_FEAT_DEF(PNO) \
+ BRCMF_FEAT_DEF(WOWL) \
+ BRCMF_FEAT_DEF(P2P)
/*
* Quirks:
*
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
index 9cb99152ad17..743f16b6a072 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
@@ -23,6 +23,10 @@
#include "debug.h"
#include "firmware.h"
+#define BRCMF_FW_MAX_NVRAM_SIZE 64000
+#define BRCMF_FW_NVRAM_DEVPATH_LEN 19 /* devpath0=pcie/1/4/ */
+#define BRCMF_FW_NVRAM_PCIEDEV_LEN 10 /* pcie/1/4/ + \0 */
+
char brcmf_firmware_path[BRCMF_FW_PATH_LEN];
module_param_string(firmware_path, brcmf_firmware_path,
BRCMF_FW_PATH_LEN, 0440);
@@ -39,25 +43,35 @@ enum nvram_parser_state {
* struct nvram_parser - internal info for parser.
*
* @state: current parser state.
- * @fwnv: input buffer being parsed.
+ * @data: input buffer being parsed.
* @nvram: output buffer with parse result.
* @nvram_len: lenght of parse result.
* @line: current line.
* @column: current column in line.
* @pos: byte offset in input buffer.
* @entry: start position of key,value entry.
+ * @multi_dev_v1: detect pcie multi device v1 (compressed).
+ * @multi_dev_v2: detect pcie multi device v2.
*/
struct nvram_parser {
enum nvram_parser_state state;
- const struct firmware *fwnv;
+ const u8 *data;
u8 *nvram;
u32 nvram_len;
u32 line;
u32 column;
u32 pos;
u32 entry;
+ bool multi_dev_v1;
+ bool multi_dev_v2;
};
+/**
+ * is_nvram_char() - check if char is a valid one for NVRAM entry
+ *
+ * It accepts all printable ASCII chars except for '#' which opens a comment.
+ * Please note that ' ' (space) while accepted is not a valid key name char.
+ */
static bool is_nvram_char(char c)
{
/* comment marker excluded */
@@ -65,7 +79,7 @@ static bool is_nvram_char(char c)
return false;
/* key and value may have any other readable character */
- return (c > 0x20 && c < 0x7f);
+ return (c >= 0x20 && c < 0x7f);
}
static bool is_whitespace(char c)
@@ -77,7 +91,7 @@ static enum nvram_parser_state brcmf_nvram_handle_idle(struct nvram_parser *nvp)
{
char c;
- c = nvp->fwnv->data[nvp->pos];
+ c = nvp->data[nvp->pos];
if (c == '\n')
return COMMENT;
if (is_whitespace(c))
@@ -101,14 +115,18 @@ static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp)
enum nvram_parser_state st = nvp->state;
char c;
- c = nvp->fwnv->data[nvp->pos];
+ c = nvp->data[nvp->pos];
if (c == '=') {
/* ignore RAW1 by treating as comment */
- if (strncmp(&nvp->fwnv->data[nvp->entry], "RAW1", 4) == 0)
+ if (strncmp(&nvp->data[nvp->entry], "RAW1", 4) == 0)
st = COMMENT;
else
st = VALUE;
- } else if (!is_nvram_char(c)) {
+ if (strncmp(&nvp->data[nvp->entry], "devpath", 7) == 0)
+ nvp->multi_dev_v1 = true;
+ if (strncmp(&nvp->data[nvp->entry], "pcie/", 5) == 0)
+ nvp->multi_dev_v2 = true;
+ } else if (!is_nvram_char(c) || c == ' ') {
brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n",
nvp->line, nvp->column);
return COMMENT;
@@ -127,12 +145,14 @@ brcmf_nvram_handle_value(struct nvram_parser *nvp)
char *ekv;
u32 cplen;
- c = nvp->fwnv->data[nvp->pos];
+ c = nvp->data[nvp->pos];
if (!is_nvram_char(c)) {
/* key,value pair complete */
- ekv = (u8 *)&nvp->fwnv->data[nvp->pos];
- skv = (u8 *)&nvp->fwnv->data[nvp->entry];
+ ekv = (u8 *)&nvp->data[nvp->pos];
+ skv = (u8 *)&nvp->data[nvp->entry];
cplen = ekv - skv;
+ if (nvp->nvram_len + cplen + 1 >= BRCMF_FW_MAX_NVRAM_SIZE)
+ return END;
/* copy to output buffer */
memcpy(&nvp->nvram[nvp->nvram_len], skv, cplen);
nvp->nvram_len += cplen;
@@ -148,17 +168,20 @@ brcmf_nvram_handle_value(struct nvram_parser *nvp)
static enum nvram_parser_state
brcmf_nvram_handle_comment(struct nvram_parser *nvp)
{
- char *eol, *sol;
-
- sol = (char *)&nvp->fwnv->data[nvp->pos];
- eol = strchr(sol, '\n');
- if (eol == NULL)
- return END;
+ char *eoc, *sol;
+
+ sol = (char *)&nvp->data[nvp->pos];
+ eoc = strchr(sol, '\n');
+ if (!eoc) {
+ eoc = strchr(sol, '\0');
+ if (!eoc)
+ return END;
+ }
/* eat all moving to next line */
nvp->line++;
nvp->column = 1;
- nvp->pos += (eol - sol) + 1;
+ nvp->pos += (eoc - sol) + 1;
return IDLE;
}
@@ -178,12 +201,20 @@ static enum nvram_parser_state
};
static int brcmf_init_nvram_parser(struct nvram_parser *nvp,
- const struct firmware *nv)
+ const u8 *data, size_t data_len)
{
+ size_t size;
+
memset(nvp, 0, sizeof(*nvp));
- nvp->fwnv = nv;
+ nvp->data = data;
+ /* Limit size to MAX_NVRAM_SIZE, some files contain lot of comment */
+ if (data_len > BRCMF_FW_MAX_NVRAM_SIZE)
+ size = BRCMF_FW_MAX_NVRAM_SIZE;
+ else
+ size = data_len;
/* Alloc for extra 0 byte + roundup by 4 + length field */
- nvp->nvram = kzalloc(nv->size + 1 + 3 + sizeof(u32), GFP_KERNEL);
+ size += 1 + 3 + sizeof(u32);
+ nvp->nvram = kzalloc(size, GFP_KERNEL);
if (!nvp->nvram)
return -ENOMEM;
@@ -192,26 +223,171 @@ static int brcmf_init_nvram_parser(struct nvram_parser *nvp,
return 0;
}
+/* brcmf_fw_strip_multi_v1 :Some nvram files contain settings for multiple
+ * devices. Strip it down for one device, use domain_nr/bus_nr to determine
+ * which data is to be returned. v1 is the version where nvram is stored
+ * compressed and "devpath" maps to index for valid entries.
+ */
+static void brcmf_fw_strip_multi_v1(struct nvram_parser *nvp, u16 domain_nr,
+ u16 bus_nr)
+{
+ /* Device path with a leading '=' key-value separator */
+ char pci_path[] = "=pci/?/?";
+ size_t pci_len;
+ char pcie_path[] = "=pcie/?/?";
+ size_t pcie_len;
+
+ u32 i, j;
+ bool found;
+ u8 *nvram;
+ u8 id;
+
+ nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL);
+ if (!nvram)
+ goto fail;
+
+ /* min length: devpath0=pcie/1/4/ + 0:x=y */
+ if (nvp->nvram_len < BRCMF_FW_NVRAM_DEVPATH_LEN + 6)
+ goto fail;
+
+ /* First search for the devpathX and see if it is the configuration
+ * for domain_nr/bus_nr. Search complete nvp
+ */
+ snprintf(pci_path, sizeof(pci_path), "=pci/%d/%d", domain_nr,
+ bus_nr);
+ pci_len = strlen(pci_path);
+ snprintf(pcie_path, sizeof(pcie_path), "=pcie/%d/%d", domain_nr,
+ bus_nr);
+ pcie_len = strlen(pcie_path);
+ found = false;
+ i = 0;
+ while (i < nvp->nvram_len - BRCMF_FW_NVRAM_DEVPATH_LEN) {
+ /* Format: devpathX=pcie/Y/Z/
+ * Y = domain_nr, Z = bus_nr, X = virtual ID
+ */
+ if (strncmp(&nvp->nvram[i], "devpath", 7) == 0 &&
+ (!strncmp(&nvp->nvram[i + 8], pci_path, pci_len) ||
+ !strncmp(&nvp->nvram[i + 8], pcie_path, pcie_len))) {
+ id = nvp->nvram[i + 7] - '0';
+ found = true;
+ break;
+ }
+ while (nvp->nvram[i] != 0)
+ i++;
+ i++;
+ }
+ if (!found)
+ goto fail;
+
+ /* Now copy all valid entries, release old nvram and assign new one */
+ i = 0;
+ j = 0;
+ while (i < nvp->nvram_len) {
+ if ((nvp->nvram[i] - '0' == id) && (nvp->nvram[i + 1] == ':')) {
+ i += 2;
+ while (nvp->nvram[i] != 0) {
+ nvram[j] = nvp->nvram[i];
+ i++;
+ j++;
+ }
+ nvram[j] = 0;
+ j++;
+ }
+ while (nvp->nvram[i] != 0)
+ i++;
+ i++;
+ }
+ kfree(nvp->nvram);
+ nvp->nvram = nvram;
+ nvp->nvram_len = j;
+ return;
+
+fail:
+ kfree(nvram);
+ nvp->nvram_len = 0;
+}
+
+/* brcmf_fw_strip_multi_v2 :Some nvram files contain settings for multiple
+ * devices. Strip it down for one device, use domain_nr/bus_nr to determine
+ * which data is to be returned. v2 is the version where nvram is stored
+ * uncompressed, all relevant valid entries are identified by
+ * pcie/domain_nr/bus_nr:
+ */
+static void brcmf_fw_strip_multi_v2(struct nvram_parser *nvp, u16 domain_nr,
+ u16 bus_nr)
+{
+ char prefix[BRCMF_FW_NVRAM_PCIEDEV_LEN];
+ size_t len;
+ u32 i, j;
+ u8 *nvram;
+
+ nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL);
+ if (!nvram)
+ goto fail;
+
+ /* Copy all valid entries, release old nvram and assign new one.
+ * Valid entries are of type pcie/X/Y/ where X = domain_nr and
+ * Y = bus_nr.
+ */
+ snprintf(prefix, sizeof(prefix), "pcie/%d/%d/", domain_nr, bus_nr);
+ len = strlen(prefix);
+ i = 0;
+ j = 0;
+ while (i < nvp->nvram_len - len) {
+ if (strncmp(&nvp->nvram[i], prefix, len) == 0) {
+ i += len;
+ while (nvp->nvram[i] != 0) {
+ nvram[j] = nvp->nvram[i];
+ i++;
+ j++;
+ }
+ nvram[j] = 0;
+ j++;
+ }
+ while (nvp->nvram[i] != 0)
+ i++;
+ i++;
+ }
+ kfree(nvp->nvram);
+ nvp->nvram = nvram;
+ nvp->nvram_len = j;
+ return;
+fail:
+ kfree(nvram);
+ nvp->nvram_len = 0;
+}
+
/* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil
* and ending in a NUL. Removes carriage returns, empty lines, comment lines,
* and converts newlines to NULs. Shortens buffer as needed and pads with NULs.
* End of buffer is completed with token identifying length of buffer.
*/
-static void *brcmf_fw_nvram_strip(const struct firmware *nv, u32 *new_length)
+static void *brcmf_fw_nvram_strip(const u8 *data, size_t data_len,
+ u32 *new_length, u16 domain_nr, u16 bus_nr)
{
struct nvram_parser nvp;
u32 pad;
u32 token;
__le32 token_le;
- if (brcmf_init_nvram_parser(&nvp, nv) < 0)
+ if (brcmf_init_nvram_parser(&nvp, data, data_len) < 0)
return NULL;
- while (nvp.pos < nv->size) {
+ while (nvp.pos < data_len) {
nvp.state = nv_parser_states[nvp.state](&nvp);
if (nvp.state == END)
break;
}
+ if (nvp.multi_dev_v1)
+ brcmf_fw_strip_multi_v1(&nvp, domain_nr, bus_nr);
+ else if (nvp.multi_dev_v2)
+ brcmf_fw_strip_multi_v2(&nvp, domain_nr, bus_nr);
+
+ if (nvp.nvram_len == 0) {
+ kfree(nvp.nvram);
+ return NULL;
+ }
+
pad = nvp.nvram_len;
*new_length = roundup(nvp.nvram_len + 1, 4);
while (pad != *new_length) {
@@ -239,6 +415,8 @@ struct brcmf_fw {
u16 flags;
const struct firmware *code;
const char *nvram_name;
+ u16 domain_nr;
+ u16 bus_nr;
void (*done)(struct device *dev, const struct firmware *fw,
void *nvram_image, u32 nvram_len);
};
@@ -254,7 +432,8 @@ static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
goto fail;
if (fw) {
- nvram = brcmf_fw_nvram_strip(fw, &nvram_length);
+ nvram = brcmf_fw_nvram_strip(fw->data, fw->size, &nvram_length,
+ fwctx->domain_nr, fwctx->bus_nr);
release_firmware(fw);
if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
goto fail;
@@ -309,11 +488,12 @@ fail:
kfree(fwctx);
}
-int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
- const char *code, const char *nvram,
- void (*fw_cb)(struct device *dev,
- const struct firmware *fw,
- void *nvram_image, u32 nvram_len))
+int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
+ const char *code, const char *nvram,
+ void (*fw_cb)(struct device *dev,
+ const struct firmware *fw,
+ void *nvram_image, u32 nvram_len),
+ u16 domain_nr, u16 bus_nr)
{
struct brcmf_fw *fwctx;
@@ -333,8 +513,21 @@ int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
fwctx->done = fw_cb;
if (flags & BRCMF_FW_REQUEST_NVRAM)
fwctx->nvram_name = nvram;
+ fwctx->domain_nr = domain_nr;
+ fwctx->bus_nr = bus_nr;
return request_firmware_nowait(THIS_MODULE, true, code, dev,
GFP_KERNEL, fwctx,
brcmf_fw_request_code_done);
}
+
+int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
+ const char *code, const char *nvram,
+ void (*fw_cb)(struct device *dev,
+ const struct firmware *fw,
+ void *nvram_image, u32 nvram_len))
+{
+ return brcmf_fw_get_firmwares_pcie(dev, flags, code, nvram, fw_cb, 0,
+ 0);
+}
+
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/brcm80211/brcmfmac/firmware.h
index 4d3482356b77..604dd48ab4e0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.h
@@ -32,6 +32,12 @@ void brcmf_fw_nvram_free(void *nvram);
* fails it will not use the callback, but call device_release_driver()
* instead which will call the driver .remove() callback.
*/
+int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
+ const char *code, const char *nvram,
+ void (*fw_cb)(struct device *dev,
+ const struct firmware *fw,
+ void *nvram_image, u32 nvram_len),
+ u16 domain_nr, u16 bus_nr);
int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
const char *code, const char *nvram,
void (*fw_cb)(struct device *dev,
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
index eb1325371d3a..59440631fec5 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
@@ -249,8 +249,8 @@ void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid)
}
-void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
- struct sk_buff *skb)
+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
+ struct sk_buff *skb)
{
struct brcmf_flowring_ring *ring;
@@ -271,6 +271,7 @@ void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
if (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)
brcmf_flowring_block(flow, flowid, false);
}
+ return skb_queue_len(&ring->skblist);
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.h b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h
index a34cd394c616..5551861a44bc 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h
@@ -64,8 +64,8 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid);
void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid);
u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid);
-void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
- struct sk_buff *skb);
+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
+ struct sk_buff *skb);
struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid);
void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
struct sk_buff *skb);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
index 374920965108..297911f38fa0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
@@ -32,7 +32,11 @@
#define BRCMF_BSS_INFO_VERSION 109 /* curr ver of brcmf_bss_info_le struct */
#define BRCMF_BSS_RSSI_ON_CHANNEL 0x0002
-#define BRCMF_STA_ASSOC 0x10 /* Associated */
+#define BRCMF_STA_WME 0x00000002 /* WMM association */
+#define BRCMF_STA_AUTHE 0x00000008 /* Authenticated */
+#define BRCMF_STA_ASSOC 0x00000010 /* Associated */
+#define BRCMF_STA_AUTHO 0x00000020 /* Authorized */
+#define BRCMF_STA_SCBSTATS 0x00004000 /* Per STA debug stats */
/* size of brcmf_scan_params not including variable length array */
#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
@@ -113,6 +117,7 @@
#define BRCMF_WOWL_MAXPATTERNSIZE 128
#define BRCMF_COUNTRY_BUF_SZ 4
+#define BRCMF_ANT_MAX 4
/* join preference types for join_pref iovar */
enum brcmf_join_pref_types {
@@ -456,25 +461,61 @@ struct brcmf_channel_info_le {
};
struct brcmf_sta_info_le {
- __le16 ver; /* version of this struct */
- __le16 len; /* length in bytes of this structure */
- __le16 cap; /* sta's advertised capabilities */
- __le32 flags; /* flags defined below */
- __le32 idle; /* time since data pkt rx'd from sta */
- u8 ea[ETH_ALEN]; /* Station address */
- __le32 count; /* # rates in this set */
- u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */
+ __le16 ver; /* version of this struct */
+ __le16 len; /* length in bytes of this structure */
+ __le16 cap; /* sta's advertised capabilities */
+ __le32 flags; /* flags defined below */
+ __le32 idle; /* time since data pkt rx'd from sta */
+ u8 ea[ETH_ALEN]; /* Station address */
+ __le32 count; /* # rates in this set */
+ u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */
/* w/hi bit set if basic */
- __le32 in; /* seconds elapsed since associated */
- __le32 listen_interval_inms; /* Min Listen interval in ms for STA */
- __le32 tx_pkts; /* # of packets transmitted */
- __le32 tx_failures; /* # of packets failed */
- __le32 rx_ucast_pkts; /* # of unicast packets received */
- __le32 rx_mcast_pkts; /* # of multicast packets received */
- __le32 tx_rate; /* Rate of last successful tx frame */
- __le32 rx_rate; /* Rate of last successful rx frame */
- __le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */
- __le32 rx_decrypt_failures; /* # of packet decrypted failed */
+ __le32 in; /* seconds elapsed since associated */
+ __le32 listen_interval_inms; /* Min Listen interval in ms for STA */
+ __le32 tx_pkts; /* # of packets transmitted */
+ __le32 tx_failures; /* # of packets failed */
+ __le32 rx_ucast_pkts; /* # of unicast packets received */
+ __le32 rx_mcast_pkts; /* # of multicast packets received */
+ __le32 tx_rate; /* Rate of last successful tx frame */
+ __le32 rx_rate; /* Rate of last successful rx frame */
+ __le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */
+ __le32 rx_decrypt_failures; /* # of packet decrypted failed */
+ __le32 tx_tot_pkts; /* # of tx pkts (ucast + mcast) */
+ __le32 rx_tot_pkts; /* # of data packets recvd (uni + mcast) */
+ __le32 tx_mcast_pkts; /* # of mcast pkts txed */
+ __le64 tx_tot_bytes; /* data bytes txed (ucast + mcast) */
+ __le64 rx_tot_bytes; /* data bytes recvd (ucast + mcast) */
+ __le64 tx_ucast_bytes; /* data bytes txed (ucast) */
+ __le64 tx_mcast_bytes; /* # data bytes txed (mcast) */
+ __le64 rx_ucast_bytes; /* data bytes recvd (ucast) */
+ __le64 rx_mcast_bytes; /* data bytes recvd (mcast) */
+ s8 rssi[BRCMF_ANT_MAX]; /* per antenna rssi */
+ s8 nf[BRCMF_ANT_MAX]; /* per antenna noise floor */
+ __le16 aid; /* association ID */
+ __le16 ht_capabilities; /* advertised ht caps */
+ __le16 vht_flags; /* converted vht flags */
+ __le32 tx_pkts_retry_cnt; /* # of frames where a retry was
+ * exhausted.
+ */
+ __le32 tx_pkts_retry_exhausted; /* # of user frames where a retry
+ * was exhausted
+ */
+ s8 rx_lastpkt_rssi[BRCMF_ANT_MAX]; /* Per antenna RSSI of last
+ * received data frame.
+ */
+ /* TX WLAN retry/failure statistics:
+ * Separated for host requested frames and locally generated frames.
+ * Include unicast frame only where the retries/failures can be counted.
+ */
+ __le32 tx_pkts_total; /* # user frames sent successfully */
+ __le32 tx_pkts_retries; /* # user frames retries */
+ __le32 tx_pkts_fw_total; /* # FW generated sent successfully */
+ __le32 tx_pkts_fw_retries; /* # retries for FW generated frames */
+ __le32 tx_pkts_fw_retry_exhausted; /* # FW generated where a retry
+ * was exhausted
+ */
+ __le32 rx_pkts_retried; /* # rx with retry bit set */
+ __le32 tx_rate_fallback; /* lowest fallback TX rate */
};
struct brcmf_chanspec_list {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index f0dda0ecd23b..5017eaa4af45 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -635,7 +635,7 @@ static int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h,
return 0;
}
-static int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
+static inline int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
u32 slot_id, struct sk_buff **pktout,
bool remove_item)
{
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
index 65efb1468988..898c3801e658 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
@@ -73,8 +73,10 @@
#define BRCMF_MSGBUF_TX_FLUSH_CNT1 32
#define BRCMF_MSGBUF_TX_FLUSH_CNT2 96
-#define BRCMF_MSGBUF_DELAY_TXWORKER_THRS 64
+#define BRCMF_MSGBUF_DELAY_TXWORKER_THRS 96
#define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS 32
+#define BRCMF_MSGBUF_UPDATE_RX_PTR_THRS 48
+
struct msgbuf_common_hdr {
u8 msgtype;
@@ -278,16 +280,6 @@ struct brcmf_msgbuf_pktids {
struct brcmf_msgbuf_pktid *array;
};
-
-/* dma flushing needs implementation for mips and arm platforms. Should
- * be put in util. Note, this is not real flushing. It is virtual non
- * cached memory. Only write buffers should have to be drained. Though
- * this may be different depending on platform......
- */
-#define brcmf_dma_flush(addr, len)
-#define brcmf_dma_invalidate_cache(addr, len)
-
-
static void brcmf_msgbuf_rxbuf_ioctlresp_post(struct brcmf_msgbuf *msgbuf);
@@ -462,7 +454,6 @@ static int brcmf_msgbuf_tx_ioctl(struct brcmf_pub *drvr, int ifidx,
memcpy(msgbuf->ioctbuf, buf, buf_len);
else
memset(msgbuf->ioctbuf, 0, buf_len);
- brcmf_dma_flush(ioctl_buf, buf_len);
err = brcmf_commonring_write_complete(commonring);
brcmf_commonring_unlock(commonring);
@@ -795,6 +786,8 @@ static int brcmf_msgbuf_txdata(struct brcmf_pub *drvr, int ifidx,
struct brcmf_flowring *flow = msgbuf->flow;
struct ethhdr *eh = (struct ethhdr *)(skb->data);
u32 flowid;
+ u32 queue_count;
+ bool force;
flowid = brcmf_flowring_lookup(flow, eh->h_dest, skb->priority, ifidx);
if (flowid == BRCMF_FLOWRING_INVALID_ID) {
@@ -802,8 +795,9 @@ static int brcmf_msgbuf_txdata(struct brcmf_pub *drvr, int ifidx,
if (flowid == BRCMF_FLOWRING_INVALID_ID)
return -ENOMEM;
}
- brcmf_flowring_enqueue(flow, flowid, skb);
- brcmf_msgbuf_schedule_txdata(msgbuf, flowid, false);
+ queue_count = brcmf_flowring_enqueue(flow, flowid, skb);
+ force = ((queue_count % BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) == 0);
+ brcmf_msgbuf_schedule_txdata(msgbuf, flowid, force);
return 0;
}
@@ -1265,19 +1259,27 @@ static void brcmf_msgbuf_process_rx(struct brcmf_msgbuf *msgbuf,
{
void *buf;
u16 count;
+ u16 processed;
again:
buf = brcmf_commonring_get_read_ptr(commonring, &count);
if (buf == NULL)
return;
+ processed = 0;
while (count) {
brcmf_msgbuf_process_msgtype(msgbuf,
buf + msgbuf->rx_dataoffset);
buf += brcmf_commonring_len_item(commonring);
+ processed++;
+ if (processed == BRCMF_MSGBUF_UPDATE_RX_PTR_THRS) {
+ brcmf_commonring_read_complete(commonring, processed);
+ processed = 0;
+ }
count--;
}
- brcmf_commonring_read_complete(commonring);
+ if (processed)
+ brcmf_commonring_read_complete(commonring, processed);
if (commonring->r_ptr == 0)
goto again;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/of.c b/drivers/net/wireless/brcm80211/brcmfmac/of.c
index c824570ddea3..03f35e0c52ca 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/of.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/of.c
@@ -39,10 +39,16 @@ void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
if (!sdiodev->pdata)
return;
+ if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
+ sdiodev->pdata->drive_strength = val;
+
+ /* make sure there are interrupts defined in the node */
+ if (!of_find_property(np, "interrupts", NULL))
+ return;
+
irq = irq_of_parse_and_map(np, 0);
if (!irq) {
brcmf_err("interrupt could not be mapped\n");
- devm_kfree(dev, sdiodev->pdata);
return;
}
irqf = irqd_get_trigger_type(irq_get_irq_data(irq));
@@ -50,7 +56,4 @@ void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
sdiodev->pdata->oob_irq_supported = true;
sdiodev->pdata->oob_irq_nr = irq;
sdiodev->pdata->oob_irq_flags = irqf;
-
- if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
- sdiodev->pdata->drive_strength = val;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
index 710fbe570eb2..a9ba775a24c1 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
#include <net/cfg80211.h>
#include <brcmu_wifi.h>
@@ -1908,105 +1909,6 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
/**
- * brcmf_p2p_attach() - attach for P2P.
- *
- * @cfg: driver private data for cfg80211 interface.
- */
-s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
-{
- struct brcmf_if *pri_ifp;
- struct brcmf_if *p2p_ifp;
- struct brcmf_cfg80211_vif *p2p_vif;
- struct brcmf_p2p_info *p2p;
- struct brcmf_pub *drvr;
- s32 bssidx;
- s32 err = 0;
-
- p2p = &cfg->p2p;
- p2p->cfg = cfg;
-
- drvr = cfg->pub;
-
- pri_ifp = drvr->iflist[0];
- p2p_ifp = drvr->iflist[1];
-
- p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;
-
- if (p2p_ifp) {
- p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE,
- false);
- if (IS_ERR(p2p_vif)) {
- brcmf_err("could not create discovery vif\n");
- err = -ENOMEM;
- goto exit;
- }
-
- p2p_vif->ifp = p2p_ifp;
- p2p_ifp->vif = p2p_vif;
- p2p_vif->wdev.netdev = p2p_ifp->ndev;
- p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev;
- SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy));
-
- p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;
-
- brcmf_p2p_generate_bss_mac(p2p, NULL);
- memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
- brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
-
- /* Initialize P2P Discovery in the firmware */
- err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
- if (err < 0) {
- brcmf_err("set p2p_disc error\n");
- brcmf_free_vif(p2p_vif);
- goto exit;
- }
- /* obtain bsscfg index for P2P discovery */
- err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
- if (err < 0) {
- brcmf_err("retrieving discover bsscfg index failed\n");
- brcmf_free_vif(p2p_vif);
- goto exit;
- }
- /* Verify that firmware uses same bssidx as driver !! */
- if (p2p_ifp->bssidx != bssidx) {
- brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",
- bssidx, p2p_ifp->bssidx);
- brcmf_free_vif(p2p_vif);
- goto exit;
- }
-
- init_completion(&p2p->send_af_done);
- INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler);
- init_completion(&p2p->afx_hdl.act_frm_scan);
- init_completion(&p2p->wait_next_af);
- }
-exit:
- return err;
-}
-
-
-/**
- * brcmf_p2p_detach() - detach P2P.
- *
- * @p2p: P2P specific data.
- */
-void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
-{
- struct brcmf_cfg80211_vif *vif;
-
- vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
- if (vif != NULL) {
- brcmf_p2p_cancel_remain_on_channel(vif->ifp);
- brcmf_p2p_deinit_discovery(p2p);
- /* remove discovery interface */
- brcmf_free_vif(vif);
- p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
- }
- /* just set it all to zero */
- memset(p2p, 0, sizeof(*p2p));
-}
-
-/**
* brcmf_p2p_get_current_chanspec() - Get current operation channel.
*
* @p2p: P2P specific data.
@@ -2238,6 +2140,7 @@ static void brcmf_p2p_delete_p2pdev(struct brcmf_p2p_info *p2p,
{
cfg80211_unregister_wdev(&vif->wdev);
p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+ brcmf_remove_interface(vif->ifp->drvr, vif->ifp->bssidx);
brcmf_free_vif(vif);
}
@@ -2364,6 +2267,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
break;
case NL80211_IFTYPE_P2P_DEVICE:
+ brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+ brcmf_p2p_deinit_discovery(p2p);
brcmf_p2p_delete_p2pdev(p2p, vif);
return 0;
default:
@@ -2425,3 +2330,103 @@ void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev)
clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
mutex_unlock(&cfg->usr_sync);
}
+
+/**
+ * brcmf_p2p_attach() - attach for P2P.
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ */
+s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
+{
+ struct brcmf_if *pri_ifp;
+ struct brcmf_if *p2p_ifp;
+ struct brcmf_cfg80211_vif *p2p_vif;
+ struct brcmf_p2p_info *p2p;
+ struct brcmf_pub *drvr;
+ s32 bssidx;
+ s32 err = 0;
+
+ p2p = &cfg->p2p;
+ p2p->cfg = cfg;
+
+ drvr = cfg->pub;
+
+ pri_ifp = drvr->iflist[0];
+ p2p_ifp = drvr->iflist[1];
+
+ p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;
+
+ if (p2p_ifp) {
+ p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE,
+ false);
+ if (IS_ERR(p2p_vif)) {
+ brcmf_err("could not create discovery vif\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ p2p_vif->ifp = p2p_ifp;
+ p2p_ifp->vif = p2p_vif;
+ p2p_vif->wdev.netdev = p2p_ifp->ndev;
+ p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev;
+ SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy));
+
+ p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;
+
+ brcmf_p2p_generate_bss_mac(p2p, NULL);
+ memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
+ brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
+
+ /* Initialize P2P Discovery in the firmware */
+ err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
+ if (err < 0) {
+ brcmf_err("set p2p_disc error\n");
+ brcmf_free_vif(p2p_vif);
+ goto exit;
+ }
+ /* obtain bsscfg index for P2P discovery */
+ err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
+ if (err < 0) {
+ brcmf_err("retrieving discover bsscfg index failed\n");
+ brcmf_free_vif(p2p_vif);
+ goto exit;
+ }
+ /* Verify that firmware uses same bssidx as driver !! */
+ if (p2p_ifp->bssidx != bssidx) {
+ brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",
+ bssidx, p2p_ifp->bssidx);
+ brcmf_free_vif(p2p_vif);
+ goto exit;
+ }
+
+ init_completion(&p2p->send_af_done);
+ INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler);
+ init_completion(&p2p->afx_hdl.act_frm_scan);
+ init_completion(&p2p->wait_next_af);
+ }
+exit:
+ return err;
+}
+
+/**
+ * brcmf_p2p_detach() - detach P2P.
+ *
+ * @p2p: P2P specific data.
+ */
+void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
+{
+ struct brcmf_cfg80211_vif *vif;
+
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ if (vif != NULL) {
+ brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+ brcmf_p2p_deinit_discovery(p2p);
+ /* remove discovery interface */
+ rtnl_lock();
+ brcmf_p2p_delete_p2pdev(p2p, vif);
+ rtnl_unlock();
+ }
+ /* just set it all to zero */
+ memset(p2p, 0, sizeof(*p2p));
+}
+
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
index 1831ecd0813e..3a98c4306d1d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
@@ -51,6 +51,8 @@ enum brcmf_pcie_state {
#define BRCMF_PCIE_4356_NVRAM_NAME "brcm/brcmfmac4356-pcie.txt"
#define BRCMF_PCIE_43570_FW_NAME "brcm/brcmfmac43570-pcie.bin"
#define BRCMF_PCIE_43570_NVRAM_NAME "brcm/brcmfmac43570-pcie.txt"
+#define BRCMF_PCIE_4358_FW_NAME "brcm/brcmfmac4358-pcie.bin"
+#define BRCMF_PCIE_4358_NVRAM_NAME "brcm/brcmfmac4358-pcie.txt"
#define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */
@@ -110,10 +112,11 @@ enum brcmf_pcie_state {
BRCMF_PCIE_MB_INT_D2H3_DB0 | \
BRCMF_PCIE_MB_INT_D2H3_DB1)
-#define BRCMF_PCIE_MIN_SHARED_VERSION 4
+#define BRCMF_PCIE_MIN_SHARED_VERSION 5
#define BRCMF_PCIE_MAX_SHARED_VERSION 5
#define BRCMF_PCIE_SHARED_VERSION_MASK 0x00FF
-#define BRCMF_PCIE_SHARED_TXPUSH_SUPPORT 0x4000
+#define BRCMF_PCIE_SHARED_DMA_INDEX 0x10000
+#define BRCMF_PCIE_SHARED_DMA_2B_IDX 0x100000
#define BRCMF_PCIE_FLAGS_HTOD_SPLIT 0x4000
#define BRCMF_PCIE_FLAGS_DTOH_SPLIT 0x8000
@@ -145,6 +148,10 @@ enum brcmf_pcie_state {
#define BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET 8
#define BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET 12
#define BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET 16
+#define BRCMF_SHARED_RING_H2D_WP_HADDR_OFFSET 20
+#define BRCMF_SHARED_RING_H2D_RP_HADDR_OFFSET 28
+#define BRCMF_SHARED_RING_D2H_WP_HADDR_OFFSET 36
+#define BRCMF_SHARED_RING_D2H_RP_HADDR_OFFSET 44
#define BRCMF_SHARED_RING_TCM_MEMLOC_OFFSET 0
#define BRCMF_SHARED_RING_MAX_SUB_QUEUES 52
@@ -189,6 +196,8 @@ MODULE_FIRMWARE(BRCMF_PCIE_4356_FW_NAME);
MODULE_FIRMWARE(BRCMF_PCIE_4356_NVRAM_NAME);
MODULE_FIRMWARE(BRCMF_PCIE_43570_FW_NAME);
MODULE_FIRMWARE(BRCMF_PCIE_43570_NVRAM_NAME);
+MODULE_FIRMWARE(BRCMF_PCIE_4358_FW_NAME);
+MODULE_FIRMWARE(BRCMF_PCIE_4358_NVRAM_NAME);
struct brcmf_pcie_console {
@@ -244,6 +253,13 @@ struct brcmf_pciedev_info {
bool mbdata_completed;
bool irq_allocated;
bool wowl_enabled;
+ u8 dma_idx_sz;
+ void *idxbuf;
+ u32 idxbuf_sz;
+ dma_addr_t idxbuf_dmahandle;
+ u16 (*read_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset);
+ void (*write_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
+ u16 value);
};
struct brcmf_pcie_ringbuf {
@@ -273,15 +289,6 @@ static const u32 brcmf_ring_itemsize[BRCMF_NROF_COMMON_MSGRINGS] = {
};
-/* dma flushing needs implementation for mips and arm platforms. Should
- * be put in util. Note, this is not real flushing. It is virtual non
- * cached memory. Only write buffers should have to be drained. Though
- * this may be different depending on platform......
- */
-#define brcmf_dma_flush(addr, len)
-#define brcmf_dma_invalidate_cache(addr, len)
-
-
static u32
brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset)
{
@@ -329,6 +336,25 @@ brcmf_pcie_write_tcm16(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
}
+static u16
+brcmf_pcie_read_idx(struct brcmf_pciedev_info *devinfo, u32 mem_offset)
+{
+ u16 *address = devinfo->idxbuf + mem_offset;
+
+ return (*(address));
+}
+
+
+static void
+brcmf_pcie_write_idx(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
+ u16 value)
+{
+ u16 *address = devinfo->idxbuf + mem_offset;
+
+ *(address) = value;
+}
+
+
static u32
brcmf_pcie_read_tcm32(struct brcmf_pciedev_info *devinfo, u32 mem_offset)
{
@@ -874,7 +900,7 @@ static int brcmf_pcie_ring_mb_write_rptr(void *ctx)
brcmf_dbg(PCIE, "W r_ptr %d (%d), ring %d\n", commonring->r_ptr,
commonring->w_ptr, ring->id);
- brcmf_pcie_write_tcm16(devinfo, ring->r_idx_addr, commonring->r_ptr);
+ devinfo->write_ptr(devinfo, ring->r_idx_addr, commonring->r_ptr);
return 0;
}
@@ -892,7 +918,7 @@ static int brcmf_pcie_ring_mb_write_wptr(void *ctx)
brcmf_dbg(PCIE, "W w_ptr %d (%d), ring %d\n", commonring->w_ptr,
commonring->r_ptr, ring->id);
- brcmf_pcie_write_tcm16(devinfo, ring->w_idx_addr, commonring->w_ptr);
+ devinfo->write_ptr(devinfo, ring->w_idx_addr, commonring->w_ptr);
return 0;
}
@@ -921,7 +947,7 @@ static int brcmf_pcie_ring_mb_update_rptr(void *ctx)
if (devinfo->state != BRCMFMAC_PCIE_STATE_UP)
return -EIO;
- commonring->r_ptr = brcmf_pcie_read_tcm16(devinfo, ring->r_idx_addr);
+ commonring->r_ptr = devinfo->read_ptr(devinfo, ring->r_idx_addr);
brcmf_dbg(PCIE, "R r_ptr %d (%d), ring %d\n", commonring->r_ptr,
commonring->w_ptr, ring->id);
@@ -939,7 +965,7 @@ static int brcmf_pcie_ring_mb_update_wptr(void *ctx)
if (devinfo->state != BRCMFMAC_PCIE_STATE_UP)
return -EIO;
- commonring->w_ptr = brcmf_pcie_read_tcm16(devinfo, ring->w_idx_addr);
+ commonring->w_ptr = devinfo->read_ptr(devinfo, ring->w_idx_addr);
brcmf_dbg(PCIE, "R w_ptr %d (%d), ring %d\n", commonring->w_ptr,
commonring->r_ptr, ring->id);
@@ -1044,6 +1070,13 @@ static void brcmf_pcie_release_ringbuffers(struct brcmf_pciedev_info *devinfo)
}
kfree(devinfo->shared.flowrings);
devinfo->shared.flowrings = NULL;
+ if (devinfo->idxbuf) {
+ dma_free_coherent(&devinfo->pdev->dev,
+ devinfo->idxbuf_sz,
+ devinfo->idxbuf,
+ devinfo->idxbuf_dmahandle);
+ devinfo->idxbuf = NULL;
+ }
}
@@ -1059,19 +1092,72 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo)
u32 addr;
u32 ring_mem_ptr;
u32 i;
+ u64 address;
+ u32 bufsz;
u16 max_sub_queues;
+ u8 idx_offset;
ring_addr = devinfo->shared.ring_info_addr;
brcmf_dbg(PCIE, "Base ring addr = 0x%08x\n", ring_addr);
+ addr = ring_addr + BRCMF_SHARED_RING_MAX_SUB_QUEUES;
+ max_sub_queues = brcmf_pcie_read_tcm16(devinfo, addr);
- addr = ring_addr + BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET;
- d2h_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
- addr = ring_addr + BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET;
- d2h_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
- addr = ring_addr + BRCMF_SHARED_RING_H2D_W_IDX_PTR_OFFSET;
- h2d_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
- addr = ring_addr + BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET;
- h2d_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
+ if (devinfo->dma_idx_sz != 0) {
+ bufsz = (BRCMF_NROF_D2H_COMMON_MSGRINGS + max_sub_queues) *
+ devinfo->dma_idx_sz * 2;
+ devinfo->idxbuf = dma_alloc_coherent(&devinfo->pdev->dev, bufsz,
+ &devinfo->idxbuf_dmahandle,
+ GFP_KERNEL);
+ if (!devinfo->idxbuf)
+ devinfo->dma_idx_sz = 0;
+ }
+
+ if (devinfo->dma_idx_sz == 0) {
+ addr = ring_addr + BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET;
+ d2h_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
+ addr = ring_addr + BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET;
+ d2h_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
+ addr = ring_addr + BRCMF_SHARED_RING_H2D_W_IDX_PTR_OFFSET;
+ h2d_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
+ addr = ring_addr + BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET;
+ h2d_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
+ idx_offset = sizeof(u32);
+ devinfo->write_ptr = brcmf_pcie_write_tcm16;
+ devinfo->read_ptr = brcmf_pcie_read_tcm16;
+ brcmf_dbg(PCIE, "Using TCM indices\n");
+ } else {
+ memset(devinfo->idxbuf, 0, bufsz);
+ devinfo->idxbuf_sz = bufsz;
+ idx_offset = devinfo->dma_idx_sz;
+ devinfo->write_ptr = brcmf_pcie_write_idx;
+ devinfo->read_ptr = brcmf_pcie_read_idx;
+
+ h2d_w_idx_ptr = 0;
+ addr = ring_addr + BRCMF_SHARED_RING_H2D_WP_HADDR_OFFSET;
+ address = (u64)devinfo->idxbuf_dmahandle;
+ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff);
+ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32);
+
+ h2d_r_idx_ptr = h2d_w_idx_ptr + max_sub_queues * idx_offset;
+ addr = ring_addr + BRCMF_SHARED_RING_H2D_RP_HADDR_OFFSET;
+ address += max_sub_queues * idx_offset;
+ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff);
+ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32);
+
+ d2h_w_idx_ptr = h2d_r_idx_ptr + max_sub_queues * idx_offset;
+ addr = ring_addr + BRCMF_SHARED_RING_D2H_WP_HADDR_OFFSET;
+ address += max_sub_queues * idx_offset;
+ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff);
+ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32);
+
+ d2h_r_idx_ptr = d2h_w_idx_ptr +
+ BRCMF_NROF_D2H_COMMON_MSGRINGS * idx_offset;
+ addr = ring_addr + BRCMF_SHARED_RING_D2H_RP_HADDR_OFFSET;
+ address += BRCMF_NROF_D2H_COMMON_MSGRINGS * idx_offset;
+ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff);
+ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32);
+ brcmf_dbg(PCIE, "Using host memory indices\n");
+ }
addr = ring_addr + BRCMF_SHARED_RING_TCM_MEMLOC_OFFSET;
ring_mem_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
@@ -1085,8 +1171,8 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo)
ring->id = i;
devinfo->shared.commonrings[i] = ring;
- h2d_w_idx_ptr += sizeof(u32);
- h2d_r_idx_ptr += sizeof(u32);
+ h2d_w_idx_ptr += idx_offset;
+ h2d_r_idx_ptr += idx_offset;
ring_mem_ptr += BRCMF_RING_MEM_SZ;
}
@@ -1100,13 +1186,11 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo)
ring->id = i;
devinfo->shared.commonrings[i] = ring;
- d2h_w_idx_ptr += sizeof(u32);
- d2h_r_idx_ptr += sizeof(u32);
+ d2h_w_idx_ptr += idx_offset;
+ d2h_r_idx_ptr += idx_offset;
ring_mem_ptr += BRCMF_RING_MEM_SZ;
}
- addr = ring_addr + BRCMF_SHARED_RING_MAX_SUB_QUEUES;
- max_sub_queues = brcmf_pcie_read_tcm16(devinfo, addr);
devinfo->shared.nrof_flowrings =
max_sub_queues - BRCMF_NROF_H2D_COMMON_MSGRINGS;
rings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(*ring),
@@ -1130,15 +1214,15 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo)
ring);
ring->w_idx_addr = h2d_w_idx_ptr;
ring->r_idx_addr = h2d_r_idx_ptr;
- h2d_w_idx_ptr += sizeof(u32);
- h2d_r_idx_ptr += sizeof(u32);
+ h2d_w_idx_ptr += idx_offset;
+ h2d_r_idx_ptr += idx_offset;
}
devinfo->shared.flowrings = rings;
return 0;
fail:
- brcmf_err("Allocating commonring buffers failed\n");
+ brcmf_err("Allocating ring buffers failed\n");
brcmf_pcie_release_ringbuffers(devinfo);
return -ENOMEM;
}
@@ -1171,7 +1255,6 @@ static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo)
goto fail;
memset(devinfo->shared.scratch, 0, BRCMF_DMA_D2H_SCRATCH_BUF_LEN);
- brcmf_dma_flush(devinfo->shared.scratch, BRCMF_DMA_D2H_SCRATCH_BUF_LEN);
addr = devinfo->shared.tcm_base_address +
BRCMF_SHARED_DMA_SCRATCH_ADDR_OFFSET;
@@ -1189,7 +1272,6 @@ static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo)
goto fail;
memset(devinfo->shared.ringupd, 0, BRCMF_DMA_D2H_RINGUPD_BUF_LEN);
- brcmf_dma_flush(devinfo->shared.ringupd, BRCMF_DMA_D2H_RINGUPD_BUF_LEN);
addr = devinfo->shared.tcm_base_address +
BRCMF_SHARED_DMA_RINGUPD_ADDR_OFFSET;
@@ -1276,10 +1358,13 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
brcmf_err("Unsupported PCIE version %d\n", version);
return -EINVAL;
}
- if (shared->flags & BRCMF_PCIE_SHARED_TXPUSH_SUPPORT) {
- brcmf_err("Unsupported legacy TX mode 0x%x\n",
- shared->flags & BRCMF_PCIE_SHARED_TXPUSH_SUPPORT);
- return -EINVAL;
+
+ /* check firmware support dma indicies */
+ if (shared->flags & BRCMF_PCIE_SHARED_DMA_INDEX) {
+ if (shared->flags & BRCMF_PCIE_SHARED_DMA_2B_IDX)
+ devinfo->dma_idx_sz = sizeof(u16);
+ else
+ devinfo->dma_idx_sz = sizeof(u32);
}
addr = sharedram_addr + BRCMF_SHARED_MAX_RXBUFPOST_OFFSET;
@@ -1333,6 +1418,10 @@ static int brcmf_pcie_get_fwnames(struct brcmf_pciedev_info *devinfo)
fw_name = BRCMF_PCIE_43570_FW_NAME;
nvram_name = BRCMF_PCIE_43570_NVRAM_NAME;
break;
+ case BRCM_CC_4358_CHIP_ID:
+ fw_name = BRCMF_PCIE_4358_FW_NAME;
+ nvram_name = BRCMF_PCIE_4358_NVRAM_NAME;
+ break;
default:
brcmf_err("Unsupported chip 0x%04x\n", devinfo->ci->chip);
return -ENODEV;
@@ -1540,20 +1629,7 @@ static void brcmf_pcie_buscore_write32(void *ctx, u32 addr, u32 value)
static int brcmf_pcie_buscoreprep(void *ctx)
{
- struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx;
- int err;
-
- err = brcmf_pcie_get_resource(devinfo);
- if (err == 0) {
- /* Set CC watchdog to reset all the cores on the chip to bring
- * back dongle to a sane state.
- */
- brcmf_pcie_buscore_write32(ctx, CORE_CC_REG(SI_ENUM_BASE,
- watchdog), 4);
- msleep(100);
- }
-
- return err;
+ return brcmf_pcie_get_resource(ctx);
}
@@ -1609,7 +1685,7 @@ static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw,
bus->msgbuf->commonrings[i] =
&devinfo->shared.commonrings[i]->commonring;
- flowrings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(flowrings),
+ flowrings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(*flowrings),
GFP_KERNEL);
if (!flowrings)
goto fail;
@@ -1641,8 +1717,13 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct brcmf_pciedev_info *devinfo;
struct brcmf_pciedev *pcie_bus_dev;
struct brcmf_bus *bus;
+ u16 domain_nr;
+ u16 bus_nr;
- brcmf_dbg(PCIE, "Enter %x:%x\n", pdev->vendor, pdev->device);
+ domain_nr = pci_domain_nr(pdev->bus) + 1;
+ bus_nr = pdev->bus->number;
+ brcmf_dbg(PCIE, "Enter %x:%x (%d/%d)\n", pdev->vendor, pdev->device,
+ domain_nr, bus_nr);
ret = -ENOMEM;
devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
@@ -1691,10 +1772,10 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
goto fail_bus;
- ret = brcmf_fw_get_firmwares(bus->dev, BRCMF_FW_REQUEST_NVRAM |
- BRCMF_FW_REQ_NV_OPTIONAL,
- devinfo->fw_name, devinfo->nvram_name,
- brcmf_pcie_setup);
+ ret = brcmf_fw_get_firmwares_pcie(bus->dev, BRCMF_FW_REQUEST_NVRAM |
+ BRCMF_FW_REQ_NV_OPTIONAL,
+ devinfo->fw_name, devinfo->nvram_name,
+ brcmf_pcie_setup, domain_nr, bus_nr);
if (ret == 0)
return 0;
fail_bus:
@@ -1730,6 +1811,7 @@ brcmf_pcie_remove(struct pci_dev *pdev)
brcmf_pcie_intr_disable(devinfo);
brcmf_detach(&pdev->dev);
+ brcmf_pcie_reset_device(devinfo);
kfree(bus->bus_priv.pcie);
kfree(bus->msgbuf->flowrings);
@@ -1850,9 +1932,11 @@ static struct pci_device_id brcmf_pcie_devid_table[] = {
BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4358_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_2G_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_5G_DEVICE_ID),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_RAW_DEVICE_ID),
{ /* end: all zeroes */ }
};
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
index ab0c89833013..d36f5f3d931b 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
@@ -601,6 +601,8 @@ static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
#define BCM43241B0_NVRAM_NAME "brcm/brcmfmac43241b0-sdio.txt"
#define BCM43241B4_FIRMWARE_NAME "brcm/brcmfmac43241b4-sdio.bin"
#define BCM43241B4_NVRAM_NAME "brcm/brcmfmac43241b4-sdio.txt"
+#define BCM43241B5_FIRMWARE_NAME "brcm/brcmfmac43241b5-sdio.bin"
+#define BCM43241B5_NVRAM_NAME "brcm/brcmfmac43241b5-sdio.txt"
#define BCM4329_FIRMWARE_NAME "brcm/brcmfmac4329-sdio.bin"
#define BCM4329_NVRAM_NAME "brcm/brcmfmac4329-sdio.txt"
#define BCM4330_FIRMWARE_NAME "brcm/brcmfmac4330-sdio.bin"
@@ -628,6 +630,8 @@ MODULE_FIRMWARE(BCM43241B0_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM43241B0_NVRAM_NAME);
MODULE_FIRMWARE(BCM43241B4_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM43241B4_NVRAM_NAME);
+MODULE_FIRMWARE(BCM43241B5_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM43241B5_NVRAM_NAME);
MODULE_FIRMWARE(BCM4329_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM4329_NVRAM_NAME);
MODULE_FIRMWARE(BCM4330_FIRMWARE_NAME);
@@ -667,7 +671,8 @@ enum brcmf_firmware_type {
static const struct brcmf_firmware_names brcmf_fwname_data[] = {
{ BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43143) },
{ BRCM_CC_43241_CHIP_ID, 0x0000001F, BRCMF_FIRMWARE_NVRAM(BCM43241B0) },
- { BRCM_CC_43241_CHIP_ID, 0xFFFFFFE0, BRCMF_FIRMWARE_NVRAM(BCM43241B4) },
+ { BRCM_CC_43241_CHIP_ID, 0x00000020, BRCMF_FIRMWARE_NVRAM(BCM43241B4) },
+ { BRCM_CC_43241_CHIP_ID, 0xFFFFFFC0, BRCMF_FIRMWARE_NVRAM(BCM43241B5) },
{ BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) },
{ BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) },
{ BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) },
@@ -2815,6 +2820,8 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
struct brcmf_sdio *bus = sdiodev->bus;
brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len);
+ if (sdiodev->state != BRCMF_SDIOD_DATA)
+ return -EIO;
/* Add space for the header */
skb_push(pkt, bus->tx_hdrlen);
@@ -2943,6 +2950,8 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
int ret;
brcmf_dbg(TRACE, "Enter\n");
+ if (sdiodev->state != BRCMF_SDIOD_DATA)
+ return -EIO;
/* Send from dpc */
bus->ctrl_frame_buf = msg;
@@ -3233,6 +3242,8 @@ brcmf_sdio_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
struct brcmf_sdio *bus = sdiodev->bus;
brcmf_dbg(TRACE, "Enter\n");
+ if (sdiodev->state != BRCMF_SDIOD_DATA)
+ return -EIO;
/* Wait until control frame is available */
timeleft = brcmf_sdio_dcmd_resp_wait(bus, &bus->rxlen, &pending);
@@ -3550,10 +3561,6 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus)
return;
}
- if (bus->sdiodev->state != BRCMF_SDIOD_DATA) {
- brcmf_err("bus is down. we have nothing to do\n");
- return;
- }
/* Count the interrupt call */
bus->sdcnt.intrcount++;
if (in_interrupt())
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index 5df6aa72cc2d..daba86d881bc 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -1270,8 +1270,13 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
bus->chiprev = bus_pub->chiprev;
/* request firmware here */
- brcmf_fw_get_firmwares(dev, 0, brcmf_usb_get_fwname(devinfo), NULL,
- brcmf_usb_probe_phase2);
+ ret = brcmf_fw_get_firmwares(dev, 0, brcmf_usb_get_fwname(devinfo),
+ NULL, brcmf_usb_probe_phase2);
+ if (ret) {
+ brcmf_err("firmware request failed: %d\n", ret);
+ goto fail;
+ }
+
return 0;
fail:
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index 48135063347e..ab775a5d5b33 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -41,8 +41,7 @@
#define BRCMS_FLUSH_TIMEOUT 500 /* msec */
/* Flags we support */
-#define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | \
+#define MAC_FILTERS (FIF_ALLMULTI | \
FIF_FCSFAIL | \
FIF_CONTROL | \
FIF_OTHER_BSS | \
@@ -743,8 +742,6 @@ brcms_ops_configure_filter(struct ieee80211_hw *hw,
changed_flags &= MAC_FILTERS;
*total_flags &= MAC_FILTERS;
- if (changed_flags & FIF_PROMISC_IN_BSS)
- brcms_dbg_info(core, "FIF_PROMISC_IN_BSS\n");
if (changed_flags & FIF_ALLMULTI)
brcms_dbg_info(core, "FIF_ALLMULTI\n");
if (changed_flags & FIF_FCSFAIL)
@@ -1063,10 +1060,9 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw)
*/
static int ieee_hw_init(struct ieee80211_hw *hw)
{
- hw->flags = IEEE80211_HW_SIGNAL_DBM
- /* | IEEE80211_HW_CONNECTION_MONITOR What is this? */
- | IEEE80211_HW_REPORTS_TX_ACK_STATUS
- | IEEE80211_HW_AMPDU_AGGREGATION;
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
hw->extra_tx_headroom = brcms_c_get_header_len();
hw->queues = N_TX_QUEUES;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 369527e27689..9728be0e704b 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -3571,7 +3571,7 @@ void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags)
wlc->filter_flags = filter_flags;
- if (filter_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
+ if (filter_flags & FIF_OTHER_BSS)
promisc_bits |= MCTL_PROMISC;
if (filter_flags & FIF_BCN_PRBRESP_PROMISC)
diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
index 4efdd51af9c8..7a6daa37dc6b 100644
--- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
+++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
@@ -45,6 +45,7 @@
#define BRCM_CC_43567_CHIP_ID 43567
#define BRCM_CC_43569_CHIP_ID 43569
#define BRCM_CC_43570_CHIP_ID 43570
+#define BRCM_CC_4358_CHIP_ID 0x4358
#define BRCM_CC_43602_CHIP_ID 43602
/* USB Device IDs */
@@ -59,9 +60,11 @@
#define BRCM_PCIE_4356_DEVICE_ID 0x43ec
#define BRCM_PCIE_43567_DEVICE_ID 0x43d3
#define BRCM_PCIE_43570_DEVICE_ID 0x43d9
+#define BRCM_PCIE_4358_DEVICE_ID 0x43e9
#define BRCM_PCIE_43602_DEVICE_ID 0x43ba
#define BRCM_PCIE_43602_2G_DEVICE_ID 0x43bb
#define BRCM_PCIE_43602_5G_DEVICE_ID 0x43bc
+#define BRCM_PCIE_43602_RAW_DEVICE_ID 43602
/* brcmsmac IDs */
#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */
diff --git a/drivers/net/wireless/cw1200/main.c b/drivers/net/wireless/cw1200/main.c
index 3689dbbd10bd..0e51e27d2e3f 100644
--- a/drivers/net/wireless/cw1200/main.c
+++ b/drivers/net/wireless/cw1200/main.c
@@ -278,14 +278,14 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
else
priv->ba_tx_tid_mask = 0xff; /* Enable TX BLKACK for all TIDs */
- hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_CONNECTION_MONITOR |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
- IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC;
+ ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC);
+ ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, CONNECTION_MONITOR);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, SUPPORTS_PS);
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c
index b0f65fa09428..b86500b4418f 100644
--- a/drivers/net/wireless/cw1200/sta.c
+++ b/drivers/net/wireless/cw1200/sta.c
@@ -578,13 +578,11 @@ void cw1200_configure_filter(struct ieee80211_hw *dev,
{
struct cw1200_common *priv = dev->priv;
bool listening = !!(*total_flags &
- (FIF_PROMISC_IN_BSS |
- FIF_OTHER_BSS |
+ (FIF_OTHER_BSS |
FIF_BCN_PRBRESP_PROMISC |
FIF_PROBE_REQ));
- *total_flags &= FIF_PROMISC_IN_BSS |
- FIF_OTHER_BSS |
+ *total_flags &= FIF_OTHER_BSS |
FIF_FCSFAIL |
FIF_BCN_PRBRESP_PROMISC |
FIF_PROBE_REQ;
@@ -592,14 +590,12 @@ void cw1200_configure_filter(struct ieee80211_hw *dev,
down(&priv->scan.lock);
mutex_lock(&priv->conf_mutex);
- priv->rx_filter.promiscuous = (*total_flags & FIF_PROMISC_IN_BSS)
- ? 1 : 0;
+ priv->rx_filter.promiscuous = 0;
priv->rx_filter.bssid = (*total_flags & (FIF_OTHER_BSS |
FIF_PROBE_REQ)) ? 1 : 0;
priv->rx_filter.fcs = (*total_flags & FIF_FCSFAIL) ? 1 : 0;
priv->disable_beacon_filter = !(*total_flags &
(FIF_BCN_PRBRESP_PROMISC |
- FIF_PROMISC_IN_BSS |
FIF_PROBE_REQ));
if (priv->listening != listening) {
priv->listening = listening;
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c
index e5665804d986..7f4cb692cc57 100644
--- a/drivers/net/wireless/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/iwlegacy/3945-mac.c
@@ -3048,7 +3048,7 @@ il3945_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
D_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", changed_flags,
*total_flags);
- CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+ CHK(FIF_OTHER_BSS, RXON_FILTER_PROMISC_MSK);
CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK);
CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
@@ -3074,7 +3074,7 @@ il3945_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
* filters into the device.
*/
*total_flags &=
- FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
+ FIF_OTHER_BSS | FIF_ALLMULTI |
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
@@ -3561,8 +3561,10 @@ il3945_setup_mac(struct il_priv *il)
hw->vif_data_size = sizeof(struct il_vif_priv);
/* Tell mac80211 our characteristics */
- hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, SPECTRUM_MGMT);
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index 976f65fe9c38..44fa422f255e 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -5751,11 +5751,13 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
hw->rate_control_algorithm = "iwl-4965-rs";
/* Tell mac80211 our characteristics */
- hw->flags =
- IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
if (il->cfg->sku & IL_SKU_N)
hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS |
NL80211_FEATURE_STATIC_SMPS;
@@ -6166,7 +6168,7 @@ il4965_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
D_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", changed_flags,
*total_flags);
- CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+ CHK(FIF_OTHER_BSS, RXON_FILTER_PROMISC_MSK);
/* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
@@ -6192,7 +6194,7 @@ il4965_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
* filters into the device.
*/
*total_flags &=
- FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
+ FIF_OTHER_BSS | FIF_ALLMULTI |
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index f89f446e5c8a..aba095761ac6 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -21,6 +21,7 @@ config IWLWIFI
Intel 7260 Wi-Fi Adapter
Intel 3160 Wi-Fi Adapter
Intel 7265 Wi-Fi Adapter
+ Intel 8260 Wi-Fi Adapter
Intel 3165 Wi-Fi Adapter
@@ -54,16 +55,17 @@ config IWLDVM
tristate "Intel Wireless WiFi DVM Firmware support"
default IWLWIFI
help
- This is the driver that supports the DVM firmware which is
- used by most existing devices (with the exception of 7260
- and 3160).
+ This is the driver that supports the DVM firmware. The list
+ of the devices that use this firmware is available here:
+ https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi#firmware
config IWLMVM
tristate "Intel Wireless WiFi MVM Firmware support"
select WANT_DEV_COREDUMP
help
- This is the driver that supports the MVM firmware which is
- currently only available for 7260 and 3160 devices.
+ This is the driver that supports the MVM firmware. The list
+ of the devices that use this firmware is available here:
+ https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi#firmware
# don't call it _MODULE -- will confuse Kconfig/fixdep/...
config IWLWIFI_OPMODE_MODULAR
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 3d32f4120174..dbfc5b18bcb7 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -9,6 +9,7 @@ iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o
iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o
iwlwifi-$(CONFIG_IWLDVM) += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o
iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o iwl-8000.o
+iwlwifi-objs += iwl-trans.o
iwlwifi-objs += $(iwlwifi-m)
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 5abd62ed8cb4..7acaa266b704 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -104,15 +104,16 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
hw->rate_control_algorithm = "iwl-agn-rs";
/* Tell mac80211 our characteristics */
- hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
- IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_QUEUE_CONTROL |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_WANT_MONITOR_VIF;
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC);
+ ieee80211_hw_set(hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, QUEUE_CONTROL);
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
+ ieee80211_hw_set(hw, WANT_MONITOR_VIF);
hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE;
hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT;
@@ -135,7 +136,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
*/
if (priv->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP &&
!iwlwifi_mod_params.sw_crypto)
- hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+ ieee80211_hw_set(hw, MFP_CAPABLE);
hw->sta_data_size = sizeof(struct iwl_station_priv);
hw->vif_data_size = sizeof(struct iwl_vif_priv);
@@ -1061,7 +1062,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
changed_flags, *total_flags);
- CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+ CHK(FIF_OTHER_BSS, RXON_FILTER_PROMISC_MSK);
/* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
@@ -1088,7 +1089,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
* since we currently do not support programming multicast
* filters into the device.
*/
- *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
+ *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI |
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
@@ -1140,7 +1141,6 @@ static void iwlagn_mac_event_callback(struct ieee80211_hw *hw,
return;
IWL_DEBUG_MAC80211(priv, "enter\n");
- mutex_lock(&priv->mutex);
if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist) {
@@ -1149,13 +1149,12 @@ static void iwlagn_mac_event_callback(struct ieee80211_hw *hw,
else if (event->u.rssi.data == RSSI_EVENT_HIGH)
priv->bt_enable_pspoll = false;
- iwlagn_send_advance_bt_config(priv);
+ queue_work(priv->workqueue, &priv->bt_runtime_config);
} else {
IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
"ignoring RSSI callback\n");
}
- mutex_unlock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");
}
@@ -1343,9 +1342,9 @@ static int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
* other interfaces are added, this is safe.
*/
if (vif->type == NL80211_IFTYPE_MONITOR)
- priv->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
+ ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS);
else
- priv->hw->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
+ __clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, priv->hw->flags);
err = iwl_setup_interface(priv, ctx);
if (!err || reset)
diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c
index 74ad278116be..cc35f796d406 100644
--- a/drivers/net/wireless/iwlwifi/iwl-7000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-7000.c
@@ -69,7 +69,7 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
-#define IWL7260_UCODE_API_MAX 13
+#define IWL7260_UCODE_API_MAX 15
/* Oldest version we won't warn about */
#define IWL7260_UCODE_API_OK 12
@@ -124,6 +124,28 @@ static const struct iwl_base_params iwl7000_base_params = {
.apmg_wake_up_wa = true,
};
+static const struct iwl_tt_params iwl7000_high_temp_tt_params = {
+ .ct_kill_entry = 118,
+ .ct_kill_exit = 96,
+ .ct_kill_duration = 5,
+ .dynamic_smps_entry = 114,
+ .dynamic_smps_exit = 110,
+ .tx_protection_entry = 114,
+ .tx_protection_exit = 108,
+ .tx_backoff = {
+ {.temperature = 112, .backoff = 300},
+ {.temperature = 113, .backoff = 800},
+ {.temperature = 114, .backoff = 1500},
+ {.temperature = 115, .backoff = 3000},
+ {.temperature = 116, .backoff = 5000},
+ {.temperature = 117, .backoff = 10000},
+ },
+ .support_ct_kill = true,
+ .support_dynamic_smps = true,
+ .support_tx_protection = true,
+ .support_tx_backoff = true,
+};
+
static const struct iwl_ht_params iwl7000_ht_params = {
.stbc = true,
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
@@ -166,6 +188,7 @@ const struct iwl_cfg iwl7260_2ac_cfg_high_temp = {
.host_interrupt_operation_mode = true,
.lp_xtal_workaround = true,
.dccm_len = IWL7260_DCCM_LEN,
+ .thermal_params = &iwl7000_high_temp_tt_params,
};
const struct iwl_cfg iwl7260_2n_cfg = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c
index ce6321b7d241..72040cd0b979 100644
--- a/drivers/net/wireless/iwlwifi/iwl-8000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-8000.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -69,7 +69,7 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
-#define IWL8000_UCODE_API_MAX 13
+#define IWL8000_UCODE_API_MAX 15
/* Oldest version we won't warn about */
#define IWL8000_UCODE_API_OK 12
@@ -122,24 +122,49 @@ static const struct iwl_ht_params iwl8000_ht_params = {
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
};
-#define IWL_DEVICE_8000 \
- .ucode_api_max = IWL8000_UCODE_API_MAX, \
- .ucode_api_ok = IWL8000_UCODE_API_OK, \
- .ucode_api_min = IWL8000_UCODE_API_MIN, \
- .device_family = IWL_DEVICE_FAMILY_8000, \
- .max_inst_size = IWL60_RTC_INST_SIZE, \
- .max_data_size = IWL60_RTC_DATA_SIZE, \
- .base_params = &iwl8000_base_params, \
- .led_mode = IWL_LED_RF_STATE, \
- .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \
- .d0i3 = true, \
- .non_shared_ant = ANT_A, \
- .dccm_offset = IWL8260_DCCM_OFFSET, \
- .dccm_len = IWL8260_DCCM_LEN, \
- .dccm2_offset = IWL8260_DCCM2_OFFSET, \
- .dccm2_len = IWL8260_DCCM2_LEN, \
- .smem_offset = IWL8260_SMEM_OFFSET, \
- .smem_len = IWL8260_SMEM_LEN
+static const struct iwl_tt_params iwl8000_tt_params = {
+ .ct_kill_entry = 115,
+ .ct_kill_exit = 93,
+ .ct_kill_duration = 5,
+ .dynamic_smps_entry = 111,
+ .dynamic_smps_exit = 107,
+ .tx_protection_entry = 112,
+ .tx_protection_exit = 105,
+ .tx_backoff = {
+ {.temperature = 110, .backoff = 200},
+ {.temperature = 111, .backoff = 600},
+ {.temperature = 112, .backoff = 1200},
+ {.temperature = 113, .backoff = 2000},
+ {.temperature = 114, .backoff = 4000},
+ },
+ .support_ct_kill = true,
+ .support_dynamic_smps = true,
+ .support_tx_protection = true,
+ .support_tx_backoff = true,
+};
+
+#define IWL_DEVICE_8000 \
+ .ucode_api_max = IWL8000_UCODE_API_MAX, \
+ .ucode_api_ok = IWL8000_UCODE_API_OK, \
+ .ucode_api_min = IWL8000_UCODE_API_MIN, \
+ .device_family = IWL_DEVICE_FAMILY_8000, \
+ .max_inst_size = IWL60_RTC_INST_SIZE, \
+ .max_data_size = IWL60_RTC_DATA_SIZE, \
+ .base_params = &iwl8000_base_params, \
+ .led_mode = IWL_LED_RF_STATE, \
+ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \
+ .d0i3 = true, \
+ .non_shared_ant = ANT_A, \
+ .dccm_offset = IWL8260_DCCM_OFFSET, \
+ .dccm_len = IWL8260_DCCM_LEN, \
+ .dccm2_offset = IWL8260_DCCM2_OFFSET, \
+ .dccm2_len = IWL8260_DCCM2_LEN, \
+ .smem_offset = IWL8260_SMEM_OFFSET, \
+ .smem_len = IWL8260_SMEM_LEN, \
+ .default_nvm_file_B_step = DEFAULT_NVM_FILE_FAMILY_8000B, \
+ .default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C, \
+ .thermal_params = &iwl8000_tt_params, \
+ .apmg_not_supported = true
const struct iwl_cfg iwl8260_2n_cfg = {
.name = "Intel(R) Dual Band Wireless N 8260",
@@ -177,8 +202,6 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
.ht_params = &iwl8000_ht_params,
.nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
- .default_nvm_file_B_step = DEFAULT_NVM_FILE_FAMILY_8000B,
- .default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C,
.max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
.disable_dummy_notification = true,
.max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO,
@@ -192,8 +215,6 @@ const struct iwl_cfg iwl4165_2ac_sdio_cfg = {
.ht_params = &iwl8000_ht_params,
.nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
- .default_nvm_file_B_step = DEFAULT_NVM_FILE_FAMILY_8000B,
- .default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C,
.max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
.bt_shared_single_ant = true,
.disable_dummy_notification = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h
index 3f33f753ce2f..08c14afeb148 100644
--- a/drivers/net/wireless/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/iwlwifi/iwl-config.h
@@ -195,6 +195,49 @@ struct iwl_ht_params {
};
/*
+ * Tx-backoff threshold
+ * @temperature: The threshold in Celsius
+ * @backoff: The tx-backoff in uSec
+ */
+struct iwl_tt_tx_backoff {
+ s32 temperature;
+ u32 backoff;
+};
+
+#define TT_TX_BACKOFF_SIZE 6
+
+/**
+ * struct iwl_tt_params - thermal throttling parameters
+ * @ct_kill_entry: CT Kill entry threshold
+ * @ct_kill_exit: CT Kill exit threshold
+ * @ct_kill_duration: The time intervals (in uSec) in which the driver needs
+ * to checks whether to exit CT Kill.
+ * @dynamic_smps_entry: Dynamic SMPS entry threshold
+ * @dynamic_smps_exit: Dynamic SMPS exit threshold
+ * @tx_protection_entry: TX protection entry threshold
+ * @tx_protection_exit: TX protection exit threshold
+ * @tx_backoff: Array of thresholds for tx-backoff , in ascending order.
+ * @support_ct_kill: Support CT Kill?
+ * @support_dynamic_smps: Support dynamic SMPS?
+ * @support_tx_protection: Support tx protection?
+ * @support_tx_backoff: Support tx-backoff?
+ */
+struct iwl_tt_params {
+ s32 ct_kill_entry;
+ s32 ct_kill_exit;
+ u32 ct_kill_duration;
+ s32 dynamic_smps_entry;
+ s32 dynamic_smps_exit;
+ s32 tx_protection_entry;
+ s32 tx_protection_exit;
+ struct iwl_tt_tx_backoff tx_backoff[TT_TX_BACKOFF_SIZE];
+ bool support_ct_kill;
+ bool support_dynamic_smps;
+ bool support_tx_protection;
+ bool support_tx_backoff;
+};
+
+/*
* information on how to parse the EEPROM
*/
#define EEPROM_REG_BAND_1_CHANNELS 0x08
@@ -316,6 +359,8 @@ struct iwl_cfg {
const u32 dccm2_len;
const u32 smem_offset;
const u32 smem_len;
+ const struct iwl_tt_params *thermal_params;
+ bool apmg_not_supported;
};
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h
index 223b8752f924..948ce0802fa7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h
@@ -1,6 +1,7 @@
/******************************************************************************
*
* Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -64,19 +65,21 @@ TRACE_EVENT(iwlwifi_dev_hcmd,
TRACE_EVENT(iwlwifi_dev_rx,
TP_PROTO(const struct device *dev, const struct iwl_trans *trans,
- void *rxbuf, size_t len),
- TP_ARGS(dev, trans, rxbuf, len),
+ struct iwl_rx_packet *pkt, size_t len),
+ TP_ARGS(dev, trans, pkt, len),
TP_STRUCT__entry(
DEV_ENTRY
- __dynamic_array(u8, rxbuf, iwl_rx_trace_len(trans, rxbuf, len))
+ __field(u8, cmd)
+ __dynamic_array(u8, rxbuf, iwl_rx_trace_len(trans, pkt, len))
),
TP_fast_assign(
DEV_ASSIGN;
- memcpy(__get_dynamic_array(rxbuf), rxbuf,
- iwl_rx_trace_len(trans, rxbuf, len));
+ __entry->cmd = pkt->hdr.cmd;
+ memcpy(__get_dynamic_array(rxbuf), pkt,
+ iwl_rx_trace_len(trans, pkt, len));
),
TP_printk("[%s] RX cmd %#.2x",
- __get_str(dev), ((u8 *)__get_dynamic_array(rxbuf))[4])
+ __get_str(dev), __entry->cmd)
);
TRACE_EVENT(iwlwifi_dev_tx,
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index 7267152e7dc7..6685259927f8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -423,13 +423,19 @@ static int iwl_set_ucode_api_flags(struct iwl_drv *drv, const u8 *data,
{
const struct iwl_ucode_api *ucode_api = (void *)data;
u32 api_index = le32_to_cpu(ucode_api->api_index);
+ u32 api_flags = le32_to_cpu(ucode_api->api_flags);
+ int i;
- if (api_index >= IWL_API_ARRAY_SIZE) {
+ if (api_index >= IWL_API_MAX_BITS / 32) {
IWL_ERR(drv, "api_index larger than supported by driver\n");
- return -EINVAL;
+ /* don't return an error so we can load FW that has more bits */
+ return 0;
}
- capa->api[api_index] = le32_to_cpu(ucode_api->api_flags);
+ for (i = 0; i < 32; i++) {
+ if (api_flags & BIT(i))
+ __set_bit(i + 32 * api_index, capa->_api);
+ }
return 0;
}
@@ -439,13 +445,19 @@ static int iwl_set_ucode_capabilities(struct iwl_drv *drv, const u8 *data,
{
const struct iwl_ucode_capa *ucode_capa = (void *)data;
u32 api_index = le32_to_cpu(ucode_capa->api_index);
+ u32 api_flags = le32_to_cpu(ucode_capa->api_capa);
+ int i;
- if (api_index >= IWL_CAPABILITIES_ARRAY_SIZE) {
+ if (api_index >= IWL_CAPABILITIES_MAX_BITS / 32) {
IWL_ERR(drv, "api_index larger than supported by driver\n");
- return -EINVAL;
+ /* don't return an error so we can load FW that has more bits */
+ return 0;
}
- capa->capa[api_index] = le32_to_cpu(ucode_capa->api_capa);
+ for (i = 0; i < 32; i++) {
+ if (api_flags & BIT(i))
+ __set_bit(i + 32 * api_index, capa->_capa);
+ }
return 0;
}
@@ -1148,7 +1160,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
if (err)
goto try_again;
- if (drv->fw.ucode_capa.api[0] & IWL_UCODE_TLV_API_NEW_VERSION)
+ if (fw_has_api(&drv->fw.ucode_capa, IWL_UCODE_TLV_API_NEW_VERSION))
api_ver = drv->fw.ucode_ver;
else
api_ver = IWL_UCODE_API(drv->fw.ucode_ver);
@@ -1239,6 +1251,8 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
sizeof(struct iwl_fw_dbg_trigger_txq_timer);
trigger_tlv_sz[FW_DBG_TRIGGER_TIME_EVENT] =
sizeof(struct iwl_fw_dbg_trigger_time_event);
+ trigger_tlv_sz[FW_DBG_TRIGGER_BA] =
+ sizeof(struct iwl_fw_dbg_trigger_ba);
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++) {
if (pieces->dbg_trigger_tlv[i]) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index d45dc021cda2..d56064861a9c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -438,12 +438,6 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
#define RX_QUEUE_MASK 255
#define RX_QUEUE_SIZE_LOG 8
-/*
- * RX related structures and functions
- */
-#define RX_FREE_BUFFERS 64
-#define RX_LOW_WATERMARK 8
-
/**
* struct iwl_rb_status - reserve buffer status
* host memory mapped FH registers
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index 251bf8dc4a12..e57dbd0ef2e1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -254,6 +254,7 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data)
* detection.
* @FW_DBG_TRIGGER_TIME_EVENT: trigger log collection upon time events related
* events.
+ * @FW_DBG_TRIGGER_BA: trigger log collection upon BlockAck related events.
*/
enum iwl_fw_dbg_trigger {
FW_DBG_TRIGGER_INVALID = 0,
@@ -267,6 +268,7 @@ enum iwl_fw_dbg_trigger {
FW_DBG_TRIGGER_RSSI,
FW_DBG_TRIGGER_TXQ_TIMERS,
FW_DBG_TRIGGER_TIME_EVENT,
+ FW_DBG_TRIGGER_BA,
/* must be last */
FW_DBG_TRIGGER_MAX,
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 62db2e5e45eb..a9b5ae4ebec0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -237,6 +237,8 @@ enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30),
};
+typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t;
+
/**
* enum iwl_ucode_tlv_api - ucode api
* @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex
@@ -255,22 +257,27 @@ enum iwl_ucode_tlv_flag {
* @IWL_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params
* @IWL_UCODE_TLV_API_STATS_V10: uCode supports/uses statistics API version 10
* @IWL_UCODE_TLV_API_NEW_VERSION: new versioning format
+ * @IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY: scan APIs use 8-level priority
+ * instead of 3.
*/
enum iwl_ucode_tlv_api {
- IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3),
- IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8),
- IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = BIT(9),
- IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10),
- IWL_UCODE_TLV_API_TX_POWER_DEV = BIT(11),
- IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13),
- IWL_UCODE_TLV_API_SCD_CFG = BIT(15),
- IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = BIT(16),
- IWL_UCODE_TLV_API_ASYNC_DTM = BIT(17),
- IWL_UCODE_TLV_API_LQ_SS_PARAMS = BIT(18),
- IWL_UCODE_TLV_API_STATS_V10 = BIT(19),
- IWL_UCODE_TLV_API_NEW_VERSION = BIT(20),
+ IWL_UCODE_TLV_API_BT_COEX_SPLIT = (__force iwl_ucode_tlv_api_t)3,
+ IWL_UCODE_TLV_API_FRAGMENTED_SCAN = (__force iwl_ucode_tlv_api_t)8,
+ IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = (__force iwl_ucode_tlv_api_t)9,
+ IWL_UCODE_TLV_API_HDC_PHASE_0 = (__force iwl_ucode_tlv_api_t)10,
+ IWL_UCODE_TLV_API_TX_POWER_DEV = (__force iwl_ucode_tlv_api_t)11,
+ IWL_UCODE_TLV_API_BASIC_DWELL = (__force iwl_ucode_tlv_api_t)13,
+ IWL_UCODE_TLV_API_SCD_CFG = (__force iwl_ucode_tlv_api_t)15,
+ IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = (__force iwl_ucode_tlv_api_t)16,
+ IWL_UCODE_TLV_API_ASYNC_DTM = (__force iwl_ucode_tlv_api_t)17,
+ IWL_UCODE_TLV_API_LQ_SS_PARAMS = (__force iwl_ucode_tlv_api_t)18,
+ IWL_UCODE_TLV_API_STATS_V10 = (__force iwl_ucode_tlv_api_t)19,
+ IWL_UCODE_TLV_API_NEW_VERSION = (__force iwl_ucode_tlv_api_t)20,
+ IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY = (__force iwl_ucode_tlv_api_t)24,
};
+typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
+
/**
* enum iwl_ucode_tlv_capa - ucode capabilities
* @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3
@@ -290,6 +297,7 @@ enum iwl_ucode_tlv_api {
* which also implies support for the scheduler configuration command
* @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching
* @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command
+ * @IWL_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command
* @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics
* @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running
* @IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different
@@ -299,22 +307,23 @@ enum iwl_ucode_tlv_api {
* @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC
*/
enum iwl_ucode_tlv_capa {
- IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0),
- IWL_UCODE_TLV_CAPA_LAR_SUPPORT = BIT(1),
- IWL_UCODE_TLV_CAPA_UMAC_SCAN = BIT(2),
- IWL_UCODE_TLV_CAPA_BEAMFORMER = BIT(3),
- IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = BIT(6),
- IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = BIT(8),
- IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9),
- IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = BIT(10),
- IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = BIT(11),
- IWL_UCODE_TLV_CAPA_DQA_SUPPORT = BIT(12),
- IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = BIT(13),
- IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18),
- IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = BIT(22),
- IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = BIT(28),
- IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = BIT(29),
- IWL_UCODE_TLV_CAPA_BT_COEX_RRC = BIT(30),
+ IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = (__force iwl_ucode_tlv_capa_t)0,
+ IWL_UCODE_TLV_CAPA_LAR_SUPPORT = (__force iwl_ucode_tlv_capa_t)1,
+ IWL_UCODE_TLV_CAPA_UMAC_SCAN = (__force iwl_ucode_tlv_capa_t)2,
+ IWL_UCODE_TLV_CAPA_BEAMFORMER = (__force iwl_ucode_tlv_capa_t)3,
+ IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = (__force iwl_ucode_tlv_capa_t)6,
+ IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = (__force iwl_ucode_tlv_capa_t)8,
+ IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = (__force iwl_ucode_tlv_capa_t)9,
+ IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = (__force iwl_ucode_tlv_capa_t)10,
+ IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = (__force iwl_ucode_tlv_capa_t)11,
+ IWL_UCODE_TLV_CAPA_DQA_SUPPORT = (__force iwl_ucode_tlv_capa_t)12,
+ IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = (__force iwl_ucode_tlv_capa_t)13,
+ IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = (__force iwl_ucode_tlv_capa_t)18,
+ IWL_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT = (__force iwl_ucode_tlv_capa_t)19,
+ IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = (__force iwl_ucode_tlv_capa_t)22,
+ IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = (__force iwl_ucode_tlv_capa_t)28,
+ IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = (__force iwl_ucode_tlv_capa_t)29,
+ IWL_UCODE_TLV_CAPA_BT_COEX_RRC = (__force iwl_ucode_tlv_capa_t)30,
};
/* The default calibrate table size if not specified by firmware file */
@@ -325,13 +334,14 @@ enum iwl_ucode_tlv_capa {
/* The default max probe length if not specified by the firmware file */
#define IWL_DEFAULT_MAX_PROBE_LENGTH 200
+#define IWL_API_MAX_BITS 64
+#define IWL_CAPABILITIES_MAX_BITS 64
+
/*
* For 16.0 uCode and above, there is no differentiation between sections,
* just an offset to the HW address.
*/
#define IWL_UCODE_SECTION_MAX 12
-#define IWL_API_ARRAY_SIZE 1
-#define IWL_CAPABILITIES_ARRAY_SIZE 1
#define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC
/* uCode version contains 4 values: Major/Minor/API/Serial */
@@ -424,11 +434,13 @@ struct iwl_fw_dbg_reg_op {
* @SMEM_MODE: monitor stores the data in SMEM
* @EXTERNAL_MODE: monitor stores the data in allocated DRAM
* @MARBH_MODE: monitor stores the data in MARBH buffer
+ * @MIPI_MODE: monitor outputs the data through the MIPI interface
*/
enum iwl_fw_dbg_monitor_mode {
SMEM_MODE = 0,
EXTERNAL_MODE = 1,
MARBH_MODE = 2,
+ MIPI_MODE = 3,
};
/**
@@ -436,6 +448,7 @@ enum iwl_fw_dbg_monitor_mode {
*
* @version: version of the TLV - currently 0
* @monitor_mode: %enum iwl_fw_dbg_monitor_mode
+ * @size_power: buffer size will be 2^(size_power + 11)
* @base_reg: addr of the base addr register (PRPH)
* @end_reg: addr of the end addr register (PRPH)
* @write_ptr_reg: the addr of the reg of the write pointer
@@ -449,7 +462,8 @@ enum iwl_fw_dbg_monitor_mode {
struct iwl_fw_dbg_dest_tlv {
u8 version;
u8 monitor_mode;
- u8 reserved[2];
+ u8 size_power;
+ u8 reserved;
__le32 base_reg;
__le32 end_reg;
__le32 write_ptr_reg;
@@ -659,6 +673,33 @@ struct iwl_fw_dbg_trigger_time_event {
} __packed;
/**
+ * struct iwl_fw_dbg_trigger_ba - configures BlockAck related trigger
+ * rx_ba_start: tid bitmap to configure on what tid the trigger should occur
+ * when an Rx BlockAck session is started.
+ * rx_ba_stop: tid bitmap to configure on what tid the trigger should occur
+ * when an Rx BlockAck session is stopped.
+ * tx_ba_start: tid bitmap to configure on what tid the trigger should occur
+ * when a Tx BlockAck session is started.
+ * tx_ba_stop: tid bitmap to configure on what tid the trigger should occur
+ * when a Tx BlockAck session is stopped.
+ * rx_bar: tid bitmap to configure on what tid the trigger should occur
+ * when a BAR is received (for a Tx BlockAck session).
+ * tx_bar: tid bitmap to configure on what tid the trigger should occur
+ * when a BAR is send (for an Rx BlocAck session).
+ * frame_timeout: tid bitmap to configure on what tid the trigger should occur
+ * when a frame times out in the reodering buffer.
+ */
+struct iwl_fw_dbg_trigger_ba {
+ __le16 rx_ba_start;
+ __le16 rx_ba_stop;
+ __le16 tx_ba_start;
+ __le16 tx_ba_stop;
+ __le16 rx_bar;
+ __le16 tx_bar;
+ __le16 frame_timeout;
+} __packed;
+
+/**
* struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration.
* @id: conf id
* @usniffer: should the uSniffer image be used
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index cf75bafae51d..3e3c9d8b3c37 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -105,10 +105,24 @@ struct iwl_ucode_capabilities {
u32 n_scan_channels;
u32 standard_phy_calibration_size;
u32 flags;
- u32 api[IWL_API_ARRAY_SIZE];
- u32 capa[IWL_CAPABILITIES_ARRAY_SIZE];
+ unsigned long _api[BITS_TO_LONGS(IWL_API_MAX_BITS)];
+ unsigned long _capa[BITS_TO_LONGS(IWL_CAPABILITIES_MAX_BITS)];
};
+static inline bool
+fw_has_api(const struct iwl_ucode_capabilities *capabilities,
+ iwl_ucode_tlv_api_t api)
+{
+ return test_bit((__force long)api, capabilities->_api);
+}
+
+static inline bool
+fw_has_capa(const struct iwl_ucode_capabilities *capabilities,
+ iwl_ucode_tlv_capa_t capa)
+{
+ return test_bit((__force long)capa, capabilities->_capa);
+}
+
/* one for each uCode image (inst/data, init/runtime/wowlan) */
struct fw_desc {
const void *data; /* vmalloc'ed data */
@@ -205,6 +219,8 @@ static inline const char *get_fw_dbg_mode_string(int mode)
return "EXTERNAL_DRAM";
case MARBH_MODE:
return "MARBH";
+ case MIPI_MODE:
+ return "MIPI";
default:
return "UNKNOWN";
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
index 8e604a3931ca..80fefe7d7b8c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -249,7 +249,7 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
*/
if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
(flags & IEEE80211_CHAN_NO_IR))
- flags |= IEEE80211_CHAN_GO_CONCURRENT;
+ flags |= IEEE80211_CHAN_IR_CONCURRENT;
return flags;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 88a57e6e232f..5af1c776d2d4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -348,6 +348,9 @@ enum secure_load_status_reg {
#define MON_BUFF_WRPTR (0xa03c44)
#define MON_BUFF_CYCLE_CNT (0xa03c48)
+#define MON_DMARB_RD_CTL_ADDR (0xa03c60)
+#define MON_DMARB_RD_DATA_ADDR (0xa03c5c)
+
#define DBGC_IN_SAMPLE (0xa03c00)
/* enable the ID buf for read */
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c
new file mode 100644
index 000000000000..9f8bcefc04c5
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.c
@@ -0,0 +1,113 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2015 Intel Mobile Communications GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Intel Mobile Communications GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#include <linux/kernel.h>
+#include "iwl-trans.h"
+
+struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
+ struct device *dev,
+ const struct iwl_cfg *cfg,
+ const struct iwl_trans_ops *ops,
+ size_t dev_cmd_headroom)
+{
+ struct iwl_trans *trans;
+#ifdef CONFIG_LOCKDEP
+ static struct lock_class_key __key;
+#endif
+
+ trans = kzalloc(sizeof(*trans) + priv_size, GFP_KERNEL);
+ if (!trans)
+ return NULL;
+
+#ifdef CONFIG_LOCKDEP
+ lockdep_init_map(&trans->sync_cmd_lockdep_map, "sync_cmd_lockdep_map",
+ &__key, 0);
+#endif
+
+ trans->dev = dev;
+ trans->cfg = cfg;
+ trans->ops = ops;
+ trans->dev_cmd_headroom = dev_cmd_headroom;
+
+ snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name),
+ "iwl_cmd_pool:%s", dev_name(trans->dev));
+ trans->dev_cmd_pool =
+ kmem_cache_create(trans->dev_cmd_pool_name,
+ sizeof(struct iwl_device_cmd)
+ + trans->dev_cmd_headroom,
+ sizeof(void *),
+ SLAB_HWCACHE_ALIGN,
+ NULL);
+ if (!trans->dev_cmd_pool)
+ goto free;
+
+ return trans;
+ free:
+ kfree(trans);
+ return NULL;
+}
+
+void iwl_trans_free(struct iwl_trans *trans)
+{
+ kmem_cache_destroy(trans->dev_cmd_pool);
+ kfree(trans);
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 56254a837214..87a230a7f4b6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -641,6 +641,8 @@ struct iwl_trans {
enum iwl_d0i3_mode d0i3_mode;
+ bool wowlan_d0i3;
+
/* pointer to trans specific struct */
/*Ensure that this pointer will always be aligned to sizeof pointer */
char trans_specific[0] __aligned(sizeof(void *));
@@ -1011,19 +1013,19 @@ static inline void iwl_trans_fw_error(struct iwl_trans *trans)
}
/*****************************************************
+ * transport helper functions
+ *****************************************************/
+struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
+ struct device *dev,
+ const struct iwl_cfg *cfg,
+ const struct iwl_trans_ops *ops,
+ size_t dev_cmd_headroom);
+void iwl_trans_free(struct iwl_trans *trans);
+
+/*****************************************************
* driver (transport) register/unregister functions
******************************************************/
int __must_check iwl_pci_register_driver(void);
void iwl_pci_unregister_driver(void);
-static inline void trans_lockdep_init(struct iwl_trans *trans)
-{
-#ifdef CONFIG_LOCKDEP
- static struct lock_class_key __key;
-
- lockdep_init_map(&trans->sync_cmd_lockdep_map, "sync_cmd_lockdep_map",
- &__key, 0);
-#endif
-}
-
#endif /* __iwl_trans_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c
index 13a0a03158de..b4737e296c92 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -408,23 +408,12 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif)
int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
{
- struct iwl_bt_coex_cmd *bt_cmd;
- struct iwl_host_cmd cmd = {
- .id = BT_CONFIG,
- .len = { sizeof(*bt_cmd), },
- .dataflags = { IWL_HCMD_DFL_NOCOPY, },
- };
- int ret;
+ struct iwl_bt_coex_cmd bt_cmd = {};
u32 mode;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_send_bt_init_conf_old(mvm);
- bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL);
- if (!bt_cmd)
- return -ENOMEM;
- cmd.data[0] = bt_cmd;
-
lockdep_assert_held(&mvm->mutex);
if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) {
@@ -440,36 +429,33 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
mode = 0;
}
- bt_cmd->mode = cpu_to_le32(mode);
+ bt_cmd.mode = cpu_to_le32(mode);
goto send_cmd;
}
mode = iwlwifi_mod_params.bt_coex_active ? BT_COEX_NW : BT_COEX_DISABLE;
- bt_cmd->mode = cpu_to_le32(mode);
+ bt_cmd.mode = cpu_to_le32(mode);
if (IWL_MVM_BT_COEX_SYNC2SCO)
- bt_cmd->enabled_modules |=
+ bt_cmd.enabled_modules |=
cpu_to_le32(BT_COEX_SYNC2SCO_ENABLED);
if (iwl_mvm_bt_is_plcr_supported(mvm))
- bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_CORUN_ENABLED);
+ bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_CORUN_ENABLED);
if (IWL_MVM_BT_COEX_MPLUT) {
- bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_MPLUT_ENABLED);
- bt_cmd->enabled_modules |=
+ bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_MPLUT_ENABLED);
+ bt_cmd.enabled_modules |=
cpu_to_le32(BT_COEX_MPLUT_BOOST_ENABLED);
}
- bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET);
+ bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET);
send_cmd:
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
- ret = iwl_mvm_send_cmd(mvm, &cmd);
-
- kfree(bt_cmd);
- return ret;
+ return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, 0, sizeof(bt_cmd), &bt_cmd);
}
static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
@@ -746,7 +732,7 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_rx_bt_coex_notif_old(mvm, rxb, dev_cmd);
IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");
@@ -770,52 +756,14 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
return 0;
}
-static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
- struct ieee80211_vif *vif)
-{
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_bt_iterator_data *data = _data;
- struct iwl_mvm *mvm = data->mvm;
-
- struct ieee80211_sta *sta;
- struct iwl_mvm_sta *mvmsta;
-
- struct ieee80211_chanctx_conf *chanctx_conf;
-
- rcu_read_lock();
- chanctx_conf = rcu_dereference(vif->chanctx_conf);
- /* If channel context is invalid or not on 2.4GHz - don't count it */
- if (!chanctx_conf ||
- chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) {
- rcu_read_unlock();
- return;
- }
- rcu_read_unlock();
-
- if (vif->type != NL80211_IFTYPE_STATION ||
- mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
- return;
-
- sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
- lockdep_is_held(&mvm->mutex));
-
- /* This can happen if the station has been removed right now */
- if (IS_ERR_OR_NULL(sta))
- return;
-
- mvmsta = iwl_mvm_sta_from_mac80211(sta);
-}
-
void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum ieee80211_rssi_event_data rssi_event)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_bt_iterator_data data = {
- .mvm = mvm,
- };
int ret;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
+ if (!fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
iwl_mvm_bt_rssi_event_old(mvm, vif, rssi_event);
return;
}
@@ -853,10 +801,6 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (ret)
IWL_ERR(mvm, "couldn't send BT_CONFIG HCMD upon RSSI event\n");
-
- ieee80211_iterate_active_interfaces_atomic(
- mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_bt_rssi_iterator, &data);
}
#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000)
@@ -870,7 +814,7 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
enum iwl_bt_coex_lut_type lut_type;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_coex_agg_time_limit_old(mvm, sta);
if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id))
@@ -897,7 +841,7 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
enum iwl_bt_coex_lut_type lut_type;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_bt_coex_is_mimo_allowed_old(mvm, sta);
if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id))
@@ -927,7 +871,7 @@ bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant)
if (ant & mvm->cfg->non_shared_ant)
return true;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm);
return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
@@ -940,10 +884,10 @@ bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm)
if (mvm->cfg->bt_shared_single_ant)
return true;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm);
- return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF;
+ return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC;
}
bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
@@ -951,7 +895,7 @@ bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
{
u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading);
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_bt_coex_is_tpc_allowed_old(mvm, band);
if (band != IEEE80211_BAND_2GHZ)
@@ -994,7 +938,8 @@ u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm)
{
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
+ if (!fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
iwl_mvm_bt_coex_vif_change_old(mvm);
return;
}
@@ -1012,7 +957,7 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
u8 __maybe_unused lower_bound, upper_bound;
u8 lut;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb, dev_cmd);
if (!iwl_mvm_bt_is_plcr_supported(mvm))
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index 4310cf102d78..4165d104e4c3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -761,7 +761,7 @@ void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
{
- iwl_mvm_cancel_scan(mvm);
+ iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true);
iwl_trans_stop_device(mvm->trans);
@@ -981,7 +981,8 @@ iwl_mvm_netdetect_config(struct iwl_mvm *mvm,
if (ret)
return ret;
- ret = iwl_mvm_scan_offload_start(mvm, vif, nd_config, &mvm->nd_ies);
+ ret = iwl_mvm_sched_scan_start(mvm, vif, nd_config, &mvm->nd_ies,
+ IWL_MVM_SCAN_NETDETECT);
if (ret)
return ret;
@@ -1169,7 +1170,8 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
iwl_trans_suspend(mvm->trans);
- if (wowlan->any) {
+ mvm->trans->wowlan_d0i3 = wowlan->any;
+ if (mvm->trans->wowlan_d0i3) {
/* 'any' trigger means d0i3 usage */
if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) {
int ret = iwl_mvm_enter_d0i3_sync(mvm);
@@ -1784,7 +1786,7 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
for_each_set_bit(i, &matched_profiles, mvm->n_nd_match_sets) {
struct iwl_scan_offload_profile_match *fw_match;
struct cfg80211_wowlan_nd_match *match;
- int n_channels = 0;
+ int idx, n_channels = 0;
fw_match = &query.matches[i];
@@ -1799,8 +1801,12 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
net_detect->matches[net_detect->n_matches++] = match;
- match->ssid.ssid_len = mvm->nd_match_sets[i].ssid.ssid_len;
- memcpy(match->ssid.ssid, mvm->nd_match_sets[i].ssid.ssid,
+ /* We inverted the order of the SSIDs in the scan
+ * request, so invert the index here.
+ */
+ idx = mvm->n_nd_match_sets - i - 1;
+ match->ssid.ssid_len = mvm->nd_match_sets[idx].ssid.ssid_len;
+ memcpy(match->ssid.ssid, mvm->nd_match_sets[idx].ssid.ssid,
match->ssid.ssid_len);
if (mvm->n_nd_channels < n_channels)
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
index 5f37eab5008d..5c8a65de0e77 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -190,6 +190,21 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
return ret ?: count;
}
+static ssize_t iwl_dbgfs_tx_pwr_lmt_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_vif *vif = file->private_data;
+ char buf[64];
+ int bufsz = sizeof(buf);
+ int pos;
+
+ pos = scnprintf(buf, bufsz, "bss limit = %d\n",
+ vif->bss_conf.txpower);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
@@ -607,6 +622,7 @@ static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
} while (0)
MVM_DEBUGFS_READ_FILE_OPS(mac_params);
+MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
@@ -641,6 +657,7 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir,
S_IRUSR | S_IWUSR);
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index 9ac04c1ea706..ffb4b5cef275 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -493,7 +493,8 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
mutex_lock(&mvm->mutex);
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
+ if (!fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
struct iwl_bt_coex_profile_notif_old *notif =
&mvm->last_bt_notif_old;
@@ -550,7 +551,8 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
mutex_lock(&mvm->mutex);
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
+ if (!fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
struct iwl_bt_coex_ci_cmd_old *cmd = &mvm->last_bt_ci_cmd_old;
pos += scnprintf(buf+pos, bufsz-pos,
@@ -916,7 +918,8 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
if (mvm->scan_rx_ant != scan_rx_ant) {
mvm->scan_rx_ant = scan_rx_ant;
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_UMAC_SCAN))
iwl_mvm_config_scan(mvm);
}
@@ -1356,6 +1359,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN);
PRINT_MVM_REF(IWL_MVM_REF_SCAN);
PRINT_MVM_REF(IWL_MVM_REF_ROC);
+ PRINT_MVM_REF(IWL_MVM_REF_ROC_AUX);
PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT);
PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS);
PRINT_MVM_REF(IWL_MVM_REF_USER);
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
index d6cced47d561..5e4cbdb44c60 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -274,50 +274,18 @@ struct iwl_scan_offload_profile_cfg {
} __packed;
/**
- * iwl_scan_offload_schedule - schedule of scan offload
+ * iwl_scan_schedule_lmac - schedule of scan offload
* @delay: delay between iterations, in seconds.
* @iterations: num of scan iterations
* @full_scan_mul: number of partial scans before each full scan
*/
-struct iwl_scan_offload_schedule {
+struct iwl_scan_schedule_lmac {
__le16 delay;
u8 iterations;
u8 full_scan_mul;
-} __packed;
-
-/*
- * iwl_scan_offload_flags
- *
- * IWL_SCAN_OFFLOAD_FLAG_PASS_ALL: pass all results - no filtering.
- * IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL: add cached channels to partial scan.
- * IWL_SCAN_OFFLOAD_FLAG_EBS_QUICK_MODE: EBS duration is 100mSec - typical
- * beacon period. Finding channel activity in this mode is not guaranteed.
- * IWL_SCAN_OFFLOAD_FLAG_EBS_ACCURATE_MODE: EBS duration is 200mSec.
- * Assuming beacon period is 100ms finding channel activity is guaranteed.
- */
-enum iwl_scan_offload_flags {
- IWL_SCAN_OFFLOAD_FLAG_PASS_ALL = BIT(0),
- IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL = BIT(2),
- IWL_SCAN_OFFLOAD_FLAG_EBS_QUICK_MODE = BIT(5),
- IWL_SCAN_OFFLOAD_FLAG_EBS_ACCURATE_MODE = BIT(6),
-};
-
-/**
- * iwl_scan_offload_req - scan offload request command
- * @flags: bitmap - enum iwl_scan_offload_flags.
- * @watchdog: maximum scan duration in TU.
- * @delay: delay in seconds before first iteration.
- * @schedule_line: scan offload schedule, for fast and regular scan.
- */
-struct iwl_scan_offload_req {
- __le16 flags;
- __le16 watchdog;
- __le16 delay;
- __le16 reserved;
- struct iwl_scan_offload_schedule schedule_line[2];
-} __packed;
+} __packed; /* SCAN_SCHEDULE_API_S */
-enum iwl_scan_offload_compleate_status {
+enum iwl_scan_offload_complete_status {
IWL_SCAN_OFFLOAD_COMPLETED = 1,
IWL_SCAN_OFFLOAD_ABORTED = 2,
};
@@ -326,6 +294,7 @@ enum iwl_scan_ebs_status {
IWL_SCAN_EBS_SUCCESS,
IWL_SCAN_EBS_FAILED,
IWL_SCAN_EBS_CHAN_NOT_FOUND,
+ IWL_SCAN_EBS_INACTIVE,
};
/**
@@ -463,8 +432,19 @@ enum iwl_scan_priority {
IWL_SCAN_PRIORITY_HIGH,
};
+enum iwl_scan_priority_ext {
+ IWL_SCAN_PRIORITY_EXT_0_LOWEST,
+ IWL_SCAN_PRIORITY_EXT_1,
+ IWL_SCAN_PRIORITY_EXT_2,
+ IWL_SCAN_PRIORITY_EXT_3,
+ IWL_SCAN_PRIORITY_EXT_4,
+ IWL_SCAN_PRIORITY_EXT_5,
+ IWL_SCAN_PRIORITY_EXT_6,
+ IWL_SCAN_PRIORITY_EXT_7_HIGHEST,
+};
+
/**
- * iwl_scan_req_unified_lmac - SCAN_REQUEST_CMD_API_S_VER_1
+ * iwl_scan_req_lmac - SCAN_REQUEST_CMD_API_S_VER_1
* @reserved1: for alignment and future use
* @channel_num: num of channels to scan
* @active-dwell: dwell time for active channels
@@ -487,7 +467,7 @@ enum iwl_scan_priority {
* @channel_opt: channel optimization options, for full and partial scan
* @data: channel configuration and probe request packet.
*/
-struct iwl_scan_req_unified_lmac {
+struct iwl_scan_req_lmac {
/* SCAN_REQUEST_FIXED_PART_API_S_VER_7 */
__le32 reserved1;
u8 n_channels;
@@ -508,7 +488,7 @@ struct iwl_scan_req_unified_lmac {
/* SCAN_REQ_PERIODIC_PARAMS_API_S */
__le32 iter_num;
__le32 delay;
- struct iwl_scan_offload_schedule schedule[2];
+ struct iwl_scan_schedule_lmac schedule[2];
struct iwl_scan_channel_opt channel_opt[2];
u8 data[];
} __packed;
@@ -582,7 +562,11 @@ struct iwl_mvm_umac_cmd_hdr {
u8 ver;
} __packed;
-#define IWL_MVM_MAX_SIMULTANEOUS_SCANS 8
+/* The maximum of either of these cannot exceed 8, because we use an
+ * 8-bit mask (see IWL_MVM_SCAN_MASK in mvm.h).
+ */
+#define IWL_MVM_MAX_UMAC_SCANS 8
+#define IWL_MVM_MAX_LMAC_SCANS 1
enum scan_config_flags {
SCAN_CONFIG_FLAG_ACTIVATE = BIT(0),
@@ -865,4 +849,27 @@ struct iwl_scan_offload_profiles_query {
struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES];
} __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_2 */
+/**
+ * struct iwl_umac_scan_iter_complete_notif - notifies end of scanning iteration
+ * @uid: scan id, &enum iwl_umac_scan_uid_offsets
+ * @scanned_channels: number of channels scanned and number of valid elements in
+ * results array
+ * @status: one of SCAN_COMP_STATUS_*
+ * @bt_status: BT on/off status
+ * @last_channel: last channel that was scanned
+ * @tsf_low: TSF timer (lower half) in usecs
+ * @tsf_high: TSF timer (higher half) in usecs
+ * @results: array of scan results, only "scanned_channels" of them are valid
+ */
+struct iwl_umac_scan_iter_complete_notif {
+ __le32 uid;
+ u8 scanned_channels;
+ u8 status;
+ u8 bt_status;
+ u8 last_channel;
+ __le32 tsf_low;
+ __le32 tsf_high;
+ struct iwl_scan_results_notif results[];
+} __packed; /* SCAN_ITER_COMPLETE_NTF_UMAC_API_S_VER_1 */
+
#endif
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 01b1da6ad359..16e9ef49397f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -108,6 +108,7 @@ enum {
ANTENNA_COUPLING_NOTIFICATION = 0xa,
/* UMAC scan commands */
+ SCAN_ITERATION_COMPLETE_UMAC = 0xb5,
SCAN_CFG_CMD = 0xc,
SCAN_REQ_UMAC = 0xd,
SCAN_ABORT_UMAC = 0xe,
@@ -147,13 +148,6 @@ enum {
LQ_CMD = 0x4e,
- /* Calibration */
- TEMPERATURE_NOTIFICATION = 0x62,
- CALIBRATION_CFG_CMD = 0x65,
- CALIBRATION_RES_NOTIFICATION = 0x66,
- CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
- RADIO_VERSION_NOTIFICATION = 0x68,
-
/* Scan offload */
SCAN_OFFLOAD_REQUEST_CMD = 0x51,
SCAN_OFFLOAD_ABORT_CMD = 0x52,
@@ -177,12 +171,8 @@ enum {
/* Thermal Throttling*/
REPLY_THERMAL_MNG_BACKOFF = 0x7e,
- /* Scanning */
- SCAN_REQUEST_CMD = 0x80,
- SCAN_ABORT_CMD = 0x81,
- SCAN_START_NOTIFICATION = 0x82,
- SCAN_RESULTS_NOTIFICATION = 0x83,
- SCAN_COMPLETE_NOTIFICATION = 0x84,
+ /* Set/Get DC2DC frequency tune */
+ DC2DC_CONFIG_CMD = 0x83,
/* NVM */
NVM_ACCESS_CMD = 0x88,
@@ -1402,6 +1392,49 @@ struct iwl_mvm_marker {
__le32 metadata[0];
} __packed; /* MARKER_API_S_VER_1 */
+/*
+ * enum iwl_dc2dc_config_id - flag ids
+ *
+ * Ids of dc2dc configuration flags
+ */
+enum iwl_dc2dc_config_id {
+ DCDC_LOW_POWER_MODE_MSK_SET = 0x1, /* not used */
+ DCDC_FREQ_TUNE_SET = 0x2,
+}; /* MARKER_ID_API_E_VER_1 */
+
+/**
+ * struct iwl_dc2dc_config_cmd - configure dc2dc values
+ *
+ * (DC2DC_CONFIG_CMD = 0x83)
+ *
+ * Set/Get & configure dc2dc values.
+ * The command always returns the current dc2dc values.
+ *
+ * @flags: set/get dc2dc
+ * @enable_low_power_mode: not used.
+ * @dc2dc_freq_tune0: frequency divider - digital domain
+ * @dc2dc_freq_tune1: frequency divider - analog domain
+ */
+struct iwl_dc2dc_config_cmd {
+ __le32 flags;
+ __le32 enable_low_power_mode; /* not used */
+ __le32 dc2dc_freq_tune0;
+ __le32 dc2dc_freq_tune1;
+} __packed; /* DC2DC_CONFIG_CMD_API_S_VER_1 */
+
+/**
+ * struct iwl_dc2dc_config_resp - response for iwl_dc2dc_config_cmd
+ *
+ * Current dc2dc values returned by the FW.
+ *
+ * @dc2dc_freq_tune0: frequency divider - digital domain
+ * @dc2dc_freq_tune1: frequency divider - analog domain
+ */
+struct iwl_dc2dc_config_resp {
+ __le32 dc2dc_freq_tune0;
+ __le32 dc2dc_freq_tune1;
+} __packed; /* DC2DC_CONFIG_RESP_API_S_VER_1 */
+
/***********************************
* Smart Fifo API
***********************************/
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index df869633f4dd..eb10c5ee4a14 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -623,7 +623,7 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm)
if (!mvm->trans->ltr_enabled)
return 0;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_HDC_PHASE_0))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_HDC_PHASE_0))
return iwl_mvm_config_ltr_v1(mvm);
return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0,
@@ -662,9 +662,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
* device that are triggered by the INIT firwmare (MFUART).
*/
_iwl_trans_stop_device(mvm->trans, false);
- _iwl_trans_start_hw(mvm->trans, false);
+ ret = _iwl_trans_start_hw(mvm->trans, false);
if (ret)
- return ret;
+ goto error;
}
if (iwlmvm_mod_params.init_dbg)
@@ -754,7 +754,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
goto error;
}
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
ret = iwl_mvm_config_scan(mvm);
if (ret)
goto error;
@@ -832,21 +832,6 @@ int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm,
return 0;
}
-int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd)
-{
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_radio_version_notif *radio_version = (void *)pkt->data;
-
- /* TODO: what to do with that? */
- IWL_DEBUG_INFO(mvm,
- "Radio version: flavor: 0x%08x, step 0x%08x, dash 0x%08x\n",
- le32_to_cpu(radio_version->radio_flavor),
- le32_to_cpu(radio_version->radio_step),
- le32_to_cpu(radio_version->radio_dash));
- return 0;
-}
-
int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index 8088c7137f7c..1812dd018af2 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -852,7 +852,7 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
MAC_FILTER_IN_BEACON |
MAC_FILTER_IN_PROBE_REQUEST |
MAC_FILTER_IN_CRC32);
- mvm->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
+ ieee80211_hw_set(mvm->hw, RX_INCLUDES_FCS);
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
}
@@ -1270,7 +1270,7 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
mvmvif->uploaded = false;
if (vif->type == NL80211_IFTYPE_MONITOR)
- mvm->hw->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
+ __clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, mvm->hw->flags);
return 0;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index dda9f7b5f342..dfdab38e2d4a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -80,7 +80,6 @@
#include "sta.h"
#include "time-event.h"
#include "iwl-eeprom-parse.h"
-#include "fw-api-scan.h"
#include "iwl-phy-db.h"
#include "testmode.h"
#include "iwl-fw-error-dump.h"
@@ -319,7 +318,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
resp = iwl_mvm_update_mcc(mvm, alpha2, src_id);
if (IS_ERR_OR_NULL(resp)) {
IWL_DEBUG_LAR(mvm, "Could not get update from FW %d\n",
- PTR_RET(resp));
+ PTR_ERR_OR_ZERO(resp));
goto out;
}
@@ -335,7 +334,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
kfree(resp);
if (IS_ERR_OR_NULL(regd)) {
IWL_DEBUG_LAR(mvm, "Could not get parse update from FW %d\n",
- PTR_RET(regd));
+ PTR_ERR_OR_ZERO(regd));
goto out;
}
@@ -416,20 +415,27 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
{
struct ieee80211_hw *hw = mvm->hw;
int num_mac, ret, i;
+ static const u32 mvm_ciphers[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+ };
/* Tell mac80211 our characteristics */
- hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_QUEUE_CONTROL |
- IEEE80211_HW_WANT_MONITOR_VIF |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_TIMING_BEACON_ONLY |
- IEEE80211_HW_CONNECTION_MONITOR |
- IEEE80211_HW_CHANCTX_STA_CSA |
- IEEE80211_HW_SUPPORTS_CLONED_SKBS;
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, QUEUE_CONTROL);
+ ieee80211_hw_set(hw, WANT_MONITOR_VIF);
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, TIMING_BEACON_ONLY);
+ ieee80211_hw_set(hw, CONNECTION_MONITOR);
+ ieee80211_hw_set(hw, CHANCTX_STA_CSA);
+ ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
+ ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
hw->queues = mvm->first_agg_queue;
hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
@@ -441,19 +447,38 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
+ BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 2);
+ memcpy(mvm->ciphers, mvm_ciphers, sizeof(mvm_ciphers));
+ hw->wiphy->n_cipher_suites = ARRAY_SIZE(mvm_ciphers);
+ hw->wiphy->cipher_suites = mvm->ciphers;
+
/*
* Enable 11w if advertised by firmware and software crypto
* is not enabled (as the firmware will interpret some mgmt
* packets, so enabling it with software crypto isn't safe)
*/
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP &&
- !iwlwifi_mod_params.sw_crypto)
- hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+ !iwlwifi_mod_params.sw_crypto) {
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+ mvm->ciphers[hw->wiphy->n_cipher_suites] =
+ WLAN_CIPHER_SUITE_AES_CMAC;
+ hw->wiphy->n_cipher_suites++;
+ }
- hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS;
+ /* currently FW API supports only one optional cipher scheme */
+ if (mvm->fw->cs[0].cipher) {
+ mvm->hw->n_cipher_schemes = 1;
+ mvm->hw->cipher_schemes = &mvm->fw->cs[0];
+ mvm->ciphers[hw->wiphy->n_cipher_suites] =
+ mvm->fw->cs[0].cipher;
+ hw->wiphy->n_cipher_suites++;
+ }
+
+ ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
hw->wiphy->features |=
NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
- NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
+ NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR |
+ NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
hw->sta_data_size = sizeof(struct iwl_mvm_sta);
hw->vif_data_size = sizeof(struct iwl_mvm_vif);
@@ -506,10 +531,19 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
iwl_mvm_reset_phy_ctxts(mvm);
- hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm, false);
+ hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm);
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
+ BUILD_BUG_ON(IWL_MVM_SCAN_STOPPING_MASK & IWL_MVM_SCAN_MASK);
+ BUILD_BUG_ON(IWL_MVM_MAX_UMAC_SCANS > HWEIGHT32(IWL_MVM_SCAN_MASK) ||
+ IWL_MVM_MAX_LMAC_SCANS > HWEIGHT32(IWL_MVM_SCAN_MASK));
+
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN))
+ mvm->max_scans = IWL_MVM_MAX_UMAC_SCANS;
+ else
+ mvm->max_scans = IWL_MVM_MAX_LMAC_SCANS;
+
if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels)
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&mvm->nvm_data->bands[IEEE80211_BAND_2GHZ];
@@ -517,10 +551,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&mvm->nvm_data->bands[IEEE80211_BAND_5GHZ];
- if ((mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
- (mvm->fw->ucode_capa.api[0] &
- IWL_UCODE_TLV_API_LQ_SS_PARAMS))
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
+ fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_LQ_SS_PARAMS))
hw->wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |=
IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
}
@@ -532,14 +566,12 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
else
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
- if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10) {
- hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
- hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
- hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
- /* we create the 802.11 header and zero length SSID IE. */
- hw->wiphy->max_sched_scan_ie_len =
- SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
- }
+ hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+ hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
+ hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
+ /* we create the 802.11 header and zero length SSID IE. */
+ hw->wiphy->max_sched_scan_ie_len =
+ SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
NL80211_FEATURE_LOW_PRIORITY_SCAN |
@@ -548,30 +580,24 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
NL80211_FEATURE_STATIC_SMPS |
NL80211_FEATURE_SUPPORTS_WMM_ADMISSION;
- if (mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT)
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT))
hw->wiphy->features |= NL80211_FEATURE_TX_POWER_INSERTION;
- if (mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT)
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT))
hw->wiphy->features |= NL80211_FEATURE_QUIET;
- if (mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT)
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT))
hw->wiphy->features |=
NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES;
- if (mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT)
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT))
hw->wiphy->features |= NL80211_FEATURE_WFA_TPC_IE_IN_PROBES;
mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
- /* currently FW API supports only one optional cipher scheme */
- if (mvm->fw->cs[0].cipher) {
- mvm->hw->n_cipher_schemes = 1;
- mvm->hw->cipher_schemes = &mvm->fw->cs[0];
- }
-
#ifdef CONFIG_PM_SLEEP
if (iwl_mvm_is_d0i3_supported(mvm) &&
device_can_wakeup(mvm->trans->dev)) {
@@ -611,13 +637,14 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
if (ret)
return ret;
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_TDLS_SUPPORT) {
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_TDLS_SUPPORT)) {
IWL_DEBUG_TDLS(mvm, "TDLS supported\n");
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
}
- if (mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH) {
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH)) {
IWL_DEBUG_TDLS(mvm, "TDLS channel switch supported\n");
hw->wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH;
}
@@ -730,6 +757,60 @@ static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg)
return true;
}
+#define CHECK_BA_TRIGGER(_mvm, _trig, _tid_bm, _tid, _fmt...) \
+ do { \
+ if (!(le16_to_cpu(_tid_bm) & BIT(_tid))) \
+ break; \
+ iwl_mvm_fw_dbg_collect_trig(_mvm, _trig, _fmt); \
+ } while (0)
+
+static void
+iwl_mvm_ampdu_check_trigger(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid, u16 rx_ba_ssn,
+ enum ieee80211_ampdu_mlme_action action)
+{
+ struct iwl_fw_dbg_trigger_tlv *trig;
+ struct iwl_fw_dbg_trigger_ba *ba_trig;
+
+ if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
+ return;
+
+ trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
+ ba_trig = (void *)trig->data;
+
+ if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig))
+ return;
+
+ switch (action) {
+ case IEEE80211_AMPDU_TX_OPERATIONAL: {
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
+
+ CHECK_BA_TRIGGER(mvm, trig, ba_trig->tx_ba_start, tid,
+ "TX AGG START: MAC %pM tid %d ssn %d\n",
+ sta->addr, tid, tid_data->ssn);
+ break;
+ }
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ CHECK_BA_TRIGGER(mvm, trig, ba_trig->tx_ba_stop, tid,
+ "TX AGG STOP: MAC %pM tid %d\n",
+ sta->addr, tid);
+ break;
+ case IEEE80211_AMPDU_RX_START:
+ CHECK_BA_TRIGGER(mvm, trig, ba_trig->rx_ba_start, tid,
+ "RX AGG START: MAC %pM tid %d ssn %d\n",
+ sta->addr, tid, rx_ba_ssn);
+ break;
+ case IEEE80211_AMPDU_RX_STOP:
+ CHECK_BA_TRIGGER(mvm, trig, ba_trig->rx_ba_stop, tid,
+ "RX AGG STOP: MAC %pM tid %d\n",
+ sta->addr, tid);
+ break;
+ default:
+ break;
+ }
+}
+
static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
@@ -806,6 +887,16 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
ret = -EINVAL;
break;
}
+
+ if (!ret) {
+ u16 rx_ba_ssn = 0;
+
+ if (action == IEEE80211_AMPDU_RX_START)
+ rx_ba_ssn = *ssn;
+
+ iwl_mvm_ampdu_check_trigger(mvm, vif, sta, tid,
+ rx_ba_ssn, action);
+ }
mutex_unlock(&mvm->mutex);
/*
@@ -1227,22 +1318,23 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
iwl_trans_stop_device(mvm->trans);
- mvm->scan_status = IWL_MVM_SCAN_NONE;
+ mvm->scan_status = 0;
mvm->ps_disabled = false;
mvm->calibrating = false;
/* just in case one was running */
ieee80211_remain_on_channel_expired(mvm->hw);
- ieee80211_iterate_active_interfaces_atomic(
- mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
- iwl_mvm_cleanup_iterator, mvm);
+ /*
+ * cleanup all interfaces, even inactive ones, as some might have
+ * gone down during the HW restart
+ */
+ ieee80211_iterate_interfaces(mvm->hw, 0, iwl_mvm_cleanup_iterator, mvm);
mvm->p2p_device_vif = NULL;
mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
iwl_mvm_reset_phy_ctxts(mvm);
- memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained));
memset(mvm->tfd_drained, 0, sizeof(mvm->tfd_drained));
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
@@ -1404,7 +1496,7 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
* The work item could be running or queued if the
* ROC time event stops just as we get here.
*/
- cancel_work_sync(&mvm->roc_done_wk);
+ flush_work(&mvm->roc_done_wk);
iwl_trans_stop_device(mvm->trans);
@@ -1417,20 +1509,24 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
/*
* Clear IN_HW_RESTART flag when stopping the hw (as restart_complete()
* won't be called in this case).
+ * But make sure to cleanup interfaces that have gone down before/during
+ * HW restart was requested.
*/
- clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+ if (test_and_clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+ ieee80211_iterate_interfaces(mvm->hw, 0,
+ iwl_mvm_cleanup_iterator, mvm);
/* We shouldn't have any UIDs still set. Loop over all the UIDs to
* make sure there's nothing left there and warn if any is found.
*/
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
int i;
- for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) {
- if (WARN_ONCE(mvm->scan_uid[i],
- "UMAC scan UID %d was not cleaned\n",
- mvm->scan_uid[i]))
- mvm->scan_uid[i] = 0;
+ for (i = 0; i < mvm->max_scans; i++) {
+ if (WARN_ONCE(mvm->scan_uid_status[i],
+ "UMAC scan UID %d status was not cleaned\n",
+ i))
+ mvm->scan_uid_status[i] = 0;
}
}
@@ -1495,7 +1591,7 @@ static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
.pwr_restriction = cpu_to_le16(8 * tx_power),
};
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_TX_POWER_DEV))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TX_POWER_DEV))
return iwl_mvm_set_tx_power_old(mvm, vif, tx_power);
if (tx_power == IWL_DEFAULT_MAX_TX_POWER)
@@ -2354,7 +2450,7 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
mutex_lock(&mvm->mutex);
if (changes & BSS_CHANGED_IDLE && !bss_conf->idle)
- iwl_mvm_scan_offload_stop(mvm, true);
+ iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true);
switch (vif->type) {
case NL80211_IFTYPE_STATION:
@@ -2373,89 +2469,21 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
iwl_mvm_unref(mvm, IWL_MVM_REF_BSS_CHANGED);
}
-static int iwl_mvm_cancel_scan_wait_notif(struct iwl_mvm *mvm,
- enum iwl_scan_status scan_type)
-{
- int ret;
- bool wait_for_handlers = false;
-
- mutex_lock(&mvm->mutex);
-
- if (mvm->scan_status != scan_type) {
- ret = 0;
- /* make sure there are no pending notifications */
- wait_for_handlers = true;
- goto out;
- }
-
- switch (scan_type) {
- case IWL_MVM_SCAN_SCHED:
- ret = iwl_mvm_scan_offload_stop(mvm, true);
- break;
- case IWL_MVM_SCAN_OS:
- ret = iwl_mvm_cancel_scan(mvm);
- break;
- case IWL_MVM_SCAN_NONE:
- default:
- WARN_ON_ONCE(1);
- ret = -EINVAL;
- break;
- }
- if (ret)
- goto out;
-
- wait_for_handlers = true;
-out:
- mutex_unlock(&mvm->mutex);
-
- /* make sure we consume the completion notification */
- if (wait_for_handlers)
- iwl_mvm_wait_for_async_handlers(mvm);
-
- return ret;
-}
static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_scan_request *hw_req)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- struct cfg80211_scan_request *req = &hw_req->req;
int ret;
- if (req->n_channels == 0 ||
- req->n_channels > mvm->fw->ucode_capa.n_scan_channels)
+ if (hw_req->req.n_channels == 0 ||
+ hw_req->req.n_channels > mvm->fw->ucode_capa.n_scan_channels)
return -EINVAL;
- if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
- ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED);
- if (ret)
- return ret;
- }
-
mutex_lock(&mvm->mutex);
-
- if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
- IWL_ERR(mvm, "scan while LAR regdomain is not set\n");
- ret = -EBUSY;
- goto out;
- }
-
- if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
- ret = -EBUSY;
- goto out;
- }
-
- iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN);
-
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
- ret = iwl_mvm_scan_umac(mvm, vif, hw_req);
- else
- ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req);
-
- if (ret)
- iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
-out:
+ ret = iwl_mvm_reg_scan_start(mvm, vif, &hw_req->req, &hw_req->ies);
mutex_unlock(&mvm->mutex);
+
return ret;
}
@@ -2473,12 +2501,8 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,
* cancel scan scan before ieee80211_scan_work() could run.
* To handle that, simply return if the scan is not running.
*/
- /* FIXME: for now, we ignore this race for UMAC scans, since
- * they don't set the scan_status.
- */
- if ((mvm->scan_status == IWL_MVM_SCAN_OS) ||
- (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN))
- iwl_mvm_cancel_scan(mvm);
+ if (mvm->scan_status & IWL_MVM_SCAN_REGULAR)
+ iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true);
mutex_unlock(&mvm->mutex);
}
@@ -2794,35 +2818,17 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
struct ieee80211_scan_ies *ies)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- int ret;
- if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
- ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS);
- if (ret)
- return ret;
- }
+ int ret;
mutex_lock(&mvm->mutex);
- if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
- IWL_ERR(mvm, "sched-scan while LAR regdomain is not set\n");
- ret = -EBUSY;
- goto out;
- }
-
if (!vif->bss_conf.idle) {
ret = -EBUSY;
goto out;
}
- if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
- ret = -EBUSY;
- goto out;
- }
-
- ret = iwl_mvm_scan_offload_start(mvm, vif, req, ies);
- if (ret)
- mvm->scan_status = IWL_MVM_SCAN_NONE;
+ ret = iwl_mvm_sched_scan_start(mvm, vif, req, ies, IWL_MVM_SCAN_SCHED);
out:
mutex_unlock(&mvm->mutex);
@@ -2845,16 +2851,12 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
* could run. To handle this, simply return if the scan is
* not running.
*/
- /* FIXME: for now, we ignore this race for UMAC scans, since
- * they don't set the scan_status.
- */
- if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
- !(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
+ if (!(mvm->scan_status & IWL_MVM_SCAN_SCHED)) {
mutex_unlock(&mvm->mutex);
return 0;
}
- ret = iwl_mvm_scan_offload_stop(mvm, false);
+ ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, false);
mutex_unlock(&mvm->mutex);
iwl_mvm_wait_for_async_handlers(mvm);
@@ -2883,7 +2885,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
- WARN_ON_ONCE(!(hw->flags & IEEE80211_HW_MFP_CAPABLE));
+ WARN_ON_ONCE(!ieee80211_hw_check(hw, MFP_CAPABLE));
break;
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
@@ -2922,8 +2924,21 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
break;
}
+ /* During FW restart, in order to restore the state as it was,
+ * don't try to reprogram keys we previously failed for.
+ */
+ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
+ key->hw_key_idx == STA_KEY_IDX_INVALID) {
+ IWL_DEBUG_MAC80211(mvm,
+ "skip invalid idx key programming during restart\n");
+ ret = 0;
+ break;
+ }
+
IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n");
- ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, false);
+ ret = iwl_mvm_set_sta_key(mvm, vif, sta, key,
+ test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
+ &mvm->status));
if (ret) {
IWL_WARN(mvm, "set key failed\n");
/*
@@ -3001,7 +3016,7 @@ static bool iwl_mvm_rx_aux_roc(struct iwl_notif_wait_data *notif_wait,
return true;
}
-#define AUX_ROC_MAX_DELAY_ON_CHANNEL 5000
+#define AUX_ROC_MAX_DELAY_ON_CHANNEL 200
static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,
struct ieee80211_channel *channel,
struct ieee80211_vif *vif,
@@ -3106,8 +3121,8 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
switch (vif->type) {
case NL80211_IFTYPE_STATION:
- if (mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT) {
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT)) {
/* Use aux roc framework (HS20) */
ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
vif, duration);
@@ -3899,7 +3914,7 @@ static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
if (idx != 0)
return -ENOENT;
- if (!(mvm->fw->ucode_capa.capa[0] &
+ if (fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
return -ENOENT;
@@ -3946,8 +3961,8 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
- if (!(mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
return;
/* if beacon filtering isn't on mac80211 does it anyway */
@@ -3977,9 +3992,9 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
mutex_unlock(&mvm->mutex);
}
-static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- const struct ieee80211_event *event)
+static void iwl_mvm_event_mlme_callback(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ const struct ieee80211_event *event)
{
#define CHECK_MLME_TRIGGER(_mvm, _trig, _buf, _cnt, _fmt...) \
do { \
@@ -3988,7 +4003,6 @@ static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,
iwl_mvm_fw_dbg_collect_trig(_mvm, _trig, _fmt);\
} while (0)
- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_fw_dbg_trigger_tlv *trig;
struct iwl_fw_dbg_trigger_mlme *trig_mlme;
@@ -4032,6 +4046,75 @@ static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,
#undef CHECK_MLME_TRIGGER
}
+static void iwl_mvm_event_bar_rx_callback(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ const struct ieee80211_event *event)
+{
+ struct iwl_fw_dbg_trigger_tlv *trig;
+ struct iwl_fw_dbg_trigger_ba *ba_trig;
+
+ if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
+ return;
+
+ trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
+ ba_trig = (void *)trig->data;
+ if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig))
+ return;
+
+ if (!(le16_to_cpu(ba_trig->rx_bar) & BIT(event->u.ba.tid)))
+ return;
+
+ iwl_mvm_fw_dbg_collect_trig(mvm, trig,
+ "BAR received from %pM, tid %d, ssn %d",
+ event->u.ba.sta->addr, event->u.ba.tid,
+ event->u.ba.ssn);
+}
+
+static void
+iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ const struct ieee80211_event *event)
+{
+ struct iwl_fw_dbg_trigger_tlv *trig;
+ struct iwl_fw_dbg_trigger_ba *ba_trig;
+
+ if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
+ return;
+
+ trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
+ ba_trig = (void *)trig->data;
+ if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig))
+ return;
+
+ if (!(le16_to_cpu(ba_trig->frame_timeout) & BIT(event->u.ba.tid)))
+ return;
+
+ iwl_mvm_fw_dbg_collect_trig(mvm, trig,
+ "Frame from %pM timed out, tid %d",
+ event->u.ba.sta->addr, event->u.ba.tid);
+}
+
+static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ const struct ieee80211_event *event)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ switch (event->type) {
+ case MLME_EVENT:
+ iwl_mvm_event_mlme_callback(mvm, vif, event);
+ break;
+ case BAR_RX_EVENT:
+ iwl_mvm_event_bar_rx_callback(mvm, vif, event);
+ break;
+ case BA_FRAME_TIMEOUT:
+ iwl_mvm_event_frame_timeout_callback(mvm, vif, event);
+ break;
+ default:
+ break;
+ }
+}
+
const struct ieee80211_ops iwl_mvm_hw_ops = {
.tx = iwl_mvm_mac_tx,
.ampdu_action = iwl_mvm_mac_ampdu_action,
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index cf70f681d1ac..2d4bad5fe825 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -76,6 +76,7 @@
#include "iwl-notif-wait.h"
#include "iwl-eeprom-parse.h"
#include "iwl-fw-file.h"
+#include "iwl-config.h"
#include "sta.h"
#include "fw-api.h"
#include "constants.h"
@@ -275,6 +276,7 @@ enum iwl_mvm_ref_type {
IWL_MVM_REF_UCODE_DOWN,
IWL_MVM_REF_SCAN,
IWL_MVM_REF_ROC,
+ IWL_MVM_REF_ROC_AUX,
IWL_MVM_REF_P2P_CLIENT,
IWL_MVM_REF_AP_IBSS,
IWL_MVM_REF_USER,
@@ -445,10 +447,26 @@ iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif)
extern const u8 tid_to_mac80211_ac[];
+#define IWL_MVM_SCAN_STOPPING_SHIFT 8
+
enum iwl_scan_status {
- IWL_MVM_SCAN_NONE,
- IWL_MVM_SCAN_OS,
- IWL_MVM_SCAN_SCHED,
+ IWL_MVM_SCAN_REGULAR = BIT(0),
+ IWL_MVM_SCAN_SCHED = BIT(1),
+ IWL_MVM_SCAN_NETDETECT = BIT(2),
+
+ IWL_MVM_SCAN_STOPPING_REGULAR = BIT(8),
+ IWL_MVM_SCAN_STOPPING_SCHED = BIT(9),
+ IWL_MVM_SCAN_STOPPING_NETDETECT = BIT(10),
+
+ IWL_MVM_SCAN_REGULAR_MASK = IWL_MVM_SCAN_REGULAR |
+ IWL_MVM_SCAN_STOPPING_REGULAR,
+ IWL_MVM_SCAN_SCHED_MASK = IWL_MVM_SCAN_SCHED |
+ IWL_MVM_SCAN_STOPPING_SCHED,
+ IWL_MVM_SCAN_NETDETECT_MASK = IWL_MVM_SCAN_NETDETECT |
+ IWL_MVM_SCAN_STOPPING_NETDETECT,
+
+ IWL_MVM_SCAN_STOPPING_MASK = 0xff << IWL_MVM_SCAN_STOPPING_SHIFT,
+ IWL_MVM_SCAN_MASK = 0xff,
};
/**
@@ -463,49 +481,6 @@ struct iwl_nvm_section {
const u8 *data;
};
-/*
- * Tx-backoff threshold
- * @temperature: The threshold in Celsius
- * @backoff: The tx-backoff in uSec
- */
-struct iwl_tt_tx_backoff {
- s32 temperature;
- u32 backoff;
-};
-
-#define TT_TX_BACKOFF_SIZE 6
-
-/**
- * struct iwl_tt_params - thermal throttling parameters
- * @ct_kill_entry: CT Kill entry threshold
- * @ct_kill_exit: CT Kill exit threshold
- * @ct_kill_duration: The time intervals (in uSec) in which the driver needs
- * to checks whether to exit CT Kill.
- * @dynamic_smps_entry: Dynamic SMPS entry threshold
- * @dynamic_smps_exit: Dynamic SMPS exit threshold
- * @tx_protection_entry: TX protection entry threshold
- * @tx_protection_exit: TX protection exit threshold
- * @tx_backoff: Array of thresholds for tx-backoff , in ascending order.
- * @support_ct_kill: Support CT Kill?
- * @support_dynamic_smps: Support dynamic SMPS?
- * @support_tx_protection: Support tx protection?
- * @support_tx_backoff: Support tx-backoff?
- */
-struct iwl_tt_params {
- s32 ct_kill_entry;
- s32 ct_kill_exit;
- u32 ct_kill_duration;
- s32 dynamic_smps_entry;
- s32 dynamic_smps_exit;
- s32 tx_protection_entry;
- s32 tx_protection_exit;
- struct iwl_tt_tx_backoff tx_backoff[TT_TX_BACKOFF_SIZE];
- bool support_ct_kill;
- bool support_dynamic_smps;
- bool support_tx_protection;
- bool support_tx_backoff;
-};
-
/**
* struct iwl_mvm_tt_mgnt - Thermal Throttling Management structure
* @ct_kill_exit: worker to exit thermal kill
@@ -520,7 +495,7 @@ struct iwl_mvm_tt_mgmt {
bool dynamic_smps;
u32 tx_backoff;
u32 min_backoff;
- const struct iwl_tt_params *params;
+ struct iwl_tt_params params;
bool throttle;
};
@@ -647,13 +622,15 @@ struct iwl_mvm {
u32 rts_threshold;
/* Scan status, cmd (pre-allocated) and auxiliary station */
- enum iwl_scan_status scan_status;
+ unsigned int scan_status;
void *scan_cmd;
struct iwl_mcast_filter_cmd *mcast_filter_cmd;
+ /* max number of simultaneous scans the FW supports */
+ unsigned int max_scans;
+
/* UMAC scan tracking */
- u32 scan_uid[IWL_MVM_MAX_SIMULTANEOUS_SCANS];
- u8 scan_seq_num, sched_scan_seq_num;
+ u32 scan_uid_status[IWL_MVM_MAX_UMAC_SCANS];
/* rx chain antennas set through debugfs for the scan command */
u8 scan_rx_ant;
@@ -843,6 +820,8 @@ struct iwl_mvm {
} tdls_cs;
struct iwl_mvm_shared_mem_cfg shared_mem_cfg;
+
+ u32 ciphers[6];
};
/* Extract MVM priv from op_mode and _hw */
@@ -912,14 +891,15 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm)
return mvm->trans->cfg->d0i3 &&
mvm->trans->d0i3_mode != IWL_D0I3_MODE_OFF &&
!iwlwifi_mod_params.d0i3_disable &&
- (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT);
+ fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_D0I3_SUPPORT);
}
static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm)
{
bool nvm_lar = mvm->nvm_data->lar_enabled;
- bool tlv_lar = mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_LAR_SUPPORT;
+ bool tlv_lar = fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_LAR_SUPPORT);
if (iwlwifi_mod_params.lar_disable)
return false;
@@ -936,24 +916,28 @@ static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm)
static inline bool iwl_mvm_is_wifi_mcc_supported(struct iwl_mvm *mvm)
{
- return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WIFI_MCC_UPDATE ||
- mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC;
+ return fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_WIFI_MCC_UPDATE) ||
+ fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC);
}
static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm)
{
- return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG;
+ return fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_SCD_CFG);
}
static inline bool iwl_mvm_bt_is_plcr_supported(struct iwl_mvm *mvm)
{
- return (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BT_COEX_PLCR) &&
+ return fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_BT_COEX_PLCR) &&
IWL_MVM_BT_COEX_CORUNNING;
}
static inline bool iwl_mvm_bt_is_rrc_supported(struct iwl_mvm *mvm)
{
- return (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BT_COEX_RRC) &&
+ return fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_BT_COEX_RRC) &&
IWL_MVM_BT_COEX_RRC;
}
@@ -1083,8 +1067,6 @@ int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
-int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd);
int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
@@ -1093,8 +1075,6 @@ int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
-int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd);
int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
int iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm,
@@ -1146,48 +1126,38 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, bool force_upload,
struct ieee80211_vif *disabled_vif);
/* Scanning */
+int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct cfg80211_scan_request *req,
+ struct ieee80211_scan_ies *ies);
int iwl_mvm_scan_size(struct iwl_mvm *mvm);
-int iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
-int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan);
+int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify);
+int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm);
void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm);
/* Scheduled scan */
-int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd);
-int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd);
-int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
- struct cfg80211_sched_scan_request *req);
-int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct cfg80211_sched_scan_request *req,
- struct ieee80211_scan_ies *ies);
-int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify);
-int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd);
-
-/* Unified scan */
-int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_scan_request *req);
-int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct cfg80211_sched_scan_request *req,
- struct ieee80211_scan_ies *ies);
+int iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_scan_ies *ies,
+ int type);
+int iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
/* UMAC scan */
int iwl_mvm_config_scan(struct iwl_mvm *mvm);
-int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct ieee80211_scan_request *req);
-int iwl_mvm_sched_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct cfg80211_sched_scan_request *req,
- struct ieee80211_scan_ies *ies);
int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
/* MVM debugfs */
#ifdef CONFIG_IWLWIFI_DEBUGFS
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
index 87b2a30a2308..2a6be350704a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -316,8 +316,8 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
phy_sku = (const __le16 *)sections[NVM_SECTION_TYPE_PHY_SKU].data;
lar_enabled = !iwlwifi_mod_params.lar_disable &&
- (mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_LAR_SUPPORT);
+ fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_LAR_SUPPORT);
return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib,
regulatory, mac_override, phy_sku,
@@ -583,9 +583,9 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic)
kfree(nvm_buffer);
}
- /* load external NVM if configured */
+ /* Only if PNVM selected in the mod param - load external NVM */
if (mvm->nvm_file_name) {
- /* read External NVM file - take the default */
+ /* read External NVM file from the mod param */
ret = iwl_mvm_read_external_nvm(mvm);
if (ret) {
/* choose the nvm_file name according to the
@@ -792,8 +792,8 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm)
char mcc[3];
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
- tlv_lar = mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_LAR_SUPPORT;
+ tlv_lar = fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_LAR_SUPPORT);
nvm_lar = mvm->nvm_data->lar_enabled;
if (tlv_lar != nvm_lar)
IWL_INFO(mvm,
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 2ea01238754e..e4fa50075ffd 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -194,7 +194,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
* (PCIe power is lost before PERST# is asserted), causing ME FW
* to lose ownership and not being able to obtain it back.
*/
- if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
+ if (!mvm->trans->cfg->apmg_not_supported)
iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG,
APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
@@ -238,15 +238,16 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false),
RX_HANDLER(SCAN_ITERATION_COMPLETE,
- iwl_mvm_rx_scan_offload_iter_complete_notif, false),
+ iwl_mvm_rx_lmac_scan_iter_complete_notif, false),
RX_HANDLER(SCAN_OFFLOAD_COMPLETE,
- iwl_mvm_rx_scan_offload_complete_notif, true),
- RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results,
+ iwl_mvm_rx_lmac_scan_complete_notif, true),
+ RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_match_found,
false),
RX_HANDLER(SCAN_COMPLETE_UMAC, iwl_mvm_rx_umac_scan_complete_notif,
true),
+ RX_HANDLER(SCAN_ITERATION_COMPLETE_UMAC,
+ iwl_mvm_rx_umac_scan_iter_complete_notif, false),
- RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
RX_HANDLER(MISSED_BEACONS_NOTIFICATION, iwl_mvm_rx_missed_beacons_notif,
@@ -280,17 +281,11 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(BINDING_CONTEXT_CMD),
CMD(TIME_QUOTA_CMD),
CMD(NON_QOS_TX_COUNTER_CMD),
- CMD(RADIO_VERSION_NOTIFICATION),
- CMD(SCAN_REQUEST_CMD),
- CMD(SCAN_ABORT_CMD),
- CMD(SCAN_START_NOTIFICATION),
- CMD(SCAN_RESULTS_NOTIFICATION),
- CMD(SCAN_COMPLETE_NOTIFICATION),
+ CMD(DC2DC_CONFIG_CMD),
CMD(NVM_ACCESS_CMD),
CMD(PHY_CONFIGURATION_CMD),
CMD(CALIB_RES_NOTIF_PHY_DB),
CMD(SET_CALIB_DEFAULT_CMD),
- CMD(CALIBRATION_COMPLETE_NOTIFICATION),
CMD(ADD_STA_KEY),
CMD(ADD_STA),
CMD(REMOVE_STA),
@@ -359,6 +354,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(TDLS_CHANNEL_SWITCH_NOTIFICATION),
CMD(TDLS_CONFIG_CMD),
CMD(MCC_UPDATE_CMD),
+ CMD(SCAN_ITERATION_COMPLETE_UMAC),
};
#undef CMD
@@ -520,15 +516,12 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
min_backoff = calc_min_backoff(trans, cfg);
iwl_mvm_tt_initialize(mvm, min_backoff);
- /* set the nvm_file_name according to priority */
- if (iwlwifi_mod_params.nvm_file) {
+
+ if (iwlwifi_mod_params.nvm_file)
mvm->nvm_file_name = iwlwifi_mod_params.nvm_file;
- } else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
- if (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_B_STEP)
- mvm->nvm_file_name = mvm->cfg->default_nvm_file_B_step;
- else
- mvm->nvm_file_name = mvm->cfg->default_nvm_file_C_step;
- }
+ else
+ IWL_DEBUG_EEPROM(mvm->trans->dev,
+ "working without external nvm file\n");
if (WARN(cfg->no_power_up_nic_in_init && !mvm->nvm_file_name,
"not allowing power-up and not having nvm_file\n"))
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 33cd68ae7bf9..daff1d0a8e4a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -1,7 +1,7 @@
/******************************************************************************
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -138,7 +138,7 @@ struct rs_tx_column;
typedef bool (*allow_column_func_t) (struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl,
+ struct rs_rate *rate,
const struct rs_tx_column *next_col);
struct rs_tx_column {
@@ -150,14 +150,14 @@ struct rs_tx_column {
};
static bool rs_ant_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl,
+ struct rs_rate *rate,
const struct rs_tx_column *next_col)
{
return iwl_mvm_bt_coex_is_ant_avail(mvm, next_col->ant);
}
static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl,
+ struct rs_rate *rate,
const struct rs_tx_column *next_col)
{
struct iwl_mvm_sta *mvmsta;
@@ -187,7 +187,7 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
}
static bool rs_siso_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl,
+ struct rs_rate *rate,
const struct rs_tx_column *next_col)
{
if (!sta->ht_cap.ht_supported)
@@ -197,10 +197,9 @@ static bool rs_siso_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
}
static bool rs_sgi_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl,
+ struct rs_rate *rate,
const struct rs_tx_column *next_col)
{
- struct rs_rate *rate = &tbl->rate;
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
@@ -1128,8 +1127,8 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
u32 tx_resp_hwrate = (uintptr_t)info->status.status_driver_data[1];
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta;
- bool allow_ant_mismatch = mvm->fw->ucode_capa.api[0] &
- IWL_UCODE_TLV_API_LQ_SS_PARAMS;
+ bool allow_ant_mismatch = fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_LQ_SS_PARAMS);
/* Treat uninitialized rate scaling data same as non-existing. */
if (!lq_sta) {
@@ -1659,7 +1658,8 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
for (j = 0; j < MAX_COLUMN_CHECKS; j++) {
allow_func = next_col->checks[j];
- if (allow_func && !allow_func(mvm, sta, tbl, next_col))
+ if (allow_func && !allow_func(mvm, sta, &tbl->rate,
+ next_col))
break;
}
@@ -2136,7 +2136,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
}
/* current tx rate */
- index = lq_sta->last_txrate_idx;
+ index = rate->index;
/* rates available for this association, and for modulation mode */
rate_mask = rs_get_supported_rates(lq_sta, rate);
@@ -2184,14 +2184,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
* or search for a new one? */
rs_stay_in_table(lq_sta, false);
- goto out;
- }
- /* Else we have enough samples; calculate estimate of
- * actual average throughput */
- if (window->average_tpt != ((window->success_ratio *
- tbl->expected_tpt[index] + 64) / 128)) {
- window->average_tpt = ((window->success_ratio *
- tbl->expected_tpt[index] + 64) / 128);
+ return;
}
/* If we are searching for better modulation mode, check success. */
@@ -2403,9 +2396,6 @@ lq_update:
rs_set_stay_in_table(mvm, 0, lq_sta);
}
}
-
-out:
- lq_sta->last_txrate_idx = index;
}
struct rs_init_rate_info {
@@ -2548,7 +2538,6 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
rate = &tbl->rate;
rs_get_initial_rate(mvm, lq_sta, band, rate);
- lq_sta->last_txrate_idx = rate->index;
WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B);
if (rate->ant == ANT_A)
@@ -2725,7 +2714,7 @@ static void rs_vht_init(struct iwl_mvm *mvm,
(vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))
lq_sta->stbc_capable = true;
- if ((mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
(num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
(vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE))
lq_sta->bfer_capable = true;
@@ -3009,7 +2998,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm);
/* TODO: remove old API when min FW API hits 14 */
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS) &&
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_LQ_SS_PARAMS) &&
rs_stbc_allow(mvm, sta, lq_sta))
rate.stbc = true;
@@ -3223,12 +3212,9 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
rs_build_rates_table(mvm, sta, lq_sta, initial_rate);
- if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS)
+ if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_LQ_SS_PARAMS))
rs_set_lq_ss_params(mvm, sta, lq_sta, initial_rate);
- if (num_of_ant(initial_rate->ant) == 1)
- lq_cmd->single_stream_ant_msk = initial_rate->ant;
-
mvmsta = iwl_mvm_sta_from_mac80211(sta);
mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index e4aa9346a231..2a3da314305a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -322,8 +322,6 @@ struct iwl_lq_sta {
struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
u8 tx_agg_tid_en;
- /* used to be in sta_info */
- int last_txrate_idx;
/* last tx rate_n_flags */
u32 last_rate_n_flags;
/* packets destined for this STA are aggregated */
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index d6314ddf57b5..8f1d93b7a13a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -570,7 +570,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
};
u32 temperature;
- if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_STATS_V10) {
+ if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STATS_V10)) {
struct iwl_notif_statistics_v10 *stats = (void *)&pkt->data;
if (iwl_rx_packet_payload_len(pkt) != v10_len)
@@ -610,7 +610,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
/* Only handle rx statistics temperature changes if async temp
* notifications are not supported
*/
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_ASYNC_DTM))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_ASYNC_DTM))
iwl_mvm_tt_temp_changed(mvm, temperature);
ieee80211_iterate_active_interfaces(mvm->hw,
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index 1075a213bd6a..5de144968723 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -67,11 +67,8 @@
#include <net/mac80211.h>
#include "mvm.h"
-#include "iwl-eeprom-parse.h"
#include "fw-api-scan.h"
-#define IWL_PLCP_QUIET_THRESH 1
-#define IWL_ACTIVE_QUIET_TIME 10
#define IWL_DENSE_EBS_SCAN_RATIO 5
#define IWL_SPARSE_EBS_SCAN_RATIO 1
@@ -79,23 +76,31 @@ struct iwl_mvm_scan_params {
u32 max_out_time;
u32 suspend_time;
bool passive_fragmented;
+ u32 n_channels;
+ u16 delay;
+ int n_ssids;
+ struct cfg80211_ssid *ssids;
+ struct ieee80211_channel **channels;
+ u16 interval; /* interval between scans (in secs) */
+ u32 flags;
+ u8 *mac_addr;
+ u8 *mac_addr_mask;
+ bool no_cck;
+ bool pass_all;
+ int n_match_sets;
+ struct iwl_scan_probe_req preq;
+ struct cfg80211_match_set *match_sets;
struct _dwell {
u16 passive;
u16 active;
u16 fragmented;
} dwell[IEEE80211_NUM_BANDS];
+ struct {
+ u8 iterations;
+ u8 full_scan_mul; /* not used for UMAC */
+ } schedule[2];
};
-enum iwl_umac_scan_uid_type {
- IWL_UMAC_SCAN_UID_REG_SCAN = BIT(0),
- IWL_UMAC_SCAN_UID_SCHED_SCAN = BIT(1),
- IWL_UMAC_SCAN_UID_ALL = IWL_UMAC_SCAN_UID_REG_SCAN |
- IWL_UMAC_SCAN_UID_SCHED_SCAN,
-};
-
-static int iwl_umac_scan_stop(struct iwl_mvm *mvm,
- enum iwl_umac_scan_uid_type type, bool notify);
-
static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm)
{
if (mvm->scan_rx_ant != ANT_NONE)
@@ -143,28 +148,6 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band,
}
/*
- * We insert the SSIDs in an inverted order, because the FW will
- * invert it back. The most prioritized SSID, which is first in the
- * request list, is not copied here, but inserted directly to the probe
- * request.
- */
-static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid,
- struct cfg80211_ssid *ssids,
- int n_ssids, int first)
-{
- int fw_idx, req_idx;
-
- for (req_idx = n_ssids - 1, fw_idx = 0; req_idx >= first;
- req_idx--, fw_idx++) {
- cmd_ssid[fw_idx].id = WLAN_EID_SSID;
- cmd_ssid[fw_idx].len = ssids[req_idx].ssid_len;
- memcpy(cmd_ssid[fw_idx].ssid,
- ssids[req_idx].ssid,
- ssids[req_idx].ssid_len);
- }
-}
-
-/*
* If req->n_ssids > 0, it means we should do an active scan.
* In case of active scan w/o directed scan, we receive a zero-length SSID
* just to notify that this scan is active and not passive.
@@ -177,7 +160,7 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid,
static u16 iwl_mvm_get_active_dwell(struct iwl_mvm *mvm,
enum ieee80211_band band, int n_ssids)
{
- if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BASIC_DWELL)
+ if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BASIC_DWELL))
return 10;
if (band == IEEE80211_BAND_2GHZ)
return 20 + 3 * (n_ssids + 1);
@@ -187,7 +170,7 @@ static u16 iwl_mvm_get_active_dwell(struct iwl_mvm *mvm,
static u16 iwl_mvm_get_passive_dwell(struct iwl_mvm *mvm,
enum ieee80211_band band)
{
- if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BASIC_DWELL)
+ if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BASIC_DWELL))
return 110;
return band == IEEE80211_BAND_2GHZ ? 100 + 20 : 100 + 10;
}
@@ -203,10 +186,9 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,
*global_cnt += 1;
}
-static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- int n_ssids, u32 flags,
- struct iwl_mvm_scan_params *params)
+static void iwl_mvm_scan_calc_dwell(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct iwl_mvm_scan_params *params)
{
int global_cnt = 0;
enum ieee80211_band band;
@@ -216,7 +198,6 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_scan_condition_iterator,
&global_cnt);
-
if (!global_cnt)
goto not_bound;
@@ -224,8 +205,9 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
params->max_out_time = 120;
if (iwl_mvm_low_latency(mvm)) {
- if (mvm->fw->ucode_capa.api[0] &
- IWL_UCODE_TLV_API_FRAGMENTED_SCAN) {
+ if (fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) {
+
params->suspend_time = 105;
/*
* If there is more than one active interface make
@@ -239,8 +221,9 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
}
}
- if (frag_passive_dwell && (mvm->fw->ucode_capa.api[0] &
- IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) {
+ if (frag_passive_dwell &&
+ fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) {
/*
* P2P device scan should not be fragmented to avoid negative
* impact on P2P device discovery. Configure max_out_time to be
@@ -257,7 +240,8 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
}
}
- if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
+ if ((params->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
+ (params->max_out_time > 200))
params->max_out_time = 200;
not_bound:
@@ -268,20 +252,34 @@ not_bound:
params->dwell[band].passive = iwl_mvm_get_passive_dwell(mvm,
band);
- params->dwell[band].active = iwl_mvm_get_active_dwell(mvm, band,
- n_ssids);
+ params->dwell[band].active =
+ iwl_mvm_get_active_dwell(mvm, band, params->n_ssids);
}
+
+ IWL_DEBUG_SCAN(mvm,
+ "scan parameters: max_out_time %d, suspend_time %d, passive_fragmented %d\n",
+ params->max_out_time, params->suspend_time,
+ params->passive_fragmented);
+ IWL_DEBUG_SCAN(mvm,
+ "dwell[IEEE80211_BAND_2GHZ]: passive %d, active %d, fragmented %d\n",
+ params->dwell[IEEE80211_BAND_2GHZ].passive,
+ params->dwell[IEEE80211_BAND_2GHZ].active,
+ params->dwell[IEEE80211_BAND_2GHZ].fragmented);
+ IWL_DEBUG_SCAN(mvm,
+ "dwell[IEEE80211_BAND_5GHZ]: passive %d, active %d, fragmented %d\n",
+ params->dwell[IEEE80211_BAND_5GHZ].passive,
+ params->dwell[IEEE80211_BAND_5GHZ].active,
+ params->dwell[IEEE80211_BAND_5GHZ].fragmented);
}
static inline bool iwl_mvm_rrm_scan_needed(struct iwl_mvm *mvm)
{
/* require rrm scan whenever the fw supports it */
- return mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT;
+ return fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT);
}
-static int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm,
- bool is_sched_scan)
+static int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm)
{
int max_probe_len;
@@ -297,9 +295,9 @@ static int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm,
return max_probe_len;
}
-int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan)
+int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm)
{
- int max_ie_len = iwl_mvm_max_scan_ie_fw_cmd_room(mvm, is_sched_scan);
+ int max_ie_len = iwl_mvm_max_scan_ie_fw_cmd_room(mvm);
/* TODO: [BUG] This function should return the maximum allowed size of
* scan IEs, however the LMAC scan api contains both 2GHZ and 5GHZ IEs
@@ -314,22 +312,41 @@ int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan)
return max_ie_len;
}
-int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd)
+static u8 *iwl_mvm_dump_channel_list(struct iwl_scan_results_notif *res,
+ int num_res, u8 *buf, size_t buf_size)
+{
+ int i;
+ u8 *pos = buf, *end = buf + buf_size;
+
+ for (i = 0; pos < end && i < num_res; i++)
+ pos += snprintf(pos, end - pos, " %u", res[i].channel);
+
+ /* terminate the string in case the buffer was too short */
+ *(buf + buf_size - 1) = '\0';
+
+ return buf;
+}
+
+int iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_lmac_scan_complete_notif *notif = (void *)pkt->data;
+ u8 buf[256];
IWL_DEBUG_SCAN(mvm,
- "Scan offload iteration complete: status=0x%x scanned channels=%d\n",
- notif->status, notif->scanned_channels);
+ "Scan offload iteration complete: status=0x%x scanned channels=%d channels list: %s\n",
+ notif->status, notif->scanned_channels,
+ iwl_mvm_dump_channel_list(notif->results,
+ notif->scanned_channels, buf,
+ sizeof(buf)));
return 0;
}
-int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd)
+int iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n");
ieee80211_sched_scan_results(mvm->hw);
@@ -337,41 +354,78 @@ int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
return 0;
}
-int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd)
+static const char *iwl_mvm_ebs_status_str(enum iwl_scan_ebs_status status)
{
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_periodic_scan_complete *scan_notif;
+ switch (status) {
+ case IWL_SCAN_EBS_SUCCESS:
+ return "successful";
+ case IWL_SCAN_EBS_INACTIVE:
+ return "inactive";
+ case IWL_SCAN_EBS_FAILED:
+ case IWL_SCAN_EBS_CHAN_NOT_FOUND:
+ default:
+ return "failed";
+ }
+}
- scan_notif = (void *)pkt->data;
+int iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_periodic_scan_complete *scan_notif = (void *)pkt->data;
+ bool aborted = (scan_notif->status == IWL_SCAN_OFFLOAD_ABORTED);
/* scan status must be locked for proper checking */
lockdep_assert_held(&mvm->mutex);
- IWL_DEBUG_SCAN(mvm,
- "%s completed, status %s, EBS status %s\n",
- mvm->scan_status == IWL_MVM_SCAN_SCHED ?
- "Scheduled scan" : "Scan",
- scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
- "completed" : "aborted",
- scan_notif->ebs_status == IWL_SCAN_EBS_SUCCESS ?
- "success" : "failed");
+ /* We first check if we were stopping a scan, in which case we
+ * just clear the stopping flag. Then we check if it was a
+ * firmware initiated stop, in which case we need to inform
+ * mac80211.
+ * Note that we can have a stopping and a running scan
+ * simultaneously, but we can't have two different types of
+ * scans stopping or running at the same time (since LMAC
+ * doesn't support it).
+ */
+
+ if (mvm->scan_status & IWL_MVM_SCAN_STOPPING_SCHED) {
+ WARN_ON_ONCE(mvm->scan_status & IWL_MVM_SCAN_STOPPING_REGULAR);
+
+ IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s\n",
+ aborted ? "aborted" : "completed",
+ iwl_mvm_ebs_status_str(scan_notif->ebs_status));
+ mvm->scan_status &= ~IWL_MVM_SCAN_STOPPING_SCHED;
+ } else if (mvm->scan_status & IWL_MVM_SCAN_STOPPING_REGULAR) {
+ IWL_DEBUG_SCAN(mvm, "Regular scan %s, EBS status %s\n",
+ aborted ? "aborted" : "completed",
+ iwl_mvm_ebs_status_str(scan_notif->ebs_status));
- /* only call mac80211 completion if the stop was initiated by FW */
- if (mvm->scan_status == IWL_MVM_SCAN_SCHED) {
- mvm->scan_status = IWL_MVM_SCAN_NONE;
+ mvm->scan_status &= ~IWL_MVM_SCAN_STOPPING_REGULAR;
+ } else if (mvm->scan_status & IWL_MVM_SCAN_SCHED) {
+ WARN_ON_ONCE(mvm->scan_status & IWL_MVM_SCAN_REGULAR);
+
+ IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s (FW)\n",
+ aborted ? "aborted" : "completed",
+ iwl_mvm_ebs_status_str(scan_notif->ebs_status));
+
+ mvm->scan_status &= ~IWL_MVM_SCAN_SCHED;
ieee80211_sched_scan_stopped(mvm->hw);
- } else if (mvm->scan_status == IWL_MVM_SCAN_OS) {
- mvm->scan_status = IWL_MVM_SCAN_NONE;
+ } else if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) {
+ IWL_DEBUG_SCAN(mvm, "Regular scan %s, EBS status %s (FW)\n",
+ aborted ? "aborted" : "completed",
+ iwl_mvm_ebs_status_str(scan_notif->ebs_status));
+
+ mvm->scan_status &= ~IWL_MVM_SCAN_REGULAR;
ieee80211_scan_completed(mvm->hw,
scan_notif->status == IWL_SCAN_OFFLOAD_ABORTED);
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
}
- if (scan_notif->ebs_status)
- mvm->last_ebs_successful = false;
+ mvm->last_ebs_successful =
+ scan_notif->ebs_status == IWL_SCAN_EBS_SUCCESS ||
+ scan_notif->ebs_status == IWL_SCAN_EBS_INACTIVE;
return 0;
}
@@ -390,9 +444,12 @@ static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list)
return -1;
}
-static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
- struct iwl_ssid_ie *direct_scan,
- u32 *ssid_bitmap, bool basic_ssid)
+/* We insert the SSIDs in an inverted order, because the FW will
+ * invert it back.
+ */
+static void iwl_scan_build_ssids(struct iwl_mvm_scan_params *params,
+ struct iwl_ssid_ie *ssids,
+ u32 *ssid_bitmap)
{
int i, j;
int index;
@@ -402,39 +459,41 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
* iwl_config_sched_scan_profiles() uses the order of these ssids to
* config match list.
*/
- for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) {
+ for (i = 0, j = params->n_match_sets - 1;
+ j >= 0 && i < PROBE_OPTION_MAX;
+ i++, j--) {
/* skip empty SSID matchsets */
- if (!req->match_sets[i].ssid.ssid_len)
+ if (!params->match_sets[j].ssid.ssid_len)
continue;
- direct_scan[i].id = WLAN_EID_SSID;
- direct_scan[i].len = req->match_sets[i].ssid.ssid_len;
- memcpy(direct_scan[i].ssid, req->match_sets[i].ssid.ssid,
- direct_scan[i].len);
+ ssids[i].id = WLAN_EID_SSID;
+ ssids[i].len = params->match_sets[j].ssid.ssid_len;
+ memcpy(ssids[i].ssid, params->match_sets[j].ssid.ssid,
+ ssids[i].len);
}
/* add SSIDs from scan SSID list */
*ssid_bitmap = 0;
- for (j = 0; j < req->n_ssids && i < PROBE_OPTION_MAX; j++) {
- index = iwl_ssid_exist(req->ssids[j].ssid,
- req->ssids[j].ssid_len,
- direct_scan);
+ for (j = params->n_ssids - 1;
+ j >= 0 && i < PROBE_OPTION_MAX;
+ i++, j--) {
+ index = iwl_ssid_exist(params->ssids[j].ssid,
+ params->ssids[j].ssid_len,
+ ssids);
if (index < 0) {
- if (!req->ssids[j].ssid_len && basic_ssid)
- continue;
- direct_scan[i].id = WLAN_EID_SSID;
- direct_scan[i].len = req->ssids[j].ssid_len;
- memcpy(direct_scan[i].ssid, req->ssids[j].ssid,
- direct_scan[i].len);
- *ssid_bitmap |= BIT(i + 1);
- i++;
+ ssids[i].id = WLAN_EID_SSID;
+ ssids[i].len = params->ssids[j].ssid_len;
+ memcpy(ssids[i].ssid, params->ssids[j].ssid,
+ ssids[i].len);
+ *ssid_bitmap |= BIT(i);
} else {
- *ssid_bitmap |= BIT(index + 1);
+ *ssid_bitmap |= BIT(index);
}
}
}
-int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
- struct cfg80211_sched_scan_request *req)
+static int
+iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
+ struct cfg80211_sched_scan_request *req)
{
struct iwl_scan_offload_profile *profile;
struct iwl_scan_offload_profile_cfg *profile_cfg;
@@ -515,30 +574,7 @@ static bool iwl_mvm_scan_pass_all(struct iwl_mvm *mvm,
return true;
}
-int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct cfg80211_sched_scan_request *req,
- struct ieee80211_scan_ies *ies)
-{
- int ret;
-
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
- ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
- if (ret)
- return ret;
- ret = iwl_mvm_sched_scan_umac(mvm, vif, req, ies);
- } else {
- mvm->scan_status = IWL_MVM_SCAN_SCHED;
- ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
- if (ret)
- return ret;
- ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
- }
-
- return ret;
-}
-
-static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm)
+static int iwl_mvm_lmac_scan_abort(struct iwl_mvm *mvm)
{
int ret;
struct iwl_host_cmd cmd = {
@@ -546,12 +582,6 @@ static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm)
};
u32 status;
- /* Exit instantly with error when device is not ready
- * to receive scan abort command or it does not perform
- * scheduled scan currently */
- if (mvm->scan_status == IWL_MVM_SCAN_NONE)
- return -EIO;
-
ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status);
if (ret)
return ret;
@@ -571,69 +601,9 @@ static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm)
return ret;
}
-int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
-{
- int ret;
- struct iwl_notification_wait wait_scan_done;
- static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, };
- bool sched = mvm->scan_status == IWL_MVM_SCAN_SCHED;
-
- lockdep_assert_held(&mvm->mutex);
-
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
- return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN,
- notify);
-
- if (mvm->scan_status == IWL_MVM_SCAN_NONE)
- return 0;
-
- if (iwl_mvm_is_radio_killed(mvm)) {
- ret = 0;
- goto out;
- }
-
- iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done,
- scan_done_notif,
- ARRAY_SIZE(scan_done_notif),
- NULL, NULL);
-
- ret = iwl_mvm_send_scan_offload_abort(mvm);
- if (ret) {
- IWL_DEBUG_SCAN(mvm, "Send stop %sscan failed %d\n",
- sched ? "offloaded " : "", ret);
- iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
- goto out;
- }
-
- IWL_DEBUG_SCAN(mvm, "Successfully sent stop %sscan\n",
- sched ? "offloaded " : "");
-
- ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
-out:
- /*
- * Clear the scan status so the next scan requests will succeed. This
- * also ensures the Rx handler doesn't do anything, as the scan was
- * stopped from above. Since the rx handler won't do anything now,
- * we have to release the scan reference here.
- */
- if (mvm->scan_status == IWL_MVM_SCAN_OS)
- iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
-
- mvm->scan_status = IWL_MVM_SCAN_NONE;
-
- if (notify) {
- if (sched)
- ieee80211_sched_scan_stopped(mvm->hw);
- else
- ieee80211_scan_completed(mvm->hw, true);
- }
-
- return ret;
-}
-
-static void iwl_mvm_unified_scan_fill_tx_cmd(struct iwl_mvm *mvm,
- struct iwl_scan_req_tx_cmd *tx_cmd,
- bool no_cck)
+static void iwl_mvm_scan_fill_tx_cmd(struct iwl_mvm *mvm,
+ struct iwl_scan_req_tx_cmd *tx_cmd,
+ bool no_cck)
{
tx_cmd[0].tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
TX_CMD_FLG_BT_DIS);
@@ -654,7 +624,7 @@ static void
iwl_mvm_lmac_scan_cfg_channels(struct iwl_mvm *mvm,
struct ieee80211_channel **channels,
int n_channels, u32 ssid_bitmap,
- struct iwl_scan_req_unified_lmac *cmd)
+ struct iwl_scan_req_lmac *cmd)
{
struct iwl_scan_channel_cfg_lmac *channel_cfg = (void *)&cmd->data;
int i;
@@ -707,13 +677,14 @@ static u8 *iwl_mvm_copy_and_insert_ds_elem(struct iwl_mvm *mvm, const u8 *ies,
}
static void
-iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct ieee80211_scan_ies *ies,
- struct iwl_scan_probe_req *preq,
- const u8 *mac_addr, const u8 *mac_addr_mask)
+iwl_mvm_build_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct ieee80211_scan_ies *ies,
+ struct iwl_mvm_scan_params *params)
{
- struct ieee80211_mgmt *frame = (struct ieee80211_mgmt *)preq->buf;
+ struct ieee80211_mgmt *frame = (void *)params->preq.buf;
u8 *pos, *newpos;
+ const u8 *mac_addr = params->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
+ params->mac_addr : NULL;
/*
* Unfortunately, right now the offload scan doesn't support randomising
@@ -722,7 +693,8 @@ iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
* random, only when it's restarted, but at least that helps a bit.
*/
if (mac_addr)
- get_random_mask_addr(frame->sa, mac_addr, mac_addr_mask);
+ get_random_mask_addr(frame->sa, mac_addr,
+ params->mac_addr_mask);
else
memcpy(frame->sa, vif->addr, ETH_ALEN);
@@ -735,245 +707,167 @@ iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
*pos++ = WLAN_EID_SSID;
*pos++ = 0;
- preq->mac_header.offset = 0;
- preq->mac_header.len = cpu_to_le16(24 + 2);
+ params->preq.mac_header.offset = 0;
+ params->preq.mac_header.len = cpu_to_le16(24 + 2);
/* Insert ds parameter set element on 2.4 GHz band */
newpos = iwl_mvm_copy_and_insert_ds_elem(mvm,
ies->ies[IEEE80211_BAND_2GHZ],
ies->len[IEEE80211_BAND_2GHZ],
pos);
- preq->band_data[0].offset = cpu_to_le16(pos - preq->buf);
- preq->band_data[0].len = cpu_to_le16(newpos - pos);
+ params->preq.band_data[0].offset = cpu_to_le16(pos - params->preq.buf);
+ params->preq.band_data[0].len = cpu_to_le16(newpos - pos);
pos = newpos;
memcpy(pos, ies->ies[IEEE80211_BAND_5GHZ],
ies->len[IEEE80211_BAND_5GHZ]);
- preq->band_data[1].offset = cpu_to_le16(pos - preq->buf);
- preq->band_data[1].len = cpu_to_le16(ies->len[IEEE80211_BAND_5GHZ]);
+ params->preq.band_data[1].offset = cpu_to_le16(pos - params->preq.buf);
+ params->preq.band_data[1].len =
+ cpu_to_le16(ies->len[IEEE80211_BAND_5GHZ]);
pos += ies->len[IEEE80211_BAND_5GHZ];
memcpy(pos, ies->common_ies, ies->common_ie_len);
- preq->common_data.offset = cpu_to_le16(pos - preq->buf);
- preq->common_data.len = cpu_to_le16(ies->common_ie_len);
+ params->preq.common_data.offset = cpu_to_le16(pos - params->preq.buf);
+ params->preq.common_data.len = cpu_to_le16(ies->common_ie_len);
}
-static void
-iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm,
- struct iwl_scan_req_unified_lmac *cmd,
- struct iwl_mvm_scan_params *params)
+static __le32 iwl_mvm_scan_priority(struct iwl_mvm *mvm,
+ enum iwl_scan_priority_ext prio)
+{
+ if (fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY))
+ return cpu_to_le32(prio);
+
+ if (prio <= IWL_SCAN_PRIORITY_EXT_2)
+ return cpu_to_le32(IWL_SCAN_PRIORITY_LOW);
+
+ if (prio <= IWL_SCAN_PRIORITY_EXT_4)
+ return cpu_to_le32(IWL_SCAN_PRIORITY_MEDIUM);
+
+ return cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
+}
+
+static void iwl_mvm_scan_lmac_dwell(struct iwl_mvm *mvm,
+ struct iwl_scan_req_lmac *cmd,
+ struct iwl_mvm_scan_params *params)
{
- memset(cmd, 0, ksize(cmd));
cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active;
cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive;
if (params->passive_fragmented)
cmd->fragmented_dwell =
params->dwell[IEEE80211_BAND_2GHZ].fragmented;
- cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm);
cmd->max_out_time = cpu_to_le32(params->max_out_time);
cmd->suspend_time = cpu_to_le32(params->suspend_time);
- cmd->scan_prio = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
- cmd->iter_num = cpu_to_le32(1);
-
- if (iwl_mvm_rrm_scan_needed(mvm))
- cmd->scan_flags |=
- cpu_to_le32(IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED);
+ cmd->scan_prio = iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
}
-int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_scan_request *req)
+static inline bool iwl_mvm_scan_fits(struct iwl_mvm *mvm, int n_ssids,
+ struct ieee80211_scan_ies *ies,
+ int n_channels)
{
- struct iwl_host_cmd hcmd = {
- .id = SCAN_OFFLOAD_REQUEST_CMD,
- .len = { sizeof(struct iwl_scan_req_unified_lmac) +
- sizeof(struct iwl_scan_channel_cfg_lmac) *
- mvm->fw->ucode_capa.n_scan_channels +
- sizeof(struct iwl_scan_probe_req), },
- .data = { mvm->scan_cmd, },
- .dataflags = { IWL_HCMD_DFL_NOCOPY, },
- };
- struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd;
- struct iwl_scan_probe_req *preq;
- struct iwl_mvm_scan_params params = {};
- u32 flags;
- u32 ssid_bitmap = 0;
- int ret, i;
-
- lockdep_assert_held(&mvm->mutex);
-
- /* we should have failed registration if scan_cmd was NULL */
- if (WARN_ON(mvm->scan_cmd == NULL))
- return -ENOMEM;
-
- if (req->req.n_ssids > PROBE_OPTION_MAX ||
- req->ies.common_ie_len + req->ies.len[NL80211_BAND_2GHZ] +
- req->ies.len[NL80211_BAND_5GHZ] >
- iwl_mvm_max_scan_ie_fw_cmd_room(mvm, false) ||
- req->req.n_channels > mvm->fw->ucode_capa.n_scan_channels)
- return -ENOBUFS;
+ return ((n_ssids <= PROBE_OPTION_MAX) &&
+ (n_channels <= mvm->fw->ucode_capa.n_scan_channels) &
+ (ies->common_ie_len +
+ ies->len[NL80211_BAND_2GHZ] +
+ ies->len[NL80211_BAND_5GHZ] <=
+ iwl_mvm_max_scan_ie_fw_cmd_room(mvm)));
+}
- mvm->scan_status = IWL_MVM_SCAN_OS;
+static inline bool iwl_mvm_scan_use_ebs(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ int n_iterations)
+{
+ const struct iwl_ucode_capabilities *capa = &mvm->fw->ucode_capa;
- iwl_mvm_scan_calc_params(mvm, vif, req->req.n_ssids, req->req.flags,
- &params);
+ /* We can only use EBS if:
+ * 1. the feature is supported;
+ * 2. the last EBS was successful;
+ * 3. if only single scan, the single scan EBS API is supported;
+ * 4. it's not a p2p find operation.
+ */
+ return ((capa->flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) &&
+ mvm->last_ebs_successful &&
+ (n_iterations > 1 ||
+ fw_has_api(capa, IWL_UCODE_TLV_API_SINGLE_SCAN_EBS)) &&
+ vif->type != NL80211_IFTYPE_P2P_DEVICE);
+}
- iwl_mvm_build_generic_unified_scan_cmd(mvm, cmd, &params);
+static int iwl_mvm_scan_total_iterations(struct iwl_mvm_scan_params *params)
+{
+ return params->schedule[0].iterations + params->schedule[1].iterations;
+}
- cmd->n_channels = (u8)req->req.n_channels;
+static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm,
+ struct iwl_mvm_scan_params *params)
+{
+ int flags = 0;
- flags = IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL;
+ if (params->n_ssids == 0)
+ flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE;
- if (req->req.n_ssids == 1 && req->req.ssids[0].ssid_len != 0)
+ if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0)
flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION;
- if (params.passive_fragmented)
+ if (params->passive_fragmented)
flags |= IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED;
- if (req->req.n_ssids == 0)
- flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE;
-
- cmd->scan_flags |= cpu_to_le32(flags);
-
- cmd->flags = iwl_mvm_scan_rxon_flags(req->req.channels[0]->band);
- cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
- MAC_FILTER_IN_BEACON);
- iwl_mvm_unified_scan_fill_tx_cmd(mvm, cmd->tx_cmd, req->req.no_cck);
- iwl_mvm_scan_fill_ssids(cmd->direct_scan, req->req.ssids,
- req->req.n_ssids, 0);
-
- cmd->schedule[0].delay = 0;
- cmd->schedule[0].iterations = 1;
- cmd->schedule[0].full_scan_mul = 0;
- cmd->schedule[1].delay = 0;
- cmd->schedule[1].iterations = 0;
- cmd->schedule[1].full_scan_mul = 0;
-
- if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SINGLE_SCAN_EBS &&
- mvm->last_ebs_successful) {
- cmd->channel_opt[0].flags =
- cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
- IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
- IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
- cmd->channel_opt[0].non_ebs_ratio =
- cpu_to_le16(IWL_DENSE_EBS_SCAN_RATIO);
- cmd->channel_opt[1].flags =
- cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
- IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
- IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
- cmd->channel_opt[1].non_ebs_ratio =
- cpu_to_le16(IWL_SPARSE_EBS_SCAN_RATIO);
- }
-
- for (i = 1; i <= req->req.n_ssids; i++)
- ssid_bitmap |= BIT(i);
-
- iwl_mvm_lmac_scan_cfg_channels(mvm, req->req.channels,
- req->req.n_channels, ssid_bitmap,
- cmd);
+ if (iwl_mvm_rrm_scan_needed(mvm))
+ flags |= IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED;
- preq = (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) *
- mvm->fw->ucode_capa.n_scan_channels);
+ if (params->pass_all)
+ flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL;
+ else
+ flags |= IWL_MVM_LMAC_SCAN_FLAG_MATCH;
- iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, preq,
- req->req.flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
- req->req.mac_addr : NULL,
- req->req.mac_addr_mask);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ if (mvm->scan_iter_notif_enabled)
+ flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE;
+#endif
- ret = iwl_mvm_send_cmd(mvm, &hcmd);
- if (!ret) {
- IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
- } else {
- /*
- * If the scan failed, it usually means that the FW was unable
- * to allocate the time events. Warn on it, but maybe we
- * should try to send the command again with different params.
- */
- IWL_ERR(mvm, "Scan failed! ret %d\n", ret);
- mvm->scan_status = IWL_MVM_SCAN_NONE;
- ret = -EIO;
- }
- return ret;
+ return flags;
}
-int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct cfg80211_sched_scan_request *req,
- struct ieee80211_scan_ies *ies)
+static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_mvm_scan_params *params)
{
- struct iwl_host_cmd hcmd = {
- .id = SCAN_OFFLOAD_REQUEST_CMD,
- .len = { sizeof(struct iwl_scan_req_unified_lmac) +
- sizeof(struct iwl_scan_channel_cfg_lmac) *
- mvm->fw->ucode_capa.n_scan_channels +
- sizeof(struct iwl_scan_probe_req), },
- .data = { mvm->scan_cmd, },
- .dataflags = { IWL_HCMD_DFL_NOCOPY, },
- };
- struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd;
- struct iwl_scan_probe_req *preq;
- struct iwl_mvm_scan_params params = {};
- int ret;
- u32 flags = 0, ssid_bitmap = 0;
+ struct iwl_scan_req_lmac *cmd = mvm->scan_cmd;
+ struct iwl_scan_probe_req *preq =
+ (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) *
+ mvm->fw->ucode_capa.n_scan_channels);
+ u32 ssid_bitmap = 0;
+ int n_iterations = iwl_mvm_scan_total_iterations(params);
lockdep_assert_held(&mvm->mutex);
- /* we should have failed registration if scan_cmd was NULL */
- if (WARN_ON(mvm->scan_cmd == NULL))
- return -ENOMEM;
-
- if (req->n_ssids > PROBE_OPTION_MAX ||
- ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] +
- ies->len[NL80211_BAND_5GHZ] >
- iwl_mvm_max_scan_ie_fw_cmd_room(mvm, true) ||
- req->n_channels > mvm->fw->ucode_capa.n_scan_channels)
- return -ENOBUFS;
-
- iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, 0, &params);
-
- iwl_mvm_build_generic_unified_scan_cmd(mvm, cmd, &params);
-
- cmd->n_channels = (u8)req->n_channels;
-
- cmd->delay = cpu_to_le32(req->delay);
-
- if (iwl_mvm_scan_pass_all(mvm, req))
- flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL;
- else
- flags |= IWL_MVM_LMAC_SCAN_FLAG_MATCH;
+ memset(cmd, 0, ksize(cmd));
- if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0)
- flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION;
+ iwl_mvm_scan_lmac_dwell(mvm, cmd, params);
- if (params.passive_fragmented)
- flags |= IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED;
-
- if (req->n_ssids == 0)
- flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE;
+ cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm);
+ cmd->iter_num = cpu_to_le32(1);
+ cmd->n_channels = (u8)params->n_channels;
-#ifdef CONFIG_IWLWIFI_DEBUGFS
- if (mvm->scan_iter_notif_enabled)
- flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE;
-#endif
+ cmd->delay = cpu_to_le32(params->delay);
- cmd->scan_flags |= cpu_to_le32(flags);
+ cmd->scan_flags = cpu_to_le32(iwl_mvm_scan_lmac_flags(mvm, params));
- cmd->flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band);
+ cmd->flags = iwl_mvm_scan_rxon_flags(params->channels[0]->band);
cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
MAC_FILTER_IN_BEACON);
- iwl_mvm_unified_scan_fill_tx_cmd(mvm, cmd->tx_cmd, false);
- iwl_scan_offload_build_ssid(req, cmd->direct_scan, &ssid_bitmap, false);
+ iwl_mvm_scan_fill_tx_cmd(mvm, cmd->tx_cmd, params->no_cck);
+ iwl_scan_build_ssids(params, cmd->direct_scan, &ssid_bitmap);
- cmd->schedule[0].delay = cpu_to_le16(req->interval / MSEC_PER_SEC);
- cmd->schedule[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS;
- cmd->schedule[0].full_scan_mul = 1;
+ /* this API uses bits 1-20 instead of 0-19 */
+ ssid_bitmap <<= 1;
- cmd->schedule[1].delay = cpu_to_le16(req->interval / MSEC_PER_SEC);
- cmd->schedule[1].iterations = 0xff;
- cmd->schedule[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER;
+ cmd->schedule[0].delay = cpu_to_le16(params->interval);
+ cmd->schedule[0].iterations = params->schedule[0].iterations;
+ cmd->schedule[0].full_scan_mul = params->schedule[0].full_scan_mul;
+ cmd->schedule[1].delay = cpu_to_le16(params->interval);
+ cmd->schedule[1].iterations = params->schedule[1].iterations;
+ cmd->schedule[1].full_scan_mul = params->schedule[1].iterations;
- if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT &&
- mvm->last_ebs_successful) {
+ if (iwl_mvm_scan_use_ebs(mvm, vif, n_iterations)) {
cmd->channel_opt[0].flags =
cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
@@ -988,61 +882,14 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
cpu_to_le16(IWL_SPARSE_EBS_SCAN_RATIO);
}
- iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels,
- ssid_bitmap, cmd);
-
- preq = (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) *
- mvm->fw->ucode_capa.n_scan_channels);
+ iwl_mvm_lmac_scan_cfg_channels(mvm, params->channels,
+ params->n_channels, ssid_bitmap, cmd);
- iwl_mvm_build_unified_scan_probe(mvm, vif, ies, preq,
- req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
- req->mac_addr : NULL,
- req->mac_addr_mask);
+ *preq = params->preq;
- ret = iwl_mvm_send_cmd(mvm, &hcmd);
- if (!ret) {
- IWL_DEBUG_SCAN(mvm,
- "Sched scan request was sent successfully\n");
- } else {
- /*
- * If the scan failed, it usually means that the FW was unable
- * to allocate the time events. Warn on it, but maybe we
- * should try to send the command again with different params.
- */
- IWL_ERR(mvm, "Sched scan failed! ret %d\n", ret);
- mvm->scan_status = IWL_MVM_SCAN_NONE;
- ret = -EIO;
- }
- return ret;
-}
-
-
-int iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
-{
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
- return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_REG_SCAN,
- true);
-
- if (mvm->scan_status == IWL_MVM_SCAN_NONE)
- return 0;
-
- if (iwl_mvm_is_radio_killed(mvm)) {
- ieee80211_scan_completed(mvm->hw, true);
- iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
- mvm->scan_status = IWL_MVM_SCAN_NONE;
- return 0;
- }
-
- return iwl_mvm_scan_offload_stop(mvm, true);
+ return 0;
}
-/* UMAC scan API */
-
-struct iwl_umac_scan_done {
- struct iwl_mvm *mvm;
- enum iwl_umac_scan_uid_type type;
-};
-
static int rate_to_scan_rate_flag(unsigned int rate)
{
static const int rate_to_scan_rate[IWL_RATE_COUNT] = {
@@ -1151,79 +998,21 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)
return ret;
}
-static int iwl_mvm_find_scan_uid(struct iwl_mvm *mvm, u32 uid)
-{
- int i;
-
- for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++)
- if (mvm->scan_uid[i] == uid)
- return i;
-
- return i;
-}
-
-static int iwl_mvm_find_free_scan_uid(struct iwl_mvm *mvm)
-{
- return iwl_mvm_find_scan_uid(mvm, 0);
-}
-
-static bool iwl_mvm_find_scan_type(struct iwl_mvm *mvm,
- enum iwl_umac_scan_uid_type type)
-{
- int i;
-
- for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++)
- if (mvm->scan_uid[i] & type)
- return true;
-
- return false;
-}
-
-static int iwl_mvm_find_first_scan(struct iwl_mvm *mvm,
- enum iwl_umac_scan_uid_type type)
+static int iwl_mvm_scan_uid_by_status(struct iwl_mvm *mvm, int status)
{
int i;
- for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++)
- if (mvm->scan_uid[i] & type)
+ for (i = 0; i < mvm->max_scans; i++)
+ if (mvm->scan_uid_status[i] == status)
return i;
- return i;
+ return -ENOENT;
}
-static u32 iwl_generate_scan_uid(struct iwl_mvm *mvm,
- enum iwl_umac_scan_uid_type type)
-{
- u32 uid;
-
- /* make sure exactly one bit is on in scan type */
- WARN_ON(hweight8(type) != 1);
-
- /*
- * Make sure scan uids are unique. If one scan lasts long time while
- * others are completing frequently, the seq number will wrap up and
- * we may have more than one scan with the same uid.
- */
- do {
- uid = type | (mvm->scan_seq_num <<
- IWL_UMAC_SCAN_UID_SEQ_OFFSET);
- mvm->scan_seq_num++;
- } while (iwl_mvm_find_scan_uid(mvm, uid) <
- IWL_MVM_MAX_SIMULTANEOUS_SCANS);
-
- IWL_DEBUG_SCAN(mvm, "Generated scan UID %u\n", uid);
-
- return uid;
-}
-
-static void
-iwl_mvm_build_generic_umac_scan_cmd(struct iwl_mvm *mvm,
+static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
struct iwl_scan_req_umac *cmd,
struct iwl_mvm_scan_params *params)
{
- memset(cmd, 0, ksize(cmd));
- cmd->hdr.size = cpu_to_le16(iwl_mvm_scan_size(mvm) -
- sizeof(struct iwl_mvm_umac_cmd_hdr));
cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active;
cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive;
if (params->passive_fragmented)
@@ -1231,7 +1020,15 @@ iwl_mvm_build_generic_umac_scan_cmd(struct iwl_mvm *mvm,
params->dwell[IEEE80211_BAND_2GHZ].fragmented;
cmd->max_out_time = cpu_to_le32(params->max_out_time);
cmd->suspend_time = cpu_to_le32(params->suspend_time);
- cmd->scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
+ cmd->scan_priority =
+ iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
+
+ if (iwl_mvm_scan_total_iterations(params) == 0)
+ cmd->ooc_priority =
+ iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
+ else
+ cmd->ooc_priority =
+ iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_2);
}
static void
@@ -1251,230 +1048,326 @@ iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm,
}
}
-static u32 iwl_mvm_scan_umac_common_flags(struct iwl_mvm *mvm, int n_ssids,
- struct cfg80211_ssid *ssids,
- int fragmented)
+static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
+ struct iwl_mvm_scan_params *params)
{
int flags = 0;
- if (n_ssids == 0)
+ if (params->n_ssids == 0)
flags = IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE;
- if (n_ssids == 1 && ssids[0].ssid_len != 0)
+ if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT;
- if (fragmented)
+ if (params->passive_fragmented)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED;
if (iwl_mvm_rrm_scan_needed(mvm))
flags |= IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED;
+ if (params->pass_all)
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL;
+ else
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_MATCH;
+
+ if (iwl_mvm_scan_total_iterations(params) > 1)
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ if (mvm->scan_iter_notif_enabled)
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE;
+#endif
return flags;
}
-int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct ieee80211_scan_request *req)
+static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_mvm_scan_params *params,
+ int type)
{
- struct iwl_host_cmd hcmd = {
- .id = SCAN_REQ_UMAC,
- .len = { iwl_mvm_scan_size(mvm), },
- .data = { mvm->scan_cmd, },
- .dataflags = { IWL_HCMD_DFL_NOCOPY, },
- };
struct iwl_scan_req_umac *cmd = mvm->scan_cmd;
struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data +
sizeof(struct iwl_scan_channel_cfg_umac) *
mvm->fw->ucode_capa.n_scan_channels;
- struct iwl_mvm_scan_params params = {};
- u32 uid, flags;
+ int uid;
u32 ssid_bitmap = 0;
- int ret, i, uid_idx;
+ int n_iterations = iwl_mvm_scan_total_iterations(params);
lockdep_assert_held(&mvm->mutex);
- uid_idx = iwl_mvm_find_free_scan_uid(mvm);
- if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
- return -EBUSY;
+ uid = iwl_mvm_scan_uid_by_status(mvm, 0);
+ if (uid < 0)
+ return uid;
- /* we should have failed registration if scan_cmd was NULL */
- if (WARN_ON(mvm->scan_cmd == NULL))
- return -ENOMEM;
-
- if (WARN_ON(req->req.n_ssids > PROBE_OPTION_MAX ||
- req->ies.common_ie_len +
- req->ies.len[NL80211_BAND_2GHZ] +
- req->ies.len[NL80211_BAND_5GHZ] + 24 + 2 >
- SCAN_OFFLOAD_PROBE_REQ_SIZE || req->req.n_channels >
- mvm->fw->ucode_capa.n_scan_channels))
- return -ENOBUFS;
+ memset(cmd, 0, ksize(cmd));
+ cmd->hdr.size = cpu_to_le16(iwl_mvm_scan_size(mvm) -
+ sizeof(struct iwl_mvm_umac_cmd_hdr));
- iwl_mvm_scan_calc_params(mvm, vif, req->req.n_ssids, req->req.flags,
- &params);
+ iwl_mvm_scan_umac_dwell(mvm, cmd, params);
- iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, &params);
+ mvm->scan_uid_status[uid] = type;
- uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_REG_SCAN);
- mvm->scan_uid[uid_idx] = uid;
cmd->uid = cpu_to_le32(uid);
+ cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params));
- cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
-
- flags = iwl_mvm_scan_umac_common_flags(mvm, req->req.n_ssids,
- req->req.ssids,
- params.passive_fragmented);
-
- flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL;
-
- cmd->general_flags = cpu_to_le32(flags);
-
- if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SINGLE_SCAN_EBS &&
- mvm->last_ebs_successful)
+ if (iwl_mvm_scan_use_ebs(mvm, vif, n_iterations))
cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS |
IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
IWL_SCAN_CHANNEL_FLAG_CACHE_ADD;
- cmd->n_channels = req->req.n_channels;
+ cmd->n_channels = params->n_channels;
+
+ iwl_scan_build_ssids(params, sec_part->direct_scan, &ssid_bitmap);
- for (i = 0; i < req->req.n_ssids; i++)
- ssid_bitmap |= BIT(i);
+ iwl_mvm_umac_scan_cfg_channels(mvm, params->channels,
+ params->n_channels, ssid_bitmap, cmd);
- iwl_mvm_umac_scan_cfg_channels(mvm, req->req.channels,
- req->req.n_channels, ssid_bitmap, cmd);
+ /* With UMAC we use only one schedule for now, so use the sum
+ * of the iterations (with a a maximum of 255).
+ */
+ sec_part->schedule[0].iter_count =
+ (n_iterations > 255) ? 255 : n_iterations;
+ sec_part->schedule[0].interval = cpu_to_le16(params->interval);
- sec_part->schedule[0].iter_count = 1;
- sec_part->delay = 0;
+ sec_part->delay = cpu_to_le16(params->delay);
+ sec_part->preq = params->preq;
- iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, &sec_part->preq,
- req->req.flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
- req->req.mac_addr : NULL,
- req->req.mac_addr_mask);
+ return 0;
+}
- iwl_mvm_scan_fill_ssids(sec_part->direct_scan, req->req.ssids,
- req->req.n_ssids, 0);
+static int iwl_mvm_num_scans(struct iwl_mvm *mvm)
+{
+ return hweight32(mvm->scan_status & IWL_MVM_SCAN_MASK);
+}
- ret = iwl_mvm_send_cmd(mvm, &hcmd);
- if (!ret) {
- IWL_DEBUG_SCAN(mvm,
- "Scan request was sent successfully\n");
- } else {
- /*
- * If the scan failed, it usually means that the FW was unable
- * to allocate the time events. Warn on it, but maybe we
- * should try to send the command again with different params.
- */
- IWL_ERR(mvm, "Scan failed! ret %d\n", ret);
+static int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type)
+{
+ /* This looks a bit arbitrary, but the idea is that if we run
+ * out of possible simultaneous scans and the userspace is
+ * trying to run a scan type that is already running, we
+ * return -EBUSY. But if the userspace wants to start a
+ * different type of scan, we stop the opposite type to make
+ * space for the new request. The reason is backwards
+ * compatibility with old wpa_supplicant that wouldn't stop a
+ * scheduled scan before starting a normal scan.
+ */
+
+ if (iwl_mvm_num_scans(mvm) < mvm->max_scans)
+ return 0;
+
+ /* Use a switch, even though this is a bitmask, so that more
+ * than one bits set will fall in default and we will warn.
+ */
+ switch (type) {
+ case IWL_MVM_SCAN_REGULAR:
+ if (mvm->scan_status & IWL_MVM_SCAN_REGULAR_MASK)
+ return -EBUSY;
+ return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true);
+ case IWL_MVM_SCAN_SCHED:
+ if (mvm->scan_status & IWL_MVM_SCAN_SCHED_MASK)
+ return -EBUSY;
+ iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true);
+ case IWL_MVM_SCAN_NETDETECT:
+ /* No need to stop anything for net-detect since the
+ * firmware is restarted anyway. This way, any sched
+ * scans that were running will be restarted when we
+ * resume.
+ */
+ return 0;
+ default:
+ WARN_ON(1);
+ break;
}
- return ret;
+
+ return -EIO;
}
-int iwl_mvm_sched_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct cfg80211_sched_scan_request *req,
- struct ieee80211_scan_ies *ies)
+int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct cfg80211_scan_request *req,
+ struct ieee80211_scan_ies *ies)
{
-
struct iwl_host_cmd hcmd = {
- .id = SCAN_REQ_UMAC,
.len = { iwl_mvm_scan_size(mvm), },
.data = { mvm->scan_cmd, },
.dataflags = { IWL_HCMD_DFL_NOCOPY, },
};
- struct iwl_scan_req_umac *cmd = mvm->scan_cmd;
- struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data +
- sizeof(struct iwl_scan_channel_cfg_umac) *
- mvm->fw->ucode_capa.n_scan_channels;
struct iwl_mvm_scan_params params = {};
- u32 uid, flags;
- u32 ssid_bitmap = 0;
- int ret, uid_idx;
+ int ret;
lockdep_assert_held(&mvm->mutex);
- uid_idx = iwl_mvm_find_free_scan_uid(mvm);
- if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
+ if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
+ IWL_ERR(mvm, "scan while LAR regdomain is not set\n");
return -EBUSY;
+ }
+
+ ret = iwl_mvm_check_running_scans(mvm, IWL_MVM_SCAN_REGULAR);
+ if (ret)
+ return ret;
+
+ iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN);
/* we should have failed registration if scan_cmd was NULL */
- if (WARN_ON(mvm->scan_cmd == NULL))
+ if (WARN_ON(!mvm->scan_cmd))
return -ENOMEM;
- if (WARN_ON(req->n_ssids > PROBE_OPTION_MAX ||
- ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] +
- ies->len[NL80211_BAND_5GHZ] + 24 + 2 >
- SCAN_OFFLOAD_PROBE_REQ_SIZE || req->n_channels >
- mvm->fw->ucode_capa.n_scan_channels))
+ if (!iwl_mvm_scan_fits(mvm, req->n_ssids, ies, req->n_channels))
return -ENOBUFS;
- iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, req->flags,
- &params);
-
- iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, &params);
-
- cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE);
-
- uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN);
- mvm->scan_uid[uid_idx] = uid;
- cmd->uid = cpu_to_le32(uid);
+ params.n_ssids = req->n_ssids;
+ params.flags = req->flags;
+ params.n_channels = req->n_channels;
+ params.delay = 0;
+ params.interval = 0;
+ params.ssids = req->ssids;
+ params.channels = req->channels;
+ params.mac_addr = req->mac_addr;
+ params.mac_addr_mask = req->mac_addr_mask;
+ params.no_cck = req->no_cck;
+ params.pass_all = true;
+ params.n_match_sets = 0;
+ params.match_sets = NULL;
+
+ params.schedule[0].iterations = 1;
+ params.schedule[0].full_scan_mul = 0;
+ params.schedule[1].iterations = 0;
+ params.schedule[1].full_scan_mul = 0;
+
+ iwl_mvm_scan_calc_dwell(mvm, vif, &params);
+
+ iwl_mvm_build_scan_probe(mvm, vif, ies, &params);
+
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
+ hcmd.id = SCAN_REQ_UMAC;
+ ret = iwl_mvm_scan_umac(mvm, vif, &params,
+ IWL_MVM_SCAN_REGULAR);
+ } else {
+ hcmd.id = SCAN_OFFLOAD_REQUEST_CMD;
+ ret = iwl_mvm_scan_lmac(mvm, vif, &params);
+ }
- cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_LOW);
+ if (ret)
+ return ret;
- flags = iwl_mvm_scan_umac_common_flags(mvm, req->n_ssids, req->ssids,
- params.passive_fragmented);
+ ret = iwl_mvm_send_cmd(mvm, &hcmd);
+ if (!ret) {
+ IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
+ mvm->scan_status |= IWL_MVM_SCAN_REGULAR;
+ } else {
+ /* If the scan failed, it usually means that the FW was unable
+ * to allocate the time events. Warn on it, but maybe we
+ * should try to send the command again with different params.
+ */
+ IWL_ERR(mvm, "Scan failed! ret %d\n", ret);
+ }
- flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC;
+ if (ret)
+ iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
- if (iwl_mvm_scan_pass_all(mvm, req))
- flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL;
- else
- flags |= IWL_UMAC_SCAN_GEN_FLAGS_MATCH;
+ return ret;
+}
- cmd->general_flags = cpu_to_le32(flags);
+int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_scan_ies *ies,
+ int type)
+{
+ struct iwl_host_cmd hcmd = {
+ .len = { iwl_mvm_scan_size(mvm), },
+ .data = { mvm->scan_cmd, },
+ .dataflags = { IWL_HCMD_DFL_NOCOPY, },
+ };
+ struct iwl_mvm_scan_params params = {};
+ int ret;
- if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT &&
- mvm->last_ebs_successful)
- cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS |
- IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
- IWL_SCAN_CHANNEL_FLAG_CACHE_ADD;
+ lockdep_assert_held(&mvm->mutex);
- cmd->n_channels = req->n_channels;
+ if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
+ IWL_ERR(mvm, "sched-scan while LAR regdomain is not set\n");
+ return -EBUSY;
+ }
- iwl_scan_offload_build_ssid(req, sec_part->direct_scan, &ssid_bitmap,
- false);
+ ret = iwl_mvm_check_running_scans(mvm, type);
+ if (ret)
+ return ret;
- /* This API uses bits 0-19 instead of 1-20. */
- ssid_bitmap = ssid_bitmap >> 1;
+ /* we should have failed registration if scan_cmd was NULL */
+ if (WARN_ON(!mvm->scan_cmd))
+ return -ENOMEM;
- iwl_mvm_umac_scan_cfg_channels(mvm, req->channels, req->n_channels,
- ssid_bitmap, cmd);
+ if (!iwl_mvm_scan_fits(mvm, req->n_ssids, ies, req->n_channels))
+ return -ENOBUFS;
- sec_part->schedule[0].interval =
- cpu_to_le16(req->interval / MSEC_PER_SEC);
- sec_part->schedule[0].iter_count = 0xff;
+ params.n_ssids = req->n_ssids;
+ params.flags = req->flags;
+ params.n_channels = req->n_channels;
+ params.ssids = req->ssids;
+ params.channels = req->channels;
+ params.mac_addr = req->mac_addr;
+ params.mac_addr_mask = req->mac_addr_mask;
+ params.no_cck = false;
+ params.pass_all = iwl_mvm_scan_pass_all(mvm, req);
+ params.n_match_sets = req->n_match_sets;
+ params.match_sets = req->match_sets;
+
+ params.schedule[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS;
+ params.schedule[0].full_scan_mul = 1;
+ params.schedule[1].iterations = 0xff;
+ params.schedule[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER;
+
+ if (req->interval > U16_MAX) {
+ IWL_DEBUG_SCAN(mvm,
+ "interval value is > 16-bits, set to max possible\n");
+ params.interval = U16_MAX;
+ } else {
+ params.interval = req->interval / MSEC_PER_SEC;
+ }
+ /* In theory, LMAC scans can handle a 32-bit delay, but since
+ * waiting for over 18 hours to start the scan is a bit silly
+ * and to keep it aligned with UMAC scans (which only support
+ * 16-bit delays), trim it down to 16-bits.
+ */
if (req->delay > U16_MAX) {
IWL_DEBUG_SCAN(mvm,
"delay value is > 16-bits, set to max possible\n");
- sec_part->delay = cpu_to_le16(U16_MAX);
+ params.delay = U16_MAX;
+ } else {
+ params.delay = req->delay;
+ }
+
+ iwl_mvm_scan_calc_dwell(mvm, vif, &params);
+
+ ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
+ if (ret)
+ return ret;
+
+ iwl_mvm_build_scan_probe(mvm, vif, ies, &params);
+
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
+ hcmd.id = SCAN_REQ_UMAC;
+ ret = iwl_mvm_scan_umac(mvm, vif, &params, IWL_MVM_SCAN_SCHED);
} else {
- sec_part->delay = cpu_to_le16(req->delay);
+ hcmd.id = SCAN_OFFLOAD_REQUEST_CMD;
+ ret = iwl_mvm_scan_lmac(mvm, vif, &params);
}
- iwl_mvm_build_unified_scan_probe(mvm, vif, ies, &sec_part->preq,
- req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
- req->mac_addr : NULL,
- req->mac_addr_mask);
+ if (ret)
+ return ret;
ret = iwl_mvm_send_cmd(mvm, &hcmd);
if (!ret) {
IWL_DEBUG_SCAN(mvm,
"Sched scan request was sent successfully\n");
+ mvm->scan_status |= type;
} else {
- /*
- * If the scan failed, it usually means that the FW was unable
+ /* If the scan failed, it usually means that the FW was unable
* to allocate the time events. Warn on it, but maybe we
* should try to send the command again with different params.
*/
IWL_ERR(mvm, "Sched scan failed! ret %d\n", ret);
}
+
return ret;
}
@@ -1485,150 +1378,124 @@ int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_umac_scan_complete *notif = (void *)pkt->data;
u32 uid = __le32_to_cpu(notif->uid);
- bool sched = !!(uid & IWL_UMAC_SCAN_UID_SCHED_SCAN);
- int uid_idx = iwl_mvm_find_scan_uid(mvm, uid);
+ bool aborted = (notif->status == IWL_SCAN_OFFLOAD_ABORTED);
- /*
- * Scan uid may be set to zero in case of scan abort request from above.
- */
- if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
+ if (WARN_ON(!(mvm->scan_uid_status[uid] & mvm->scan_status)))
return 0;
+ /* if the scan is already stopping, we don't need to notify mac80211 */
+ if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_REGULAR) {
+ ieee80211_scan_completed(mvm->hw, aborted);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
+ } else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) {
+ ieee80211_sched_scan_stopped(mvm->hw);
+ }
+
+ mvm->scan_status &= ~mvm->scan_uid_status[uid];
+
IWL_DEBUG_SCAN(mvm,
- "Scan completed, uid %u type %s, status %s, EBS status %s\n",
- uid, sched ? "sched" : "regular",
+ "Scan completed, uid %u type %u, status %s, EBS status %s\n",
+ uid, mvm->scan_uid_status[uid],
notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
"completed" : "aborted",
- notif->ebs_status == IWL_SCAN_EBS_SUCCESS ?
- "success" : "failed");
+ iwl_mvm_ebs_status_str(notif->ebs_status));
- if (notif->ebs_status)
+ if (notif->ebs_status != IWL_SCAN_EBS_SUCCESS &&
+ notif->ebs_status != IWL_SCAN_EBS_INACTIVE)
mvm->last_ebs_successful = false;
- mvm->scan_uid[uid_idx] = 0;
-
- if (!sched) {
- ieee80211_scan_completed(mvm->hw,
- notif->status ==
- IWL_SCAN_OFFLOAD_ABORTED);
- iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
- } else if (!iwl_mvm_find_scan_type(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN)) {
- ieee80211_sched_scan_stopped(mvm->hw);
- } else {
- IWL_DEBUG_SCAN(mvm, "Another sched scan is running\n");
- }
+ mvm->scan_uid_status[uid] = 0;
return 0;
}
-static bool iwl_scan_umac_done_check(struct iwl_notif_wait_data *notif_wait,
- struct iwl_rx_packet *pkt, void *data)
+int iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
- struct iwl_umac_scan_done *scan_done = data;
- struct iwl_umac_scan_complete *notif = (void *)pkt->data;
- u32 uid = __le32_to_cpu(notif->uid);
- int uid_idx = iwl_mvm_find_scan_uid(scan_done->mvm, uid);
-
- if (WARN_ON(pkt->hdr.cmd != SCAN_COMPLETE_UMAC))
- return false;
-
- if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
- return false;
-
- /*
- * Clear scan uid of scans that was aborted from above and completed
- * in FW so the RX handler does nothing. Set last_ebs_successful here if
- * needed.
- */
- scan_done->mvm->scan_uid[uid_idx] = 0;
-
- if (notif->ebs_status)
- scan_done->mvm->last_ebs_successful = false;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_umac_scan_iter_complete_notif *notif = (void *)pkt->data;
+ u8 buf[256];
- return !iwl_mvm_find_scan_type(scan_done->mvm, scan_done->type);
+ IWL_DEBUG_SCAN(mvm,
+ "UMAC Scan iteration complete: status=0x%x scanned_channels=%d channels list: %s\n",
+ notif->status, notif->scanned_channels,
+ iwl_mvm_dump_channel_list(notif->results,
+ notif->scanned_channels, buf,
+ sizeof(buf)));
+ return 0;
}
-static int iwl_umac_scan_abort_one(struct iwl_mvm *mvm, u32 uid)
+static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)
{
struct iwl_umac_scan_abort cmd = {
.hdr.size = cpu_to_le16(sizeof(struct iwl_umac_scan_abort) -
sizeof(struct iwl_mvm_umac_cmd_hdr)),
- .uid = cpu_to_le32(uid),
};
+ int uid, ret;
lockdep_assert_held(&mvm->mutex);
+ /* We should always get a valid index here, because we already
+ * checked that this type of scan was running in the generic
+ * code.
+ */
+ uid = iwl_mvm_scan_uid_by_status(mvm, type);
+ if (WARN_ON_ONCE(uid < 0))
+ return uid;
+
+ cmd.uid = cpu_to_le32(uid);
+
IWL_DEBUG_SCAN(mvm, "Sending scan abort, uid %u\n", uid);
- return iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_UMAC, 0, sizeof(cmd), &cmd);
+ ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_UMAC, 0, sizeof(cmd), &cmd);
+ if (!ret)
+ mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT;
+
+ return ret;
}
-static int iwl_umac_scan_stop(struct iwl_mvm *mvm,
- enum iwl_umac_scan_uid_type type, bool notify)
+static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)
{
struct iwl_notification_wait wait_scan_done;
- static const u8 scan_done_notif[] = { SCAN_COMPLETE_UMAC, };
- struct iwl_umac_scan_done scan_done = {
- .mvm = mvm,
- .type = type,
- };
- int i, ret = -EIO;
+ static const u8 scan_done_notif[] = { SCAN_COMPLETE_UMAC,
+ SCAN_OFFLOAD_COMPLETE, };
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done,
scan_done_notif,
ARRAY_SIZE(scan_done_notif),
- iwl_scan_umac_done_check, &scan_done);
+ NULL, NULL);
IWL_DEBUG_SCAN(mvm, "Preparing to stop scan, type %x\n", type);
- for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) {
- if (mvm->scan_uid[i] & type) {
- int err;
-
- if (iwl_mvm_is_radio_killed(mvm) &&
- (type & IWL_UMAC_SCAN_UID_REG_SCAN)) {
- ieee80211_scan_completed(mvm->hw, true);
- iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
- break;
- }
-
- err = iwl_umac_scan_abort_one(mvm, mvm->scan_uid[i]);
- if (!err)
- ret = 0;
- }
- }
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN))
+ ret = iwl_mvm_umac_scan_abort(mvm, type);
+ else
+ ret = iwl_mvm_lmac_scan_abort(mvm);
if (ret) {
- IWL_DEBUG_SCAN(mvm, "Couldn't stop scan\n");
+ IWL_DEBUG_SCAN(mvm, "couldn't stop scan type %d\n", type);
iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
return ret;
}
ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
- if (ret)
- return ret;
-
- if (notify) {
- if (type & IWL_UMAC_SCAN_UID_SCHED_SCAN)
- ieee80211_sched_scan_stopped(mvm->hw);
- if (type & IWL_UMAC_SCAN_UID_REG_SCAN) {
- ieee80211_scan_completed(mvm->hw, true);
- iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
- }
- }
return ret;
}
int iwl_mvm_scan_size(struct iwl_mvm *mvm)
{
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN))
return sizeof(struct iwl_scan_req_umac) +
sizeof(struct iwl_scan_channel_cfg_umac) *
mvm->fw->ucode_capa.n_scan_channels +
sizeof(struct iwl_scan_req_umac_tail);
- return sizeof(struct iwl_scan_req_unified_lmac) +
+ return sizeof(struct iwl_scan_req_lmac) +
sizeof(struct iwl_scan_channel_cfg_lmac) *
mvm->fw->ucode_capa.n_scan_channels +
sizeof(struct iwl_scan_probe_req);
@@ -1640,47 +1507,76 @@ int iwl_mvm_scan_size(struct iwl_mvm *mvm)
*/
void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm)
{
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
- u32 uid, i;
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
+ int uid, i;
- uid = iwl_mvm_find_first_scan(mvm, IWL_UMAC_SCAN_UID_REG_SCAN);
- if (uid < IWL_MVM_MAX_SIMULTANEOUS_SCANS) {
+ uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_REGULAR);
+ if (uid >= 0) {
ieee80211_scan_completed(mvm->hw, true);
- mvm->scan_uid[uid] = 0;
+ mvm->scan_uid_status[uid] = 0;
}
- uid = iwl_mvm_find_first_scan(mvm,
- IWL_UMAC_SCAN_UID_SCHED_SCAN);
- if (uid < IWL_MVM_MAX_SIMULTANEOUS_SCANS && !mvm->restart_fw) {
+ uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_SCHED);
+ if (uid >= 0 && !mvm->restart_fw) {
ieee80211_sched_scan_stopped(mvm->hw);
- mvm->scan_uid[uid] = 0;
+ mvm->scan_uid_status[uid] = 0;
}
/* We shouldn't have any UIDs still set. Loop over all the
* UIDs to make sure there's nothing left there and warn if
* any is found.
*/
- for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) {
- if (WARN_ONCE(mvm->scan_uid[i],
- "UMAC scan UID %d was not cleaned\n",
- mvm->scan_uid[i]))
- mvm->scan_uid[i] = 0;
+ for (i = 0; i < mvm->max_scans; i++) {
+ if (WARN_ONCE(mvm->scan_uid_status[i],
+ "UMAC scan UID %d status was not cleaned\n",
+ i))
+ mvm->scan_uid_status[i] = 0;
}
} else {
- switch (mvm->scan_status) {
- case IWL_MVM_SCAN_NONE:
- break;
- case IWL_MVM_SCAN_OS:
+ if (mvm->scan_status & IWL_MVM_SCAN_REGULAR)
ieee80211_scan_completed(mvm->hw, true);
- break;
- case IWL_MVM_SCAN_SCHED:
- /*
- * Sched scan will be restarted by mac80211 in
- * restart_hw, so do not report if FW is about to be
- * restarted.
- */
- if (!mvm->restart_fw)
- ieee80211_sched_scan_stopped(mvm->hw);
- break;
- }
+
+ /* Sched scan will be restarted by mac80211 in
+ * restart_hw, so do not report if FW is about to be
+ * restarted.
+ */
+ if ((mvm->scan_status & IWL_MVM_SCAN_SCHED) && !mvm->restart_fw)
+ ieee80211_sched_scan_stopped(mvm->hw);
+ }
+}
+
+int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify)
+{
+ int ret;
+
+ if (!(mvm->scan_status & type))
+ return 0;
+
+ if (iwl_mvm_is_radio_killed(mvm)) {
+ ret = 0;
+ goto out;
+ }
+
+ ret = iwl_mvm_scan_stop_wait(mvm, type);
+ if (!ret)
+ mvm->scan_status |= type << IWL_MVM_SCAN_STOPPING_SHIFT;
+out:
+ /* Clear the scan status so the next scan requests will
+ * succeed and mark the scan as stopping, so that the Rx
+ * handler doesn't do anything, as the scan was stopped from
+ * above.
+ */
+ mvm->scan_status &= ~type;
+
+ if (type == IWL_MVM_SCAN_REGULAR) {
+ /* Since the rx handler won't do anything now, we have
+ * to release the scan reference here.
+ */
+ iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
+ if (notify)
+ ieee80211_scan_completed(mvm->hw, true);
+ } else if (notify) {
+ ieee80211_sched_scan_stopped(mvm->hw);
}
+
+ return ret;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index 1845b79487c8..d68dc697a4a0 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -5,8 +5,8 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -31,8 +31,8 @@
*
* BSD LICENSE
*
- * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -1000,13 +1000,13 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
+ iwl_mvm_enable_agg_txq(mvm, queue, fifo, mvmsta->sta_id, tid,
+ buf_size, ssn, wdg_timeout);
+
ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true);
if (ret)
return -EIO;
- iwl_mvm_enable_agg_txq(mvm, queue, fifo, mvmsta->sta_id, tid,
- buf_size, ssn, wdg_timeout);
-
/*
* Even though in theory the peer could have different
* aggregation reorder buffer sizes for different sessions,
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
index fd7b0d36f9a6..d24b6a83e68c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -108,12 +108,14 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
* in the case that the time event actually completed in the firmware
* (which is handled in iwl_mvm_te_handle_notif).
*/
- if (test_and_clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
+ if (test_and_clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) {
queues |= BIT(IWL_MVM_OFFCHANNEL_QUEUE);
- if (test_and_clear_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status))
+ iwl_mvm_unref(mvm, IWL_MVM_REF_ROC);
+ }
+ if (test_and_clear_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) {
queues |= BIT(mvm->aux_queue);
-
- iwl_mvm_unref(mvm, IWL_MVM_REF_ROC);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_ROC_AUX);
+ }
synchronize_net();
@@ -393,6 +395,7 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,
} else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) {
set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status);
te_data->running = true;
+ iwl_mvm_ref(mvm, IWL_MVM_REF_ROC_AUX);
ieee80211_ready_on_channel(mvm->hw); /* Start TE */
} else {
IWL_DEBUG_TE(mvm,
@@ -794,13 +797,12 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
{
- struct iwl_mvm_vif *mvmvif;
+ struct iwl_mvm_vif *mvmvif = NULL;
struct iwl_mvm_time_event_data *te_data;
bool is_p2p = false;
lockdep_assert_held(&mvm->mutex);
- mvmvif = NULL;
spin_lock_bh(&mvm->time_event_lock);
/*
@@ -818,17 +820,14 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
}
}
- /*
- * Iterate over the list of aux roc time events and find the time
- * event that is associated with a BSS interface.
- * This assumes that a BSS interface can have only a single time
- * event at any given time and this time event corresponds to a ROC
- * request
+ /* There can only be at most one AUX ROC time event, we just use the
+ * list to simplify/unify code. Remove it if it exists.
*/
- list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) {
+ te_data = list_first_entry_or_null(&mvm->aux_roc_te_list,
+ struct iwl_mvm_time_event_data,
+ list);
+ if (te_data)
mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
- goto remove_te;
- }
remove_te:
spin_unlock_bh(&mvm->time_event_lock);
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c
index ba615ad2176c..80d07db6e7e8 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tt.c
@@ -70,7 +70,7 @@
static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
{
struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
- u32 duration = mvm->thermal_throttle.params->ct_kill_duration;
+ u32 duration = tt->params.ct_kill_duration;
if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
return;
@@ -223,7 +223,7 @@ static void check_exit_ctkill(struct work_struct *work)
tt = container_of(work, struct iwl_mvm_tt_mgmt, ct_kill_exit.work);
mvm = container_of(tt, struct iwl_mvm, thermal_throttle);
- duration = tt->params->ct_kill_duration;
+ duration = tt->params.ct_kill_duration;
mutex_lock(&mvm->mutex);
@@ -247,7 +247,7 @@ static void check_exit_ctkill(struct work_struct *work)
IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp);
- if (temp <= tt->params->ct_kill_exit) {
+ if (temp <= tt->params.ct_kill_exit) {
mutex_unlock(&mvm->mutex);
iwl_mvm_exit_ctkill(mvm);
return;
@@ -325,7 +325,7 @@ void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff)
void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
{
- const struct iwl_tt_params *params = mvm->thermal_throttle.params;
+ struct iwl_tt_params *params = &mvm->thermal_throttle.params;
struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
s32 temperature = mvm->temperature;
bool throttle_enable = false;
@@ -340,7 +340,7 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
}
if (params->support_ct_kill &&
- temperature <= tt->params->ct_kill_exit) {
+ temperature <= params->ct_kill_exit) {
iwl_mvm_exit_ctkill(mvm);
return;
}
@@ -400,7 +400,7 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
}
}
-static const struct iwl_tt_params iwl7000_tt_params = {
+static const struct iwl_tt_params iwl_mvm_default_tt_params = {
.ct_kill_entry = 118,
.ct_kill_exit = 96,
.ct_kill_duration = 5,
@@ -422,38 +422,16 @@ static const struct iwl_tt_params iwl7000_tt_params = {
.support_tx_backoff = true,
};
-static const struct iwl_tt_params iwl7000_high_temp_tt_params = {
- .ct_kill_entry = 118,
- .ct_kill_exit = 96,
- .ct_kill_duration = 5,
- .dynamic_smps_entry = 114,
- .dynamic_smps_exit = 110,
- .tx_protection_entry = 114,
- .tx_protection_exit = 108,
- .tx_backoff = {
- {.temperature = 112, .backoff = 300},
- {.temperature = 113, .backoff = 800},
- {.temperature = 114, .backoff = 1500},
- {.temperature = 115, .backoff = 3000},
- {.temperature = 116, .backoff = 5000},
- {.temperature = 117, .backoff = 10000},
- },
- .support_ct_kill = true,
- .support_dynamic_smps = true,
- .support_tx_protection = true,
- .support_tx_backoff = true,
-};
-
void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff)
{
struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n");
- if (mvm->cfg->high_temp)
- tt->params = &iwl7000_high_temp_tt_params;
+ if (mvm->cfg->thermal_params)
+ tt->params = *mvm->cfg->thermal_params;
else
- tt->params = &iwl7000_tt_params;
+ tt->params = iwl_mvm_default_tt_params;
tt->throttle = false;
tt->dynamic_smps = false;
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index ef32e177f662..7ba7a118ff5c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -70,6 +70,30 @@
#include "mvm.h"
#include "sta.h"
+static void
+iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr,
+ u16 tid, u16 ssn)
+{
+ struct iwl_fw_dbg_trigger_tlv *trig;
+ struct iwl_fw_dbg_trigger_ba *ba_trig;
+
+ if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
+ return;
+
+ trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
+ ba_trig = (void *)trig->data;
+
+ if (!iwl_fw_dbg_trigger_check_stop(mvm, NULL, trig))
+ return;
+
+ if (!(le16_to_cpu(ba_trig->tx_bar) & BIT(tid)))
+ return;
+
+ iwl_mvm_fw_dbg_collect_trig(mvm, trig,
+ "BAR sent to %pM, tid %d, ssn %d",
+ addr, tid, ssn);
+}
+
/*
* Sets most of the Tx cmd's fields
*/
@@ -101,12 +125,15 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
} else if (ieee80211_is_back_req(fc)) {
struct ieee80211_bar *bar = (void *)skb->data;
u16 control = le16_to_cpu(bar->control);
+ u16 ssn = le16_to_cpu(bar->start_seq_num);
tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR;
tx_cmd->tid_tspec = (control &
IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
WARN_ON_ONCE(tx_cmd->tid_tspec >= IWL_MAX_TID_COUNT);
+ iwl_mvm_bar_check_trigger(mvm, bar->ra, tx_cmd->tid_tspec,
+ ssn);
} else {
tx_cmd->tid_tspec = IWL_TID_NON_QOS;
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
@@ -144,8 +171,8 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
!is_multicast_ether_addr(ieee80211_get_DA(hdr)))
tx_flags |= TX_CMD_FLG_PROT_REQUIRE;
- if ((mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT) &&
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT) &&
ieee80211_action_contains_tpc(skb))
tx_flags |= TX_CMD_FLG_WRITE_TX_POWER;
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index bc55a8b82db6..03f8e06dded7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -584,7 +584,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
struct iwl_error_event_table table;
u32 base;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_NEW_VERSION)) {
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_NEW_VERSION)) {
iwl_mvm_dump_nic_error_log_old(mvm);
return;
}
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c
index b18569734922..2ed1e4d2774d 100644
--- a/drivers/net/wireless/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/iwlwifi/pcie/drv.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -629,7 +629,18 @@ static int iwl_pci_resume(struct device *device)
if (!trans->op_mode)
return 0;
- iwl_enable_rfkill_int(trans);
+ /*
+ * On suspend, ict is disabled, and the interrupt mask
+ * gets cleared. Reconfigure them both in case of d0i3
+ * image. Otherwise, only enable rfkill interrupt (in
+ * order to keep track of the rfkill status)
+ */
+ if (trans->wowlan_d0i3) {
+ iwl_pcie_reset_ict(trans);
+ iwl_enable_interrupts(trans);
+ } else {
+ iwl_enable_rfkill_int(trans);
+ }
hw_rfkill = iwl_is_rfkill_set(trans);
iwl_trans_pcie_rf_kill(trans, hw_rfkill);
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index 376b84e54ad7..31f72a61cc3f 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -44,6 +44,15 @@
#include "iwl-io.h"
#include "iwl-op-mode.h"
+/*
+ * RX related structures and functions
+ */
+#define RX_NUM_QUEUES 1
+#define RX_POST_REQ_ALLOC 2
+#define RX_CLAIM_REQ_ALLOC 8
+#define RX_POOL_SIZE ((RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC) * RX_NUM_QUEUES)
+#define RX_LOW_WATERMARK 8
+
struct iwl_host_cmd;
/*This file includes the declaration that are internal to the
@@ -77,29 +86,29 @@ struct isr_statistics {
* struct iwl_rxq - Rx queue
* @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
* @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
- * @pool:
- * @queue:
* @read: Shared index to newest available Rx buffer
* @write: Shared index to oldest written Rx packet
* @free_count: Number of pre-allocated buffers in rx_free
+ * @used_count: Number of RBDs handled to allocator to use for allocation
* @write_actual:
- * @rx_free: list of free SKBs for use
- * @rx_used: List of Rx buffers with no SKB
+ * @rx_free: list of RBDs with allocated RB ready for use
+ * @rx_used: list of RBDs with no RB attached
* @need_update: flag to indicate we need to update read/write index
* @rb_stts: driver's pointer to receive buffer status
* @rb_stts_dma: bus address of receive buffer status
* @lock:
+ * @pool: initial pool of iwl_rx_mem_buffer for the queue
+ * @queue: actual rx queue
*
* NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
*/
struct iwl_rxq {
__le32 *bd;
dma_addr_t bd_dma;
- struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
- struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
u32 read;
u32 write;
u32 free_count;
+ u32 used_count;
u32 write_actual;
struct list_head rx_free;
struct list_head rx_used;
@@ -107,6 +116,32 @@ struct iwl_rxq {
struct iwl_rb_status *rb_stts;
dma_addr_t rb_stts_dma;
spinlock_t lock;
+ struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE];
+ struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
+};
+
+/**
+ * struct iwl_rb_allocator - Rx allocator
+ * @pool: initial pool of allocator
+ * @req_pending: number of requests the allcator had not processed yet
+ * @req_ready: number of requests honored and ready for claiming
+ * @rbd_allocated: RBDs with pages allocated and ready to be handled to
+ * the queue. This is a list of &struct iwl_rx_mem_buffer
+ * @rbd_empty: RBDs with no page attached for allocator use. This is a list
+ * of &struct iwl_rx_mem_buffer
+ * @lock: protects the rbd_allocated and rbd_empty lists
+ * @alloc_wq: work queue for background calls
+ * @rx_alloc: work struct for background calls
+ */
+struct iwl_rb_allocator {
+ struct iwl_rx_mem_buffer pool[RX_POOL_SIZE];
+ atomic_t req_pending;
+ atomic_t req_ready;
+ struct list_head rbd_allocated;
+ struct list_head rbd_empty;
+ spinlock_t lock;
+ struct workqueue_struct *alloc_wq;
+ struct work_struct rx_alloc;
};
struct iwl_dma_ptr {
@@ -250,7 +285,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
/**
* struct iwl_trans_pcie - PCIe transport specific data
* @rxq: all the RX queue data
- * @rx_replenish: work that will be called when buffers need to be allocated
+ * @rba: allocator for RX replenishing
* @drv - pointer to iwl_drv
* @trans: pointer to the generic transport area
* @scd_base_addr: scheduler sram base address in SRAM
@@ -273,7 +308,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
*/
struct iwl_trans_pcie {
struct iwl_rxq rxq;
- struct work_struct rx_replenish;
+ struct iwl_rb_allocator rba;
struct iwl_trans *trans;
struct iwl_drv *drv;
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index 7ff69c642103..a3fbaa0ef5e0 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -1,7 +1,7 @@
/******************************************************************************
*
* Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -74,16 +74,29 @@
* resets the Rx queue buffers with new memory.
*
* The management in the driver is as follows:
- * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When
- * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
- * to replenish the iwl->rxq->rx_free.
- * + In iwl_pcie_rx_replenish (scheduled) if 'processed' != 'read' then the
- * iwl->rxq is replenished and the READ INDEX is updated (updating the
- * 'processed' and 'read' driver indexes as well)
+ * + A list of pre-allocated RBDs is stored in iwl->rxq->rx_free.
+ * When the interrupt handler is called, the request is processed.
+ * The page is either stolen - transferred to the upper layer
+ * or reused - added immediately to the iwl->rxq->rx_free list.
+ * + When the page is stolen - the driver updates the matching queue's used
+ * count, detaches the RBD and transfers it to the queue used list.
+ * When there are two used RBDs - they are transferred to the allocator empty
+ * list. Work is then scheduled for the allocator to start allocating
+ * eight buffers.
+ * When there are another 6 used RBDs - they are transferred to the allocator
+ * empty list and the driver tries to claim the pre-allocated buffers and
+ * add them to iwl->rxq->rx_free. If it fails - it continues to claim them
+ * until ready.
+ * When there are 8+ buffers in the free list - either from allocation or from
+ * 8 reused unstolen pages - restock is called to update the FW and indexes.
+ * + In order to make sure the allocator always has RBDs to use for allocation
+ * the allocator has initial pool in the size of num_queues*(8-2) - the
+ * maximum missing RBDs per allocation request (request posted with 2
+ * empty RBDs, there is no guarantee when the other 6 RBDs are supplied).
+ * The queues supplies the recycle of the rest of the RBDs.
* + A received packet is processed and handed to the kernel network stack,
* detached from the iwl->rxq. The driver 'processed' index is updated.
- * + The Host/Firmware iwl->rxq is replenished at irq thread time from the
- * rx_free list. If there are no allocated buffers in iwl->rxq->rx_free,
+ * + If there are no allocated buffers in iwl->rxq->rx_free,
* the READ INDEX is not incremented and iwl->status(RX_STALLED) is set.
* If there were enough free buffers and RX_STALLED is set it is cleared.
*
@@ -92,18 +105,32 @@
*
* iwl_rxq_alloc() Allocates rx_free
* iwl_pcie_rx_replenish() Replenishes rx_free list from rx_used, and calls
- * iwl_pcie_rxq_restock
+ * iwl_pcie_rxq_restock.
+ * Used only during initialization.
* iwl_pcie_rxq_restock() Moves available buffers from rx_free into Rx
* queue, updates firmware pointers, and updates
- * the WRITE index. If insufficient rx_free buffers
- * are available, schedules iwl_pcie_rx_replenish
+ * the WRITE index.
+ * iwl_pcie_rx_allocator() Background work for allocating pages.
*
* -- enable interrupts --
* ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the
* READ INDEX, detaching the SKB from the pool.
* Moves the packet buffer from queue to rx_used.
+ * Posts and claims requests to the allocator.
* Calls iwl_pcie_rxq_restock to refill any empty
* slots.
+ *
+ * RBD life-cycle:
+ *
+ * Init:
+ * rxq.pool -> rxq.rx_used -> rxq.rx_free -> rxq.queue
+ *
+ * Regular Receive interrupt:
+ * Page Stolen:
+ * rxq.queue -> rxq.rx_used -> allocator.rbd_empty ->
+ * allocator.rbd_allocated -> rxq.rx_free -> rxq.queue
+ * Page not Stolen:
+ * rxq.queue -> rxq.rx_free -> rxq.queue
* ...
*
*/
@@ -240,10 +267,6 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
rxq->free_count--;
}
spin_unlock(&rxq->lock);
- /* If the pre-allocated buffer pool is dropping low, schedule to
- * refill it */
- if (rxq->free_count <= RX_LOW_WATERMARK)
- schedule_work(&trans_pcie->rx_replenish);
/* If we've added more space for the firmware to place data, tell it.
* Increment device's write pointer in multiples of 8. */
@@ -255,6 +278,44 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
}
/*
+ * iwl_pcie_rx_alloc_page - allocates and returns a page.
+ *
+ */
+static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_rxq *rxq = &trans_pcie->rxq;
+ struct page *page;
+ gfp_t gfp_mask = GFP_KERNEL;
+
+ if (rxq->free_count > RX_LOW_WATERMARK)
+ gfp_mask |= __GFP_NOWARN;
+
+ if (trans_pcie->rx_page_order > 0)
+ gfp_mask |= __GFP_COMP;
+
+ /* Alloc a new receive buffer */
+ page = alloc_pages(gfp_mask, trans_pcie->rx_page_order);
+ if (!page) {
+ if (net_ratelimit())
+ IWL_DEBUG_INFO(trans, "alloc_pages failed, order: %d\n",
+ trans_pcie->rx_page_order);
+ /* Issue an error if the hardware has consumed more than half
+ * of its free buffer list and we don't have enough
+ * pre-allocated buffers.
+` */
+ if (rxq->free_count <= RX_LOW_WATERMARK &&
+ iwl_rxq_space(rxq) > (RX_QUEUE_SIZE / 2) &&
+ net_ratelimit())
+ IWL_CRIT(trans,
+ "Failed to alloc_pages with GFP_KERNEL. Only %u free buffers remaining.\n",
+ rxq->free_count);
+ return NULL;
+ }
+ return page;
+}
+
+/*
* iwl_pcie_rxq_alloc_rbs - allocate a page for each used RBD
*
* A used RBD is an Rx buffer that has been given to the stack. To use it again
@@ -263,13 +324,12 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
* iwl_pcie_rxq_restock. The latter function will update the HW to use the newly
* allocated buffers.
*/
-static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
+static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *rxq = &trans_pcie->rxq;
struct iwl_rx_mem_buffer *rxb;
struct page *page;
- gfp_t gfp_mask = priority;
while (1) {
spin_lock(&rxq->lock);
@@ -279,32 +339,10 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
}
spin_unlock(&rxq->lock);
- if (rxq->free_count > RX_LOW_WATERMARK)
- gfp_mask |= __GFP_NOWARN;
-
- if (trans_pcie->rx_page_order > 0)
- gfp_mask |= __GFP_COMP;
-
/* Alloc a new receive buffer */
- page = alloc_pages(gfp_mask, trans_pcie->rx_page_order);
- if (!page) {
- if (net_ratelimit())
- IWL_DEBUG_INFO(trans, "alloc_pages failed, "
- "order: %d\n",
- trans_pcie->rx_page_order);
-
- if ((rxq->free_count <= RX_LOW_WATERMARK) &&
- net_ratelimit())
- IWL_CRIT(trans, "Failed to alloc_pages with %s."
- "Only %u free buffers remaining.\n",
- priority == GFP_ATOMIC ?
- "GFP_ATOMIC" : "GFP_KERNEL",
- rxq->free_count);
- /* We don't reschedule replenish work here -- we will
- * call the restock method and if it still needs
- * more buffers it will schedule replenish */
+ page = iwl_pcie_rx_alloc_page(trans);
+ if (!page)
return;
- }
spin_lock(&rxq->lock);
@@ -355,7 +393,7 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans)
lockdep_assert_held(&rxq->lock);
- for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+ for (i = 0; i < RX_QUEUE_SIZE; i++) {
if (!rxq->pool[i].page)
continue;
dma_unmap_page(trans->dev, rxq->pool[i].page_dma,
@@ -372,32 +410,144 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans)
* When moving to rx_free an page is allocated for the slot.
*
* Also restock the Rx queue via iwl_pcie_rxq_restock.
- * This is called as a scheduled work item (except for during initialization)
+ * This is called only during initialization
*/
-static void iwl_pcie_rx_replenish(struct iwl_trans *trans, gfp_t gfp)
+static void iwl_pcie_rx_replenish(struct iwl_trans *trans)
{
- iwl_pcie_rxq_alloc_rbs(trans, gfp);
+ iwl_pcie_rxq_alloc_rbs(trans);
iwl_pcie_rxq_restock(trans);
}
-static void iwl_pcie_rx_replenish_work(struct work_struct *data)
+/*
+ * iwl_pcie_rx_allocator - Allocates pages in the background for RX queues
+ *
+ * Allocates for each received request 8 pages
+ * Called as a scheduled work item.
+ */
+static void iwl_pcie_rx_allocator(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
+
+ while (atomic_read(&rba->req_pending)) {
+ int i;
+ struct list_head local_empty;
+ struct list_head local_allocated;
+
+ INIT_LIST_HEAD(&local_allocated);
+ spin_lock(&rba->lock);
+ /* swap out the entire rba->rbd_empty to a local list */
+ list_replace_init(&rba->rbd_empty, &local_empty);
+ spin_unlock(&rba->lock);
+
+ for (i = 0; i < RX_CLAIM_REQ_ALLOC;) {
+ struct iwl_rx_mem_buffer *rxb;
+ struct page *page;
+
+ /* List should never be empty - each reused RBD is
+ * returned to the list, and initial pool covers any
+ * possible gap between the time the page is allocated
+ * to the time the RBD is added.
+ */
+ BUG_ON(list_empty(&local_empty));
+ /* Get the first rxb from the rbd list */
+ rxb = list_first_entry(&local_empty,
+ struct iwl_rx_mem_buffer, list);
+ BUG_ON(rxb->page);
+
+ /* Alloc a new receive buffer */
+ page = iwl_pcie_rx_alloc_page(trans);
+ if (!page)
+ continue;
+ rxb->page = page;
+
+ /* Get physical address of the RB */
+ rxb->page_dma = dma_map_page(trans->dev, page, 0,
+ PAGE_SIZE << trans_pcie->rx_page_order,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(trans->dev, rxb->page_dma)) {
+ rxb->page = NULL;
+ __free_pages(page, trans_pcie->rx_page_order);
+ continue;
+ }
+ /* dma address must be no more than 36 bits */
+ BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
+ /* and also 256 byte aligned! */
+ BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
+
+ /* move the allocated entry to the out list */
+ list_move(&rxb->list, &local_allocated);
+ i++;
+ }
+
+ spin_lock(&rba->lock);
+ /* add the allocated rbds to the allocator allocated list */
+ list_splice_tail(&local_allocated, &rba->rbd_allocated);
+ /* add the unused rbds back to the allocator empty list */
+ list_splice_tail(&local_empty, &rba->rbd_empty);
+ spin_unlock(&rba->lock);
+
+ atomic_dec(&rba->req_pending);
+ atomic_inc(&rba->req_ready);
+ }
+}
+
+/*
+ * iwl_pcie_rx_allocator_get - Returns the pre-allocated pages
+.*
+.* Called by queue when the queue posted allocation request and
+ * has freed 8 RBDs in order to restock itself.
+ */
+static int iwl_pcie_rx_allocator_get(struct iwl_trans *trans,
+ struct iwl_rx_mem_buffer
+ *out[RX_CLAIM_REQ_ALLOC])
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
+ int i;
+
+ if (atomic_dec_return(&rba->req_ready) < 0) {
+ atomic_inc(&rba->req_ready);
+ IWL_DEBUG_RX(trans,
+ "Allocation request not ready, pending requests = %d\n",
+ atomic_read(&rba->req_pending));
+ return -ENOMEM;
+ }
+
+ spin_lock(&rba->lock);
+ for (i = 0; i < RX_CLAIM_REQ_ALLOC; i++) {
+ /* Get next free Rx buffer, remove it from free list */
+ out[i] = list_first_entry(&rba->rbd_allocated,
+ struct iwl_rx_mem_buffer, list);
+ list_del(&out[i]->list);
+ }
+ spin_unlock(&rba->lock);
+
+ return 0;
+}
+
+static void iwl_pcie_rx_allocator_work(struct work_struct *data)
{
+ struct iwl_rb_allocator *rba_p =
+ container_of(data, struct iwl_rb_allocator, rx_alloc);
struct iwl_trans_pcie *trans_pcie =
- container_of(data, struct iwl_trans_pcie, rx_replenish);
+ container_of(rba_p, struct iwl_trans_pcie, rba);
- iwl_pcie_rx_replenish(trans_pcie->trans, GFP_KERNEL);
+ iwl_pcie_rx_allocator(trans_pcie->trans);
}
static int iwl_pcie_rx_alloc(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *rxq = &trans_pcie->rxq;
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
struct device *dev = trans->dev;
memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq));
spin_lock_init(&rxq->lock);
+ spin_lock_init(&rba->lock);
if (WARN_ON(rxq->bd || rxq->rb_stts))
return -EINVAL;
@@ -487,15 +637,49 @@ static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq)
INIT_LIST_HEAD(&rxq->rx_free);
INIT_LIST_HEAD(&rxq->rx_used);
rxq->free_count = 0;
+ rxq->used_count = 0;
- for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
+ for (i = 0; i < RX_QUEUE_SIZE; i++)
list_add(&rxq->pool[i].list, &rxq->rx_used);
}
+static void iwl_pcie_rx_init_rba(struct iwl_rb_allocator *rba)
+{
+ int i;
+
+ lockdep_assert_held(&rba->lock);
+
+ INIT_LIST_HEAD(&rba->rbd_allocated);
+ INIT_LIST_HEAD(&rba->rbd_empty);
+
+ for (i = 0; i < RX_POOL_SIZE; i++)
+ list_add(&rba->pool[i].list, &rba->rbd_empty);
+}
+
+static void iwl_pcie_rx_free_rba(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
+ int i;
+
+ lockdep_assert_held(&rba->lock);
+
+ for (i = 0; i < RX_POOL_SIZE; i++) {
+ if (!rba->pool[i].page)
+ continue;
+ dma_unmap_page(trans->dev, rba->pool[i].page_dma,
+ PAGE_SIZE << trans_pcie->rx_page_order,
+ DMA_FROM_DEVICE);
+ __free_pages(rba->pool[i].page, trans_pcie->rx_page_order);
+ rba->pool[i].page = NULL;
+ }
+}
+
int iwl_pcie_rx_init(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *rxq = &trans_pcie->rxq;
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
int i, err;
if (!rxq->bd) {
@@ -503,11 +687,21 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
if (err)
return err;
}
+ if (!rba->alloc_wq)
+ rba->alloc_wq = alloc_workqueue("rb_allocator",
+ WQ_HIGHPRI | WQ_UNBOUND, 1);
+ INIT_WORK(&rba->rx_alloc, iwl_pcie_rx_allocator_work);
+
+ spin_lock(&rba->lock);
+ atomic_set(&rba->req_pending, 0);
+ atomic_set(&rba->req_ready, 0);
+ /* free all first - we might be reconfigured for a different size */
+ iwl_pcie_rx_free_rba(trans);
+ iwl_pcie_rx_init_rba(rba);
+ spin_unlock(&rba->lock);
spin_lock(&rxq->lock);
- INIT_WORK(&trans_pcie->rx_replenish, iwl_pcie_rx_replenish_work);
-
/* free all first - we might be reconfigured for a different size */
iwl_pcie_rxq_free_rbs(trans);
iwl_pcie_rx_init_rxb_lists(rxq);
@@ -522,7 +716,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
spin_unlock(&rxq->lock);
- iwl_pcie_rx_replenish(trans, GFP_KERNEL);
+ iwl_pcie_rx_replenish(trans);
iwl_pcie_rx_hw_init(trans, rxq);
@@ -537,6 +731,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *rxq = &trans_pcie->rxq;
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
/*if rxq->bd is NULL, it means that nothing has been allocated,
* exit now */
@@ -545,7 +740,15 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
return;
}
- cancel_work_sync(&trans_pcie->rx_replenish);
+ cancel_work_sync(&rba->rx_alloc);
+ if (rba->alloc_wq) {
+ destroy_workqueue(rba->alloc_wq);
+ rba->alloc_wq = NULL;
+ }
+
+ spin_lock(&rba->lock);
+ iwl_pcie_rx_free_rba(trans);
+ spin_unlock(&rba->lock);
spin_lock(&rxq->lock);
iwl_pcie_rxq_free_rbs(trans);
@@ -566,6 +769,43 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
rxq->rb_stts = NULL;
}
+/*
+ * iwl_pcie_rx_reuse_rbd - Recycle used RBDs
+ *
+ * Called when a RBD can be reused. The RBD is transferred to the allocator.
+ * When there are 2 empty RBDs - a request for allocation is posted
+ */
+static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_rxq *rxq)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
+
+ /* Count the used RBDs */
+ rxq->used_count++;
+
+ /* Move the RBD to the used list, will be moved to allocator in batches
+ * before claiming or posting a request*/
+ list_add_tail(&rxb->list, &rxq->rx_used);
+
+ /* If we have RX_POST_REQ_ALLOC new released rx buffers -
+ * issue a request for allocator. Modulo RX_CLAIM_REQ_ALLOC is
+ * used for the case we failed to claim RX_CLAIM_REQ_ALLOC,
+ * after but we still need to post another request.
+ */
+ if ((rxq->used_count % RX_CLAIM_REQ_ALLOC) == RX_POST_REQ_ALLOC) {
+ /* Move the 2 RBDs to the allocator ownership.
+ Allocator has another 6 from pool for the request completion*/
+ spin_lock(&rba->lock);
+ list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty);
+ spin_unlock(&rba->lock);
+
+ atomic_inc(&rba->req_pending);
+ queue_work(rba->alloc_wq, &rba->rx_alloc);
+ }
+}
+
static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
struct iwl_rx_mem_buffer *rxb)
{
@@ -688,13 +928,13 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
*/
__free_pages(rxb->page, trans_pcie->rx_page_order);
rxb->page = NULL;
- list_add_tail(&rxb->list, &rxq->rx_used);
+ iwl_pcie_rx_reuse_rbd(trans, rxb, rxq);
} else {
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
}
} else
- list_add_tail(&rxb->list, &rxq->rx_used);
+ iwl_pcie_rx_reuse_rbd(trans, rxb, rxq);
}
/*
@@ -704,10 +944,7 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *rxq = &trans_pcie->rxq;
- u32 r, i;
- u8 fill_rx = 0;
- u32 count = 8;
- int total_empty;
+ u32 r, i, j;
restart:
spin_lock(&rxq->lock);
@@ -720,14 +957,6 @@ restart:
if (i == r)
IWL_DEBUG_RX(trans, "HW = SW = %d\n", r);
- /* calculate total frames need to be restock after handling RX */
- total_empty = r - rxq->write_actual;
- if (total_empty < 0)
- total_empty += RX_QUEUE_SIZE;
-
- if (total_empty > (RX_QUEUE_SIZE / 2))
- fill_rx = 1;
-
while (i != r) {
struct iwl_rx_mem_buffer *rxb;
@@ -739,29 +968,48 @@ restart:
iwl_pcie_rx_handle_rb(trans, rxb);
i = (i + 1) & RX_QUEUE_MASK;
- /* If there are a lot of unused frames,
- * restock the Rx queue so ucode wont assert. */
- if (fill_rx) {
- count++;
- if (count >= 8) {
- rxq->read = i;
- spin_unlock(&rxq->lock);
- iwl_pcie_rx_replenish(trans, GFP_ATOMIC);
- count = 0;
- goto restart;
+
+ /* If we have RX_CLAIM_REQ_ALLOC released rx buffers -
+ * try to claim the pre-allocated buffers from the allocator */
+ if (rxq->used_count >= RX_CLAIM_REQ_ALLOC) {
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
+ struct iwl_rx_mem_buffer *out[RX_CLAIM_REQ_ALLOC];
+
+ /* Add the remaining 6 empty RBDs for allocator use */
+ spin_lock(&rba->lock);
+ list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty);
+ spin_unlock(&rba->lock);
+
+ /* If not ready - continue, will try to reclaim later.
+ * No need to reschedule work - allocator exits only on
+ * success */
+ if (!iwl_pcie_rx_allocator_get(trans, out)) {
+ /* If success - then RX_CLAIM_REQ_ALLOC
+ * buffers were retrieved and should be added
+ * to free list */
+ rxq->used_count -= RX_CLAIM_REQ_ALLOC;
+ for (j = 0; j < RX_CLAIM_REQ_ALLOC; j++) {
+ list_add_tail(&out[j]->list,
+ &rxq->rx_free);
+ rxq->free_count++;
+ }
}
}
+ /* handle restock for two cases:
+ * - we just pulled buffers from the allocator
+ * - we have 8+ unstolen pages accumulated */
+ if (rxq->free_count >= RX_CLAIM_REQ_ALLOC) {
+ rxq->read = i;
+ spin_unlock(&rxq->lock);
+ iwl_pcie_rxq_restock(trans);
+ goto restart;
+ }
}
/* Backtrack one entry */
rxq->read = i;
spin_unlock(&rxq->lock);
- if (fill_rx)
- iwl_pcie_rx_replenish(trans, GFP_ATOMIC);
- else
- iwl_pcie_rxq_restock(trans);
-
if (trans_pcie->napi.poll)
napi_gro_flush(&trans_pcie->napi, false);
}
@@ -775,6 +1023,7 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
/* W/A for WiFi/WiMAX coex and WiMAX own the RF */
if (trans->cfg->internal_wimax_coex &&
+ !trans->cfg->apmg_not_supported &&
(!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) &
APMS_CLK_VAL_MRB_FUNC_MODE) ||
(iwl_read_prph(trans, APMG_PS_CTRL_REG) &
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index dc179094e6a0..43ae658af6ec 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -101,14 +101,26 @@ static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans)
trans_pcie->fw_mon_size = 0;
}
-static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
+static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct page *page = NULL;
dma_addr_t phys;
- u32 size;
+ u32 size = 0;
u8 power;
+ if (!max_power) {
+ /* default max_power is maximum */
+ max_power = 26;
+ } else {
+ max_power += 11;
+ }
+
+ if (WARN(max_power > 26,
+ "External buffer size for monitor is too big %d, check the FW TLV\n",
+ max_power))
+ return;
+
if (trans_pcie->fw_mon_page) {
dma_sync_single_for_device(trans->dev, trans_pcie->fw_mon_phys,
trans_pcie->fw_mon_size,
@@ -117,7 +129,7 @@ static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
}
phys = 0;
- for (power = 26; power >= 11; power--) {
+ for (power = max_power; power >= 11; power--) {
int order;
size = BIT(power);
@@ -143,6 +155,12 @@ static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
if (WARN_ON_ONCE(!page))
return;
+ if (power != max_power)
+ IWL_ERR(trans,
+ "Sorry - debug buffer is only %luK while you requested %luK\n",
+ (unsigned long)BIT(power - 10),
+ (unsigned long)BIT(max_power - 10));
+
trans_pcie->fw_mon_page = page;
trans_pcie->fw_mon_phys = phys;
trans_pcie->fw_mon_size = size;
@@ -164,6 +182,9 @@ static void iwl_trans_pcie_write_shr(struct iwl_trans *trans, u32 reg, u32 val)
static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
{
+ if (!trans->cfg->apmg_not_supported)
+ return;
+
if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold))
iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
@@ -297,7 +318,7 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
* bits do not disable clocks. This preserves any hardware
* bits already set by default in "CLK_CTRL_REG" after reset.
*/
- if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+ if (!trans->cfg->apmg_not_supported) {
iwl_write_prph(trans, APMG_CLK_EN_REG,
APMG_CLK_VAL_DMA_CLK_RQT);
udelay(20);
@@ -497,8 +518,7 @@ static int iwl_pcie_nic_init(struct iwl_trans *trans)
spin_unlock(&trans_pcie->irq_lock);
- if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
- iwl_pcie_set_pwr(trans, false);
+ iwl_pcie_set_pwr(trans, false);
iwl_op_mode_nic_config(trans->op_mode);
@@ -834,7 +854,7 @@ static void iwl_pcie_apply_destination(struct iwl_trans *trans)
get_fw_dbg_mode_string(dest->monitor_mode));
if (dest->monitor_mode == EXTERNAL_MODE)
- iwl_pcie_alloc_fw_monitor(trans);
+ iwl_pcie_alloc_fw_monitor(trans, dest->size_power);
else
IWL_WARN(trans, "PCI should have external buffer debug\n");
@@ -908,7 +928,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
/* supported for 7000 only for the moment */
if (iwlwifi_mod_params.fw_monitor &&
trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
- iwl_pcie_alloc_fw_monitor(trans);
+ iwl_pcie_alloc_fw_monitor(trans, 0);
if (trans_pcie->fw_mon_size) {
iwl_write_prph(trans, MON_BUFF_BASE_ADDR,
@@ -955,12 +975,8 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans,
return ret;
/* load to FW the binary sections of CPU2 */
- ret = iwl_pcie_load_cpu_sections_8000(trans, image, 2,
- &first_ucode_section);
- if (ret)
- return ret;
-
- return 0;
+ return iwl_pcie_load_cpu_sections_8000(trans, image, 2,
+ &first_ucode_section);
}
static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
@@ -1049,7 +1065,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
iwl_pcie_rx_stop(trans);
/* Power-down device's busmaster DMA clocks */
- if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+ if (!trans->cfg->apmg_not_supported) {
iwl_write_prph(trans, APMG_CLK_DIS_REG,
APMG_CLK_VAL_DMA_CLK_RQT);
udelay(5);
@@ -1346,14 +1362,13 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
iounmap(trans_pcie->hw_base);
pci_release_regions(trans_pcie->pci_dev);
pci_disable_device(trans_pcie->pci_dev);
- kmem_cache_destroy(trans->dev_cmd_pool);
if (trans_pcie->napi.poll)
netif_napi_del(&trans_pcie->napi);
iwl_pcie_free_fw_monitor(trans);
- kfree(trans);
+ iwl_trans_free(trans);
}
static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state)
@@ -2200,6 +2215,29 @@ static u32 iwl_trans_pcie_fh_regs_dump(struct iwl_trans *trans,
return sizeof(**data) + fh_regs_len;
}
+static u32
+iwl_trans_pci_dump_marbh_monitor(struct iwl_trans *trans,
+ struct iwl_fw_error_dump_fw_mon *fw_mon_data,
+ u32 monitor_len)
+{
+ u32 buf_size_in_dwords = (monitor_len >> 2);
+ u32 *buffer = (u32 *)fw_mon_data->data;
+ unsigned long flags;
+ u32 i;
+
+ if (!iwl_trans_grab_nic_access(trans, false, &flags))
+ return 0;
+
+ __iwl_write_prph(trans, MON_DMARB_RD_CTL_ADDR, 0x1);
+ for (i = 0; i < buf_size_in_dwords; i++)
+ buffer[i] = __iwl_read_prph(trans, MON_DMARB_RD_DATA_ADDR);
+ __iwl_write_prph(trans, MON_DMARB_RD_CTL_ADDR, 0x0);
+
+ iwl_trans_release_nic_access(trans, &flags);
+
+ return monitor_len;
+}
+
static
struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
{
@@ -2252,7 +2290,8 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
trans->dbg_dest_tlv->end_shift;
/* Make "end" point to the actual end */
- if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 ||
+ trans->dbg_dest_tlv->monitor_mode == MARBH_MODE)
end += (1 << trans->dbg_dest_tlv->end_shift);
monitor_len = end - base;
len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) +
@@ -2328,9 +2367,6 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
len += sizeof(*data) + sizeof(*fw_mon_data);
if (trans_pcie->fw_mon_page) {
- data->len = cpu_to_le32(trans_pcie->fw_mon_size +
- sizeof(*fw_mon_data));
-
/*
* The firmware is now asserted, it won't write anything
* to the buffer. CPU can take ownership to fetch the
@@ -2345,10 +2381,8 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
page_address(trans_pcie->fw_mon_page),
trans_pcie->fw_mon_size);
- len += trans_pcie->fw_mon_size;
- } else {
- /* If we are here then the buffer is internal */
-
+ monitor_len = trans_pcie->fw_mon_size;
+ } else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) {
/*
* Update pointers to reflect actual values after
* shifting
@@ -2357,10 +2391,18 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
trans->dbg_dest_tlv->base_shift;
iwl_trans_read_mem(trans, base, fw_mon_data->data,
monitor_len / sizeof(u32));
- data->len = cpu_to_le32(sizeof(*fw_mon_data) +
- monitor_len);
- len += monitor_len;
+ } else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) {
+ monitor_len =
+ iwl_trans_pci_dump_marbh_monitor(trans,
+ fw_mon_data,
+ monitor_len);
+ } else {
+ /* Didn't match anything - output no monitor data */
+ monitor_len = 0;
}
+
+ len += monitor_len;
+ data->len = cpu_to_le32(monitor_len + sizeof(*fw_mon_data));
}
dump_data->len = len;
@@ -2419,18 +2461,13 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
u16 pci_cmd;
int err;
- trans = kzalloc(sizeof(struct iwl_trans) +
- sizeof(struct iwl_trans_pcie), GFP_KERNEL);
- if (!trans) {
- err = -ENOMEM;
- goto out;
- }
+ trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie),
+ &pdev->dev, cfg, &trans_ops_pcie, 0);
+ if (!trans)
+ return ERR_PTR(-ENOMEM);
trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- trans->ops = &trans_ops_pcie;
- trans->cfg = cfg;
- trans_lockdep_init(trans);
trans_pcie->trans = trans;
spin_lock_init(&trans_pcie->irq_lock);
spin_lock_init(&trans_pcie->reg_lock);
@@ -2554,25 +2591,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
/* Initialize the wait queue for commands */
init_waitqueue_head(&trans_pcie->wait_command_queue);
- snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name),
- "iwl_cmd_pool:%s", dev_name(trans->dev));
-
- trans->dev_cmd_headroom = 0;
- trans->dev_cmd_pool =
- kmem_cache_create(trans->dev_cmd_pool_name,
- sizeof(struct iwl_device_cmd)
- + trans->dev_cmd_headroom,
- sizeof(void *),
- SLAB_HWCACHE_ALIGN,
- NULL);
-
- if (!trans->dev_cmd_pool) {
- err = -ENOMEM;
- goto out_pci_disable_msi;
- }
-
if (iwl_pcie_alloc_ict(trans))
- goto out_free_cmd_pool;
+ goto out_pci_disable_msi;
err = request_threaded_irq(pdev->irq, iwl_pcie_isr,
iwl_pcie_irq_handler,
@@ -2589,8 +2609,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
out_free_ict:
iwl_pcie_free_ict(trans);
-out_free_cmd_pool:
- kmem_cache_destroy(trans->dev_cmd_pool);
out_pci_disable_msi:
pci_disable_msi(pdev);
out_pci_release_regions:
@@ -2598,7 +2616,6 @@ out_pci_release_regions:
out_pci_disable_device:
pci_disable_device(pdev);
out_no_pci:
- kfree(trans);
-out:
+ iwl_trans_free(trans);
return ERR_PTR(err);
}
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 5ef8044c2ea3..2b86c2135de3 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -1049,8 +1049,6 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
!trans_pcie->cmd_hold_nic_awake) {
__iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
- if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
- udelay(2);
ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 1a4d558022d8..8317afd065b4 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -835,14 +835,13 @@ static int lbs_cfg_scan(struct wiphy *wiphy,
* Events
*/
-void lbs_send_disconnect_notification(struct lbs_private *priv)
+void lbs_send_disconnect_notification(struct lbs_private *priv,
+ bool locally_generated)
{
lbs_deb_enter(LBS_DEB_CFG80211);
- cfg80211_disconnected(priv->dev,
- 0,
- NULL, 0,
- GFP_KERNEL);
+ cfg80211_disconnected(priv->dev, 0, NULL, 0, locally_generated,
+ GFP_KERNEL);
lbs_deb_leave(LBS_DEB_CFG80211);
}
@@ -1458,7 +1457,7 @@ int lbs_disconnect(struct lbs_private *priv, u16 reason)
cfg80211_disconnected(priv->dev,
reason,
- NULL, 0,
+ NULL, 0, true,
GFP_KERNEL);
priv->connect_status = LBS_DISCONNECTED;
@@ -2031,7 +2030,7 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
/* TODO: consider doing this at MACREG_INT_CODE_ADHOC_BCN_LOST time */
- lbs_mac_event_disconnected(priv);
+ lbs_mac_event_disconnected(priv, true);
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
return ret;
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
index 10995f59fe34..acccc2922401 100644
--- a/drivers/net/wireless/libertas/cfg.h
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -10,7 +10,8 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev);
int lbs_cfg_register(struct lbs_private *priv);
void lbs_cfg_free(struct lbs_private *priv);
-void lbs_send_disconnect_notification(struct lbs_private *priv);
+void lbs_send_disconnect_notification(struct lbs_private *priv,
+ bool locally_generated);
void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
void lbs_scan_done(struct lbs_private *priv);
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index 4279e8ab95f2..0c5444b02c64 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -68,7 +68,8 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
/* From cmdresp.c */
-void lbs_mac_event_disconnected(struct lbs_private *priv);
+void lbs_mac_event_disconnected(struct lbs_private *priv,
+ bool locally_generated);
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 65f18f1e869c..e5442e8956f7 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -19,10 +19,13 @@
* reset link state etc.
*
* @priv: A pointer to struct lbs_private structure
+ * @locally_generated: indicates disconnect was requested locally
+ * (usually by userspace)
*
* returns: n/a
*/
-void lbs_mac_event_disconnected(struct lbs_private *priv)
+void lbs_mac_event_disconnected(struct lbs_private *priv,
+ bool locally_generated)
{
if (priv->connect_status != LBS_CONNECTED)
return;
@@ -36,7 +39,7 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
msleep_interruptible(1000);
if (priv->wdev->iftype == NL80211_IFTYPE_STATION)
- lbs_send_disconnect_notification(priv);
+ lbs_send_disconnect_notification(priv, locally_generated);
/* report disconnect to upper layer */
netif_stop_queue(priv->dev);
@@ -229,17 +232,17 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
case MACREG_INT_CODE_DEAUTHENTICATED:
lbs_deb_cmd("EVENT: deauthenticated\n");
- lbs_mac_event_disconnected(priv);
+ lbs_mac_event_disconnected(priv, false);
break;
case MACREG_INT_CODE_DISASSOCIATED:
lbs_deb_cmd("EVENT: disassociated\n");
- lbs_mac_event_disconnected(priv);
+ lbs_mac_event_disconnected(priv, false);
break;
case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
lbs_deb_cmd("EVENT: link lost\n");
- lbs_mac_event_disconnected(priv);
+ lbs_mac_event_disconnected(priv, true);
break;
case MACREG_INT_CODE_PS_SLEEP:
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index ed02e4bf2c26..a47f0acc099a 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -439,7 +439,7 @@ static u64 lbtf_op_prepare_multicast(struct ieee80211_hw *hw,
return mc_count;
}
-#define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)
+#define SUPPORTED_FIF_FLAGS FIF_ALLMULTI
static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *new_flags,
@@ -458,10 +458,7 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
return;
}
- if (*new_flags & (FIF_PROMISC_IN_BSS))
- priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE;
- else
- priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
+ priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
if (*new_flags & (FIF_ALLMULTI) ||
multicast > MRVDRV_MAX_MULTICAST_LIST_SIZE) {
priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
@@ -637,7 +634,7 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev)
priv->tx_skb = NULL;
hw->queues = 1;
- hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
hw->extra_tx_headroom = sizeof(struct txpd);
memcpy(priv->channels, lbtf_channels, sizeof(lbtf_channels));
memcpy(priv->rates, lbtf_rates, sizeof(lbtf_rates));
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index d5c0a1af08b9..99e873dc8684 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1286,7 +1286,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
if (control->sta)
hwsim_check_sta_magic(control->sta);
- if (hw->flags & IEEE80211_HW_SUPPORTS_RC_TABLE)
+ if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE))
ieee80211_get_tx_rates(txi->control.vif, control->sta, skb,
txi->control.rates,
ARRAY_SIZE(txi->control.rates));
@@ -1395,7 +1395,7 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
{
u32 _pid = ACCESS_ONCE(wmediumd_portid);
- if (hw->flags & IEEE80211_HW_SUPPORTS_RC_TABLE) {
+ if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) {
struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
ieee80211_get_tx_rates(txi->control.vif, NULL, skb,
txi->control.rates,
@@ -1432,7 +1432,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
if (skb == NULL)
return;
info = IEEE80211_SKB_CB(skb);
- if (hw->flags & IEEE80211_HW_SUPPORTS_RC_TABLE)
+ if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE))
ieee80211_get_tx_rates(vif, NULL, skb,
info->control.rates,
ARRAY_SIZE(info->control.rates));
@@ -1554,8 +1554,6 @@ static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
wiphy_debug(hw->wiphy, "%s\n", __func__);
data->rx_filter = 0;
- if (*total_flags & FIF_PROMISC_IN_BSS)
- data->rx_filter |= FIF_PROMISC_IN_BSS;
if (*total_flags & FIF_ALLMULTI)
data->rx_filter |= FIF_ALLMULTI;
@@ -2393,15 +2391,16 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
if (param->p2p_device)
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
- hw->flags = IEEE80211_HW_MFP_CAPABLE |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_WANT_MONITOR_VIF |
- IEEE80211_HW_QUEUE_CONTROL |
- IEEE80211_HW_SUPPORTS_HT_CCK_RATES |
- IEEE80211_HW_CHANCTX_STA_CSA;
+ ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
+ ieee80211_hw_set(hw, CHANCTX_STA_CSA);
+ ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
+ ieee80211_hw_set(hw, QUEUE_CONTROL);
+ ieee80211_hw_set(hw, WANT_MONITOR_VIF);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
if (rctbl)
- hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE;
+ ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
@@ -2438,6 +2437,31 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz);
sband->bitrates = data->rates + 4;
sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4;
+
+ sband->vht_cap.vht_supported = true;
+ sband->vht_cap.cap =
+ IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
+ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
+ IEEE80211_VHT_CAP_RXLDPC |
+ IEEE80211_VHT_CAP_SHORT_GI_80 |
+ IEEE80211_VHT_CAP_SHORT_GI_160 |
+ IEEE80211_VHT_CAP_TXSTBC |
+ IEEE80211_VHT_CAP_RXSTBC_1 |
+ IEEE80211_VHT_CAP_RXSTBC_2 |
+ IEEE80211_VHT_CAP_RXSTBC_3 |
+ IEEE80211_VHT_CAP_RXSTBC_4 |
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+ sband->vht_cap.vht_mcs.rx_mcs_map =
+ cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 6 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 8 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 14);
+ sband->vht_cap.vht_mcs.tx_mcs_map =
+ sband->vht_cap.vht_mcs.rx_mcs_map;
break;
default:
continue;
@@ -2458,31 +2482,6 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
hw->wiphy->bands[band] = sband;
-
- sband->vht_cap.vht_supported = true;
- sband->vht_cap.cap =
- IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
- IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
- IEEE80211_VHT_CAP_RXLDPC |
- IEEE80211_VHT_CAP_SHORT_GI_80 |
- IEEE80211_VHT_CAP_SHORT_GI_160 |
- IEEE80211_VHT_CAP_TXSTBC |
- IEEE80211_VHT_CAP_RXSTBC_1 |
- IEEE80211_VHT_CAP_RXSTBC_2 |
- IEEE80211_VHT_CAP_RXSTBC_3 |
- IEEE80211_VHT_CAP_RXSTBC_4 |
- IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
- sband->vht_cap.vht_mcs.rx_mcs_map =
- cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_8 << 0 |
- IEEE80211_VHT_MCS_SUPPORT_0_8 << 2 |
- IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 |
- IEEE80211_VHT_MCS_SUPPORT_0_8 << 6 |
- IEEE80211_VHT_MCS_SUPPORT_0_8 << 8 |
- IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 |
- IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 |
- IEEE80211_VHT_MCS_SUPPORT_0_8 << 14);
- sband->vht_cap.vht_mcs.tx_mcs_map =
- sband->vht_cap.vht_mcs.rx_mcs_map;
}
/* By default all radios belong to the first group */
@@ -2510,7 +2509,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
}
if (param->no_vif)
- hw->flags |= IEEE80211_HW_NO_AUTO_VIF;
+ ieee80211_hw_set(hw, NO_AUTO_VIF);
err = ieee80211_register_hw(hw);
if (err < 0) {
diff --git a/drivers/net/wireless/mediatek/Kconfig b/drivers/net/wireless/mediatek/Kconfig
new file mode 100644
index 000000000000..cba300c6b5da
--- /dev/null
+++ b/drivers/net/wireless/mediatek/Kconfig
@@ -0,0 +1,10 @@
+menuconfig WL_MEDIATEK
+ bool "Mediatek Wireless LAN support"
+ ---help---
+ Enable community drivers for MediaTek WiFi devices.
+ Those drivers make use of the Linux mac80211 stack.
+
+
+if WL_MEDIATEK
+source "drivers/net/wireless/mediatek/mt7601u/Kconfig"
+endif # WL_MEDIATEK
diff --git a/drivers/net/wireless/mediatek/Makefile b/drivers/net/wireless/mediatek/Makefile
new file mode 100644
index 000000000000..9d5f182fd7fd
--- /dev/null
+++ b/drivers/net/wireless/mediatek/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MT7601U) += mt7601u/
diff --git a/drivers/net/wireless/mediatek/mt7601u/Kconfig b/drivers/net/wireless/mediatek/mt7601u/Kconfig
new file mode 100644
index 000000000000..f46bed92796b
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/Kconfig
@@ -0,0 +1,6 @@
+config MT7601U
+ tristate "MediaTek MT7601U (USB) support"
+ depends on MAC80211
+ depends on USB
+ ---help---
+ This adds support for MT7601U-based wireless USB dongles.
diff --git a/drivers/net/wireless/mediatek/mt7601u/Makefile b/drivers/net/wireless/mediatek/mt7601u/Makefile
new file mode 100644
index 000000000000..ea9ed8a5db4d
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/Makefile
@@ -0,0 +1,9 @@
+ccflags-y += -D__CHECK_ENDIAN__
+
+obj-$(CONFIG_MT7601U) += mt7601u.o
+
+mt7601u-objs = \
+ usb.o init.o main.o mcu.o trace.o dma.o core.o eeprom.o phy.o \
+ mac.o util.o debugfs.o tx.o
+
+CFLAGS_trace.o := -I$(src)
diff --git a/drivers/net/wireless/mediatek/mt7601u/core.c b/drivers/net/wireless/mediatek/mt7601u/core.c
new file mode 100644
index 000000000000..0aabd790f985
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/core.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#include "mt7601u.h"
+
+int mt7601u_wait_asic_ready(struct mt7601u_dev *dev)
+{
+ int i = 100;
+ u32 val;
+
+ do {
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return -EIO;
+
+ val = mt7601u_rr(dev, MT_MAC_CSR0);
+ if (val && ~val)
+ return 0;
+
+ udelay(10);
+ } while (i--);
+
+ return -EIO;
+}
+
+bool mt76_poll(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val,
+ int timeout)
+{
+ u32 cur;
+
+ timeout /= 10;
+ do {
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return false;
+
+ cur = mt7601u_rr(dev, offset) & mask;
+ if (cur == val)
+ return true;
+
+ udelay(10);
+ } while (timeout-- > 0);
+
+ dev_err(dev->dev, "Error: Time out with reg %08x\n", offset);
+
+ return false;
+}
+
+bool mt76_poll_msec(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val,
+ int timeout)
+{
+ u32 cur;
+
+ timeout /= 10;
+ do {
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return false;
+
+ cur = mt7601u_rr(dev, offset) & mask;
+ if (cur == val)
+ return true;
+
+ msleep(10);
+ } while (timeout-- > 0);
+
+ dev_err(dev->dev, "Error: Time out with reg %08x\n", offset);
+
+ return false;
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/debugfs.c b/drivers/net/wireless/mediatek/mt7601u/debugfs.c
new file mode 100644
index 000000000000..fc008475a03b
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/debugfs.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#include <linux/debugfs.h>
+
+#include "mt7601u.h"
+#include "eeprom.h"
+
+static int
+mt76_reg_set(void *data, u64 val)
+{
+ struct mt7601u_dev *dev = data;
+
+ mt76_wr(dev, dev->debugfs_reg, val);
+ return 0;
+}
+
+static int
+mt76_reg_get(void *data, u64 *val)
+{
+ struct mt7601u_dev *dev = data;
+
+ *val = mt76_rr(dev, dev->debugfs_reg);
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n");
+
+static int
+mt7601u_ampdu_stat_read(struct seq_file *file, void *data)
+{
+ struct mt7601u_dev *dev = file->private;
+ int i, j;
+
+#define stat_printf(grp, off, name) \
+ seq_printf(file, #name ":\t%llu\n", dev->stats.grp[off])
+
+ stat_printf(rx_stat, 0, rx_crc_err);
+ stat_printf(rx_stat, 1, rx_phy_err);
+ stat_printf(rx_stat, 2, rx_false_cca);
+ stat_printf(rx_stat, 3, rx_plcp_err);
+ stat_printf(rx_stat, 4, rx_fifo_overflow);
+ stat_printf(rx_stat, 5, rx_duplicate);
+
+ stat_printf(tx_stat, 0, tx_fail_cnt);
+ stat_printf(tx_stat, 1, tx_bcn_cnt);
+ stat_printf(tx_stat, 2, tx_success);
+ stat_printf(tx_stat, 3, tx_retransmit);
+ stat_printf(tx_stat, 4, tx_zero_len);
+ stat_printf(tx_stat, 5, tx_underflow);
+
+ stat_printf(aggr_stat, 0, non_aggr_tx);
+ stat_printf(aggr_stat, 1, aggr_tx);
+
+ stat_printf(zero_len_del, 0, tx_zero_len_del);
+ stat_printf(zero_len_del, 1, rx_zero_len_del);
+#undef stat_printf
+
+ seq_puts(file, "Aggregations stats:\n");
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 8; j++)
+ seq_printf(file, "%08llx ",
+ dev->stats.aggr_n[i * 8 + j]);
+ seq_putc(file, '\n');
+ }
+
+ seq_printf(file, "recent average AMPDU len: %d\n",
+ atomic_read(&dev->avg_ampdu_len));
+
+ return 0;
+}
+
+static int
+mt7601u_ampdu_stat_open(struct inode *inode, struct file *f)
+{
+ return single_open(f, mt7601u_ampdu_stat_read, inode->i_private);
+}
+
+static const struct file_operations fops_ampdu_stat = {
+ .open = mt7601u_ampdu_stat_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int
+mt7601u_eeprom_param_read(struct seq_file *file, void *data)
+{
+ struct mt7601u_dev *dev = file->private;
+ struct mt7601u_rate_power *rp = &dev->ee->power_rate_table;
+ struct tssi_data *td = &dev->ee->tssi_data;
+ int i;
+
+ seq_printf(file, "RF freq offset: %hhx\n", dev->ee->rf_freq_off);
+ seq_printf(file, "RSSI offset: %hhx %hhx\n",
+ dev->ee->rssi_offset[0], dev->ee->rssi_offset[1]);
+ seq_printf(file, "Reference temp: %hhx\n", dev->ee->ref_temp);
+ seq_printf(file, "LNA gain: %hhx\n", dev->ee->lna_gain);
+ seq_printf(file, "Reg channels: %hhu-%hhu\n", dev->ee->reg.start,
+ dev->ee->reg.start + dev->ee->reg.num - 1);
+
+ seq_puts(file, "Per rate power:\n");
+ for (i = 0; i < 2; i++)
+ seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n",
+ rp->cck[i].raw, rp->cck[i].bw20, rp->cck[i].bw40);
+ for (i = 0; i < 4; i++)
+ seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n",
+ rp->ofdm[i].raw, rp->ofdm[i].bw20, rp->ofdm[i].bw40);
+ for (i = 0; i < 4; i++)
+ seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n",
+ rp->ht[i].raw, rp->ht[i].bw20, rp->ht[i].bw40);
+
+ seq_puts(file, "Per channel power:\n");
+ for (i = 0; i < 7; i++)
+ seq_printf(file, "\t tx_power ch%u:%02hhx ch%u:%02hhx\n",
+ i * 2 + 1, dev->ee->chan_pwr[i * 2],
+ i * 2 + 2, dev->ee->chan_pwr[i * 2 + 1]);
+
+ if (!dev->ee->tssi_enabled)
+ return 0;
+
+ seq_puts(file, "TSSI:\n");
+ seq_printf(file, "\t slope:%02hhx\n", td->slope);
+ seq_printf(file, "\t offset=%02hhx %02hhx %02hhx\n",
+ td->offset[0], td->offset[1], td->offset[2]);
+ seq_printf(file, "\t delta_off:%08x\n", td->tx0_delta_offset);
+
+ return 0;
+}
+
+static int
+mt7601u_eeprom_param_open(struct inode *inode, struct file *f)
+{
+ return single_open(f, mt7601u_eeprom_param_read, inode->i_private);
+}
+
+static const struct file_operations fops_eeprom_param = {
+ .open = mt7601u_eeprom_param_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void mt7601u_init_debugfs(struct mt7601u_dev *dev)
+{
+ struct dentry *dir;
+
+ dir = debugfs_create_dir("mt7601u", dev->hw->wiphy->debugfsdir);
+ if (!dir)
+ return;
+
+ debugfs_create_u8("temperature", S_IRUSR, dir, &dev->raw_temp);
+ debugfs_create_u32("temp_mode", S_IRUSR, dir, &dev->temp_mode);
+
+ debugfs_create_u32("regidx", S_IRUSR | S_IWUSR, dir, &dev->debugfs_reg);
+ debugfs_create_file("regval", S_IRUSR | S_IWUSR, dir, dev,
+ &fops_regval);
+ debugfs_create_file("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat);
+ debugfs_create_file("eeprom_param", S_IRUSR, dir, dev,
+ &fops_eeprom_param);
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c
new file mode 100644
index 000000000000..7217da4f1543
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/dma.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#include "mt7601u.h"
+#include "dma.h"
+#include "usb.h"
+#include "trace.h"
+
+static int mt7601u_submit_rx_buf(struct mt7601u_dev *dev,
+ struct mt7601u_dma_buf_rx *e, gfp_t gfp);
+
+static unsigned int ieee80211_get_hdrlen_from_buf(const u8 *data, unsigned len)
+{
+ const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)data;
+ unsigned int hdrlen;
+
+ if (unlikely(len < 10))
+ return 0;
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
+ if (unlikely(hdrlen > len))
+ return 0;
+ return hdrlen;
+}
+
+static struct sk_buff *
+mt7601u_rx_skb_from_seg(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi,
+ void *data, u32 seg_len, u32 truesize, struct page *p)
+{
+ struct sk_buff *skb;
+ u32 true_len, hdr_len = 0, copy, frag;
+
+ skb = alloc_skb(p ? 128 : seg_len, GFP_ATOMIC);
+ if (!skb)
+ return NULL;
+
+ true_len = mt76_mac_process_rx(dev, skb, data, rxwi);
+ if (!true_len || true_len > seg_len)
+ goto bad_frame;
+
+ hdr_len = ieee80211_get_hdrlen_from_buf(data, true_len);
+ if (!hdr_len)
+ goto bad_frame;
+
+ if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) {
+ memcpy(skb_put(skb, hdr_len), data, hdr_len);
+
+ data += hdr_len + 2;
+ true_len -= hdr_len;
+ hdr_len = 0;
+ }
+
+ /* If not doing paged RX allocated skb will always have enough space */
+ copy = (true_len <= skb_tailroom(skb)) ? true_len : hdr_len + 8;
+ frag = true_len - copy;
+
+ memcpy(skb_put(skb, copy), data, copy);
+ data += copy;
+
+ if (frag) {
+ skb_add_rx_frag(skb, 0, p, data - page_address(p),
+ frag, truesize);
+ get_page(p);
+ }
+
+ return skb;
+
+bad_frame:
+ dev_err_ratelimited(dev->dev, "Error: incorrect frame len:%u hdr:%u\n",
+ true_len, hdr_len);
+ dev_kfree_skb(skb);
+ return NULL;
+}
+
+static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data,
+ u32 seg_len, struct page *p)
+{
+ struct sk_buff *skb;
+ struct mt7601u_rxwi *rxwi;
+ u32 fce_info, truesize = seg_len;
+
+ /* DMA_INFO field at the beginning of the segment contains only some of
+ * the information, we need to read the FCE descriptor from the end.
+ */
+ fce_info = get_unaligned_le32(data + seg_len - MT_FCE_INFO_LEN);
+ seg_len -= MT_FCE_INFO_LEN;
+
+ data += MT_DMA_HDR_LEN;
+ seg_len -= MT_DMA_HDR_LEN;
+
+ rxwi = (struct mt7601u_rxwi *) data;
+ data += sizeof(struct mt7601u_rxwi);
+ seg_len -= sizeof(struct mt7601u_rxwi);
+
+ if (unlikely(rxwi->zero[0] || rxwi->zero[1] || rxwi->zero[2]))
+ dev_err_once(dev->dev, "Error: RXWI zero fields are set\n");
+ if (unlikely(MT76_GET(MT_RXD_INFO_TYPE, fce_info)))
+ dev_err_once(dev->dev, "Error: RX path seen a non-pkt urb\n");
+
+ trace_mt_rx(dev, rxwi, fce_info);
+
+ skb = mt7601u_rx_skb_from_seg(dev, rxwi, data, seg_len, truesize, p);
+ if (!skb)
+ return;
+
+ ieee80211_rx_ni(dev->hw, skb);
+}
+
+static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len)
+{
+ u32 min_seg_len = MT_DMA_HDR_LEN + MT_RX_INFO_LEN +
+ sizeof(struct mt7601u_rxwi) + MT_FCE_INFO_LEN;
+ u16 dma_len = get_unaligned_le16(data);
+
+ if (data_len < min_seg_len ||
+ WARN_ON(!dma_len) ||
+ WARN_ON(dma_len + MT_DMA_HDRS > data_len) ||
+ WARN_ON(dma_len & 0x3))
+ return 0;
+
+ return MT_DMA_HDRS + dma_len;
+}
+
+static void
+mt7601u_rx_process_entry(struct mt7601u_dev *dev, struct mt7601u_dma_buf_rx *e)
+{
+ u32 seg_len, data_len = e->urb->actual_length;
+ u8 *data = page_address(e->p);
+ struct page *new_p = NULL;
+ int cnt = 0;
+
+ if (!test_bit(MT7601U_STATE_INITIALIZED, &dev->state))
+ return;
+
+ /* Copy if there is very little data in the buffer. */
+ if (data_len > 512)
+ new_p = dev_alloc_pages(MT_RX_ORDER);
+
+ while ((seg_len = mt7601u_rx_next_seg_len(data, data_len))) {
+ mt7601u_rx_process_seg(dev, data, seg_len, new_p ? e->p : NULL);
+
+ data_len -= seg_len;
+ data += seg_len;
+ cnt++;
+ }
+
+ if (cnt > 1)
+ trace_mt_rx_dma_aggr(dev, cnt, !!new_p);
+
+ if (new_p) {
+ /* we have one extra ref from the allocator */
+ __free_pages(e->p, MT_RX_ORDER);
+
+ e->p = new_p;
+ }
+}
+
+static struct mt7601u_dma_buf_rx *
+mt7601u_rx_get_pending_entry(struct mt7601u_dev *dev)
+{
+ struct mt7601u_rx_queue *q = &dev->rx_q;
+ struct mt7601u_dma_buf_rx *buf = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->rx_lock, flags);
+
+ if (!q->pending)
+ goto out;
+
+ buf = &q->e[q->start];
+ q->pending--;
+ q->start = (q->start + 1) % q->entries;
+out:
+ spin_unlock_irqrestore(&dev->rx_lock, flags);
+
+ return buf;
+}
+
+static void mt7601u_complete_rx(struct urb *urb)
+{
+ struct mt7601u_dev *dev = urb->context;
+ struct mt7601u_rx_queue *q = &dev->rx_q;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->rx_lock, flags);
+
+ if (mt7601u_urb_has_error(urb))
+ dev_err(dev->dev, "Error: RX urb failed:%d\n", urb->status);
+ if (WARN_ONCE(q->e[q->end].urb != urb, "RX urb mismatch"))
+ goto out;
+
+ q->end = (q->end + 1) % q->entries;
+ q->pending++;
+ tasklet_schedule(&dev->rx_tasklet);
+out:
+ spin_unlock_irqrestore(&dev->rx_lock, flags);
+}
+
+static void mt7601u_rx_tasklet(unsigned long data)
+{
+ struct mt7601u_dev *dev = (struct mt7601u_dev *) data;
+ struct mt7601u_dma_buf_rx *e;
+
+ while ((e = mt7601u_rx_get_pending_entry(dev))) {
+ if (e->urb->status)
+ continue;
+
+ mt7601u_rx_process_entry(dev, e);
+ mt7601u_submit_rx_buf(dev, e, GFP_ATOMIC);
+ }
+}
+
+static void mt7601u_complete_tx(struct urb *urb)
+{
+ struct mt7601u_tx_queue *q = urb->context;
+ struct mt7601u_dev *dev = q->dev;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->tx_lock, flags);
+
+ if (mt7601u_urb_has_error(urb))
+ dev_err(dev->dev, "Error: TX urb failed:%d\n", urb->status);
+ if (WARN_ONCE(q->e[q->start].urb != urb, "TX urb mismatch"))
+ goto out;
+
+ skb = q->e[q->start].skb;
+ trace_mt_tx_dma_done(dev, skb);
+
+ mt7601u_tx_status(dev, skb);
+
+ if (q->used == q->entries - q->entries / 8)
+ ieee80211_wake_queue(dev->hw, skb_get_queue_mapping(skb));
+
+ q->start = (q->start + 1) % q->entries;
+ q->used--;
+
+ if (urb->status)
+ goto out;
+
+ set_bit(MT7601U_STATE_MORE_STATS, &dev->state);
+ if (!test_and_set_bit(MT7601U_STATE_READING_STATS, &dev->state))
+ queue_delayed_work(dev->stat_wq, &dev->stat_work,
+ msecs_to_jiffies(10));
+out:
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
+}
+
+static int mt7601u_dma_submit_tx(struct mt7601u_dev *dev,
+ struct sk_buff *skb, u8 ep)
+{
+ struct usb_device *usb_dev = mt7601u_to_usb_dev(dev);
+ unsigned snd_pipe = usb_sndbulkpipe(usb_dev, dev->out_eps[ep]);
+ struct mt7601u_dma_buf_tx *e;
+ struct mt7601u_tx_queue *q = &dev->tx_q[ep];
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&dev->tx_lock, flags);
+
+ if (WARN_ON(q->entries <= q->used)) {
+ ret = -ENOSPC;
+ goto out;
+ }
+
+ e = &q->e[q->end];
+ e->skb = skb;
+ usb_fill_bulk_urb(e->urb, usb_dev, snd_pipe, skb->data, skb->len,
+ mt7601u_complete_tx, q);
+ ret = usb_submit_urb(e->urb, GFP_ATOMIC);
+ if (ret) {
+ /* Special-handle ENODEV from TX urb submission because it will
+ * often be the first ENODEV we see after device is removed.
+ */
+ if (ret == -ENODEV)
+ set_bit(MT7601U_STATE_REMOVED, &dev->state);
+ else
+ dev_err(dev->dev, "Error: TX urb submit failed:%d\n",
+ ret);
+ goto out;
+ }
+
+ q->end = (q->end + 1) % q->entries;
+ q->used++;
+
+ if (q->used >= q->entries)
+ ieee80211_stop_queue(dev->hw, skb_get_queue_mapping(skb));
+out:
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
+
+ return ret;
+}
+
+/* Map hardware Q to USB endpoint number */
+static u8 q2ep(u8 qid)
+{
+ /* TODO: take management packets to queue 5 */
+ return qid + 1;
+}
+
+/* Map USB endpoint number to Q id in the DMA engine */
+static enum mt76_qsel ep2dmaq(u8 ep)
+{
+ if (ep == 5)
+ return MT_QSEL_MGMT;
+ return MT_QSEL_EDCA;
+}
+
+int mt7601u_dma_enqueue_tx(struct mt7601u_dev *dev, struct sk_buff *skb,
+ struct mt76_wcid *wcid, int hw_q)
+{
+ u8 ep = q2ep(hw_q);
+ u32 dma_flags;
+ int ret;
+
+ dma_flags = MT_TXD_PKT_INFO_80211;
+ if (wcid->hw_key_idx == 0xff)
+ dma_flags |= MT_TXD_PKT_INFO_WIV;
+
+ ret = mt7601u_dma_skb_wrap_pkt(skb, ep2dmaq(ep), dma_flags);
+ if (ret)
+ return ret;
+
+ ret = mt7601u_dma_submit_tx(dev, skb, ep);
+ if (ret) {
+ ieee80211_free_txskb(dev->hw, skb);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void mt7601u_kill_rx(struct mt7601u_dev *dev)
+{
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->rx_lock, flags);
+
+ for (i = 0; i < dev->rx_q.entries; i++) {
+ int next = dev->rx_q.end;
+
+ spin_unlock_irqrestore(&dev->rx_lock, flags);
+ usb_poison_urb(dev->rx_q.e[next].urb);
+ spin_lock_irqsave(&dev->rx_lock, flags);
+ }
+
+ spin_unlock_irqrestore(&dev->rx_lock, flags);
+}
+
+static int mt7601u_submit_rx_buf(struct mt7601u_dev *dev,
+ struct mt7601u_dma_buf_rx *e, gfp_t gfp)
+{
+ struct usb_device *usb_dev = mt7601u_to_usb_dev(dev);
+ u8 *buf = page_address(e->p);
+ unsigned pipe;
+ int ret;
+
+ pipe = usb_rcvbulkpipe(usb_dev, dev->in_eps[MT_EP_IN_PKT_RX]);
+
+ usb_fill_bulk_urb(e->urb, usb_dev, pipe, buf, MT_RX_URB_SIZE,
+ mt7601u_complete_rx, dev);
+
+ trace_mt_submit_urb(dev, e->urb);
+ ret = usb_submit_urb(e->urb, gfp);
+ if (ret)
+ dev_err(dev->dev, "Error: submit RX URB failed:%d\n", ret);
+
+ return ret;
+}
+
+static int mt7601u_submit_rx(struct mt7601u_dev *dev)
+{
+ int i, ret;
+
+ for (i = 0; i < dev->rx_q.entries; i++) {
+ ret = mt7601u_submit_rx_buf(dev, &dev->rx_q.e[i], GFP_KERNEL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void mt7601u_free_rx(struct mt7601u_dev *dev)
+{
+ int i;
+
+ for (i = 0; i < dev->rx_q.entries; i++) {
+ __free_pages(dev->rx_q.e[i].p, MT_RX_ORDER);
+ usb_free_urb(dev->rx_q.e[i].urb);
+ }
+}
+
+static int mt7601u_alloc_rx(struct mt7601u_dev *dev)
+{
+ int i;
+
+ memset(&dev->rx_q, 0, sizeof(dev->rx_q));
+ dev->rx_q.dev = dev;
+ dev->rx_q.entries = N_RX_ENTRIES;
+
+ for (i = 0; i < N_RX_ENTRIES; i++) {
+ dev->rx_q.e[i].urb = usb_alloc_urb(0, GFP_KERNEL);
+ dev->rx_q.e[i].p = dev_alloc_pages(MT_RX_ORDER);
+
+ if (!dev->rx_q.e[i].urb || !dev->rx_q.e[i].p)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void mt7601u_free_tx_queue(struct mt7601u_tx_queue *q)
+{
+ int i;
+
+ WARN_ON(q->used);
+
+ for (i = 0; i < q->entries; i++) {
+ usb_poison_urb(q->e[i].urb);
+ usb_free_urb(q->e[i].urb);
+ }
+}
+
+static void mt7601u_free_tx(struct mt7601u_dev *dev)
+{
+ int i;
+
+ for (i = 0; i < __MT_EP_OUT_MAX; i++)
+ mt7601u_free_tx_queue(&dev->tx_q[i]);
+}
+
+static int mt7601u_alloc_tx_queue(struct mt7601u_dev *dev,
+ struct mt7601u_tx_queue *q)
+{
+ int i;
+
+ q->dev = dev;
+ q->entries = N_TX_ENTRIES;
+
+ for (i = 0; i < N_TX_ENTRIES; i++) {
+ q->e[i].urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!q->e[i].urb)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int mt7601u_alloc_tx(struct mt7601u_dev *dev)
+{
+ int i;
+
+ dev->tx_q = devm_kcalloc(dev->dev, __MT_EP_OUT_MAX,
+ sizeof(*dev->tx_q), GFP_KERNEL);
+
+ for (i = 0; i < __MT_EP_OUT_MAX; i++)
+ if (mt7601u_alloc_tx_queue(dev, &dev->tx_q[i]))
+ return -ENOMEM;
+
+ return 0;
+}
+
+int mt7601u_dma_init(struct mt7601u_dev *dev)
+{
+ int ret = -ENOMEM;
+
+ tasklet_init(&dev->rx_tasklet, mt7601u_rx_tasklet, (unsigned long) dev);
+
+ ret = mt7601u_alloc_tx(dev);
+ if (ret)
+ goto err;
+ ret = mt7601u_alloc_rx(dev);
+ if (ret)
+ goto err;
+
+ ret = mt7601u_submit_rx(dev);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ mt7601u_dma_cleanup(dev);
+ return ret;
+}
+
+void mt7601u_dma_cleanup(struct mt7601u_dev *dev)
+{
+ mt7601u_kill_rx(dev);
+
+ tasklet_kill(&dev->rx_tasklet);
+
+ mt7601u_free_rx(dev);
+ mt7601u_free_tx(dev);
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.h b/drivers/net/wireless/mediatek/mt7601u/dma.h
new file mode 100644
index 000000000000..978e8a90b87f
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/dma.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#ifndef __MT7601U_DMA_H
+#define __MT7601U_DMA_H
+
+#include <asm/unaligned.h>
+#include <linux/skbuff.h>
+
+#include "util.h"
+
+#define MT_DMA_HDR_LEN 4
+#define MT_RX_INFO_LEN 4
+#define MT_FCE_INFO_LEN 4
+#define MT_DMA_HDRS (MT_DMA_HDR_LEN + MT_RX_INFO_LEN)
+
+/* Common Tx DMA descriptor fields */
+#define MT_TXD_INFO_LEN GENMASK(15, 0)
+#define MT_TXD_INFO_D_PORT GENMASK(29, 27)
+#define MT_TXD_INFO_TYPE GENMASK(31, 30)
+
+enum mt76_msg_port {
+ WLAN_PORT,
+ CPU_RX_PORT,
+ CPU_TX_PORT,
+ HOST_PORT,
+ VIRTUAL_CPU_RX_PORT,
+ VIRTUAL_CPU_TX_PORT,
+ DISCARD,
+};
+
+enum mt76_info_type {
+ DMA_PACKET,
+ DMA_COMMAND,
+};
+
+/* Tx DMA packet specific flags */
+#define MT_TXD_PKT_INFO_NEXT_VLD BIT(16)
+#define MT_TXD_PKT_INFO_TX_BURST BIT(17)
+#define MT_TXD_PKT_INFO_80211 BIT(19)
+#define MT_TXD_PKT_INFO_TSO BIT(20)
+#define MT_TXD_PKT_INFO_CSO BIT(21)
+#define MT_TXD_PKT_INFO_WIV BIT(24)
+#define MT_TXD_PKT_INFO_QSEL GENMASK(26, 25)
+
+enum mt76_qsel {
+ MT_QSEL_MGMT,
+ MT_QSEL_HCCA,
+ MT_QSEL_EDCA,
+ MT_QSEL_EDCA_2,
+};
+
+/* Tx DMA MCU command specific flags */
+#define MT_TXD_CMD_INFO_SEQ GENMASK(19, 16)
+#define MT_TXD_CMD_INFO_TYPE GENMASK(26, 20)
+
+static inline int mt7601u_dma_skb_wrap(struct sk_buff *skb,
+ enum mt76_msg_port d_port,
+ enum mt76_info_type type, u32 flags)
+{
+ u32 info;
+
+ /* Buffer layout:
+ * | 4B | xfer len | pad | 4B |
+ * | TXINFO | pkt/cmd | zero pad to 4B | zero |
+ *
+ * length field of TXINFO should be set to 'xfer len'.
+ */
+
+ info = flags |
+ MT76_SET(MT_TXD_INFO_LEN, round_up(skb->len, 4)) |
+ MT76_SET(MT_TXD_INFO_D_PORT, d_port) |
+ MT76_SET(MT_TXD_INFO_TYPE, type);
+
+ put_unaligned_le32(info, skb_push(skb, sizeof(info)));
+ return skb_put_padto(skb, round_up(skb->len, 4) + 4);
+}
+
+static inline int
+mt7601u_dma_skb_wrap_pkt(struct sk_buff *skb, enum mt76_qsel qsel, u32 flags)
+{
+ flags |= MT76_SET(MT_TXD_PKT_INFO_QSEL, qsel);
+ return mt7601u_dma_skb_wrap(skb, WLAN_PORT, DMA_PACKET, flags);
+}
+
+/* Common Rx DMA descriptor fields */
+#define MT_RXD_INFO_LEN GENMASK(13, 0)
+#define MT_RXD_INFO_PCIE_INTR BIT(24)
+#define MT_RXD_INFO_QSEL GENMASK(26, 25)
+#define MT_RXD_INFO_PORT GENMASK(29, 27)
+#define MT_RXD_INFO_TYPE GENMASK(31, 30)
+
+/* Rx DMA packet specific flags */
+#define MT_RXD_PKT_INFO_UDP_ERR BIT(16)
+#define MT_RXD_PKT_INFO_TCP_ERR BIT(17)
+#define MT_RXD_PKT_INFO_IP_ERR BIT(18)
+#define MT_RXD_PKT_INFO_PKT_80211 BIT(19)
+#define MT_RXD_PKT_INFO_L3L4_DONE BIT(20)
+#define MT_RXD_PKT_INFO_MAC_LEN GENMASK(23, 21)
+
+/* Rx DMA MCU command specific flags */
+#define MT_RXD_CMD_INFO_SELF_GEN BIT(15)
+#define MT_RXD_CMD_INFO_CMD_SEQ GENMASK(19, 16)
+#define MT_RXD_CMD_INFO_EVT_TYPE GENMASK(23, 20)
+
+enum mt76_evt_type {
+ CMD_DONE,
+ CMD_ERROR,
+ CMD_RETRY,
+ EVENT_PWR_RSP,
+ EVENT_WOW_RSP,
+ EVENT_CARRIER_DETECT_RSP,
+ EVENT_DFS_DETECT_RSP,
+};
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/eeprom.c b/drivers/net/wireless/mediatek/mt7601u/eeprom.c
new file mode 100644
index 000000000000..8d8ee0344f7b
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/eeprom.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#include <linux/of.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/etherdevice.h>
+#include <asm/unaligned.h>
+#include "mt7601u.h"
+#include "eeprom.h"
+
+static bool
+field_valid(u8 val)
+{
+ return val != 0xff;
+}
+
+static s8
+field_validate(u8 val)
+{
+ if (!field_valid(val))
+ return 0;
+
+ return val;
+}
+
+static int
+mt7601u_efuse_read(struct mt7601u_dev *dev, u16 addr, u8 *data,
+ enum mt7601u_eeprom_access_modes mode)
+{
+ u32 val;
+ int i;
+
+ val = mt76_rr(dev, MT_EFUSE_CTRL);
+ val &= ~(MT_EFUSE_CTRL_AIN |
+ MT_EFUSE_CTRL_MODE);
+ val |= MT76_SET(MT_EFUSE_CTRL_AIN, addr & ~0xf) |
+ MT76_SET(MT_EFUSE_CTRL_MODE, mode) |
+ MT_EFUSE_CTRL_KICK;
+ mt76_wr(dev, MT_EFUSE_CTRL, val);
+
+ if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
+ return -ETIMEDOUT;
+
+ val = mt76_rr(dev, MT_EFUSE_CTRL);
+ if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) {
+ /* Parts of eeprom not in the usage map (0x80-0xc0,0xf0)
+ * will not return valid data but it's ok.
+ */
+ memset(data, 0xff, 16);
+ return 0;
+ }
+
+ for (i = 0; i < 4; i++) {
+ val = mt76_rr(dev, MT_EFUSE_DATA(i));
+ put_unaligned_le32(val, data + 4 * i);
+ }
+
+ return 0;
+}
+
+static int
+mt7601u_efuse_physical_size_check(struct mt7601u_dev *dev)
+{
+ const int map_reads = DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16);
+ u8 data[map_reads * 16];
+ int ret, i;
+ u32 start = 0, end = 0, cnt_free;
+
+ for (i = 0; i < map_reads; i++) {
+ ret = mt7601u_efuse_read(dev, MT_EE_USAGE_MAP_START + i * 16,
+ data + i * 16, MT_EE_PHYSICAL_READ);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < MT_EFUSE_USAGE_MAP_SIZE; i++)
+ if (!data[i]) {
+ if (!start)
+ start = MT_EE_USAGE_MAP_START + i;
+ end = MT_EE_USAGE_MAP_START + i;
+ }
+ cnt_free = end - start + 1;
+
+ if (MT_EFUSE_USAGE_MAP_SIZE - cnt_free < 5) {
+ dev_err(dev->dev, "Error: your device needs default EEPROM file and this driver doesn't support it!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static bool
+mt7601u_has_tssi(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1);
+
+ return ~nic_conf1 && (nic_conf1 & MT_EE_NIC_CONF_1_TX_ALC_EN);
+}
+
+static void
+mt7601u_set_chip_cap(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ u16 nic_conf0 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_0);
+ u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1);
+
+ if (!field_valid(nic_conf1 & 0xff))
+ nic_conf1 &= 0xff00;
+
+ dev->ee->tssi_enabled = mt7601u_has_tssi(dev, eeprom) &&
+ !(nic_conf1 & MT_EE_NIC_CONF_1_TEMP_TX_ALC);
+
+ if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL)
+ dev_err(dev->dev,
+ "Error: this driver does not support HW RF ctrl\n");
+
+ if (!field_valid(nic_conf0 >> 8))
+ return;
+
+ if (MT76_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 ||
+ MT76_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1)
+ dev_err(dev->dev,
+ "Error: device has more than 1 RX/TX stream!\n");
+}
+
+static int
+mt7601u_set_macaddr(struct mt7601u_dev *dev, const u8 *eeprom)
+{
+ const void *src = eeprom + MT_EE_MAC_ADDR;
+
+ ether_addr_copy(dev->macaddr, src);
+
+ if (!is_valid_ether_addr(dev->macaddr)) {
+ eth_random_addr(dev->macaddr);
+ dev_info(dev->dev,
+ "Invalid MAC address, using random address %pM\n",
+ dev->macaddr);
+ }
+
+ mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr));
+ mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) |
+ MT76_SET(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
+
+ return 0;
+}
+
+static void mt7601u_set_channel_target_power(struct mt7601u_dev *dev,
+ u8 *eeprom, u8 max_pwr)
+{
+ u8 trgt_pwr = eeprom[MT_EE_TX_TSSI_TARGET_POWER];
+
+ if (trgt_pwr > max_pwr || !trgt_pwr) {
+ dev_warn(dev->dev, "Error: EEPROM trgt power invalid %hhx!\n",
+ trgt_pwr);
+ trgt_pwr = 0x20;
+ }
+
+ memset(dev->ee->chan_pwr, trgt_pwr, sizeof(dev->ee->chan_pwr));
+}
+
+static void
+mt7601u_set_channel_power(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ u32 i, val;
+ u8 max_pwr;
+
+ val = mt7601u_rr(dev, MT_TX_ALC_CFG_0);
+ max_pwr = MT76_GET(MT_TX_ALC_CFG_0_LIMIT_0, val);
+
+ if (mt7601u_has_tssi(dev, eeprom)) {
+ mt7601u_set_channel_target_power(dev, eeprom, max_pwr);
+ return;
+ }
+
+ for (i = 0; i < 14; i++) {
+ s8 power = field_validate(eeprom[MT_EE_TX_POWER_OFFSET + i]);
+
+ if (power > max_pwr || power < 0)
+ power = MT7601U_DEFAULT_TX_POWER;
+
+ dev->ee->chan_pwr[i] = power;
+ }
+}
+
+static void
+mt7601u_set_country_reg(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ /* Note: - region 31 is not valid for mt7601u (see rtmp_init.c)
+ * - comments in rtmp_def.h are incorrect (see rt_channel.c)
+ */
+ static const struct reg_channel_bounds chan_bounds[] = {
+ /* EEPROM country regions 0 - 7 */
+ { 1, 11 }, { 1, 13 }, { 10, 2 }, { 10, 4 },
+ { 14, 1 }, { 1, 14 }, { 3, 7 }, { 5, 9 },
+ /* EEPROM country regions 32 - 33 */
+ { 1, 11 }, { 1, 14 }
+ };
+ u8 val = eeprom[MT_EE_COUNTRY_REGION];
+ int idx = -1;
+
+ if (val < 8)
+ idx = val;
+ if (val > 31 && val < 33)
+ idx = val - 32 + 8;
+
+ if (idx != -1)
+ dev_info(dev->dev,
+ "EEPROM country region %02hhx (channels %hhd-%hhd)\n",
+ val, chan_bounds[idx].start,
+ chan_bounds[idx].start + chan_bounds[idx].num - 1);
+ else
+ idx = 5; /* channels 1 - 14 */
+
+ dev->ee->reg = chan_bounds[idx];
+
+ /* TODO: country region 33 is special - phy should be set to B-mode
+ * before entering channel 14 (see sta/connect.c)
+ */
+}
+
+static void
+mt7601u_set_rf_freq_off(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ u8 comp;
+
+ dev->ee->rf_freq_off = field_validate(eeprom[MT_EE_FREQ_OFFSET]);
+ comp = field_validate(eeprom[MT_EE_FREQ_OFFSET_COMPENSATION]);
+
+ if (comp & BIT(7))
+ dev->ee->rf_freq_off -= comp & 0x7f;
+ else
+ dev->ee->rf_freq_off += comp;
+}
+
+static void
+mt7601u_set_rssi_offset(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ int i;
+ s8 *rssi_offset = dev->ee->rssi_offset;
+
+ for (i = 0; i < 2; i++) {
+ rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET + i];
+
+ if (rssi_offset[i] < -10 || rssi_offset[i] > 10) {
+ dev_warn(dev->dev,
+ "Warning: EEPROM RSSI is invalid %02hhx\n",
+ rssi_offset[i]);
+ rssi_offset[i] = 0;
+ }
+ }
+}
+
+static void
+mt7601u_extra_power_over_mac(struct mt7601u_dev *dev)
+{
+ u32 val;
+
+ val = ((mt7601u_rr(dev, MT_TX_PWR_CFG_1) & 0x0000ff00) >> 8);
+ val |= ((mt7601u_rr(dev, MT_TX_PWR_CFG_2) & 0x0000ff00) << 8);
+ mt7601u_wr(dev, MT_TX_PWR_CFG_7, val);
+
+ val = ((mt7601u_rr(dev, MT_TX_PWR_CFG_4) & 0x0000ff00) >> 8);
+ mt7601u_wr(dev, MT_TX_PWR_CFG_9, val);
+}
+
+static void
+mt7601u_set_power_rate(struct power_per_rate *rate, s8 delta, u8 value)
+{
+ /* Invalid? Note: vendor driver does not handle this */
+ if (value == 0xff)
+ return;
+
+ rate->raw = s6_validate(value);
+ rate->bw20 = s6_to_int(value);
+ /* Note: vendor driver does cap the value to s6 right away */
+ rate->bw40 = rate->bw20 + delta;
+}
+
+static void
+mt7601u_save_power_rate(struct mt7601u_dev *dev, s8 delta, u32 val, int i)
+{
+ struct mt7601u_rate_power *t = &dev->ee->power_rate_table;
+
+ switch (i) {
+ case 0:
+ mt7601u_set_power_rate(&t->cck[0], delta, (val >> 0) & 0xff);
+ mt7601u_set_power_rate(&t->cck[1], delta, (val >> 8) & 0xff);
+ /* Save cck bw20 for fixups of channel 14 */
+ dev->ee->real_cck_bw20[0] = t->cck[0].bw20;
+ dev->ee->real_cck_bw20[1] = t->cck[1].bw20;
+
+ mt7601u_set_power_rate(&t->ofdm[0], delta, (val >> 16) & 0xff);
+ mt7601u_set_power_rate(&t->ofdm[1], delta, (val >> 24) & 0xff);
+ break;
+ case 1:
+ mt7601u_set_power_rate(&t->ofdm[2], delta, (val >> 0) & 0xff);
+ mt7601u_set_power_rate(&t->ofdm[3], delta, (val >> 8) & 0xff);
+ mt7601u_set_power_rate(&t->ht[0], delta, (val >> 16) & 0xff);
+ mt7601u_set_power_rate(&t->ht[1], delta, (val >> 24) & 0xff);
+ break;
+ case 2:
+ mt7601u_set_power_rate(&t->ht[2], delta, (val >> 0) & 0xff);
+ mt7601u_set_power_rate(&t->ht[3], delta, (val >> 8) & 0xff);
+ break;
+ }
+}
+
+static s8
+get_delta(u8 val)
+{
+ s8 ret;
+
+ if (!field_valid(val) || !(val & BIT(7)))
+ return 0;
+
+ ret = val & 0x1f;
+ if (ret > 8)
+ ret = 8;
+ if (val & BIT(6))
+ ret = -ret;
+
+ return ret;
+}
+
+static void
+mt7601u_config_tx_power_per_rate(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ u32 val;
+ s8 bw40_delta;
+ int i;
+
+ bw40_delta = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40]);
+
+ for (i = 0; i < 5; i++) {
+ val = get_unaligned_le32(eeprom + MT_EE_TX_POWER_BYRATE(i));
+
+ mt7601u_save_power_rate(dev, bw40_delta, val, i);
+
+ if (~val)
+ mt7601u_wr(dev, MT_TX_PWR_CFG_0 + i * 4, val);
+ }
+
+ mt7601u_extra_power_over_mac(dev);
+}
+
+static void
+mt7601u_init_tssi_params(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ struct tssi_data *d = &dev->ee->tssi_data;
+
+ if (!dev->ee->tssi_enabled)
+ return;
+
+ d->slope = eeprom[MT_EE_TX_TSSI_SLOPE];
+ d->tx0_delta_offset = eeprom[MT_EE_TX_TSSI_OFFSET] * 1024;
+ d->offset[0] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP];
+ d->offset[1] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP + 1];
+ d->offset[2] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP + 2];
+}
+
+int
+mt7601u_eeprom_init(struct mt7601u_dev *dev)
+{
+ u8 *eeprom;
+ int i, ret;
+
+ ret = mt7601u_efuse_physical_size_check(dev);
+ if (ret)
+ return ret;
+
+ dev->ee = devm_kzalloc(dev->dev, sizeof(*dev->ee), GFP_KERNEL);
+ if (!dev->ee)
+ return -ENOMEM;
+
+ eeprom = kmalloc(MT7601U_EEPROM_SIZE, GFP_KERNEL);
+ if (!eeprom)
+ return -ENOMEM;
+
+ for (i = 0; i + 16 <= MT7601U_EEPROM_SIZE; i += 16) {
+ ret = mt7601u_efuse_read(dev, i, eeprom + i, MT_EE_READ);
+ if (ret)
+ goto out;
+ }
+
+ if (eeprom[MT_EE_VERSION_EE] > MT7601U_EE_MAX_VER)
+ dev_warn(dev->dev,
+ "Warning: unsupported EEPROM version %02hhx\n",
+ eeprom[MT_EE_VERSION_EE]);
+ dev_info(dev->dev, "EEPROM ver:%02hhx fae:%02hhx\n",
+ eeprom[MT_EE_VERSION_EE], eeprom[MT_EE_VERSION_FAE]);
+
+ mt7601u_set_macaddr(dev, eeprom);
+ mt7601u_set_chip_cap(dev, eeprom);
+ mt7601u_set_channel_power(dev, eeprom);
+ mt7601u_set_country_reg(dev, eeprom);
+ mt7601u_set_rf_freq_off(dev, eeprom);
+ mt7601u_set_rssi_offset(dev, eeprom);
+ dev->ee->ref_temp = eeprom[MT_EE_REF_TEMP];
+ dev->ee->lna_gain = eeprom[MT_EE_LNA_GAIN];
+
+ mt7601u_config_tx_power_per_rate(dev, eeprom);
+
+ mt7601u_init_tssi_params(dev, eeprom);
+out:
+ kfree(eeprom);
+ return ret;
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/eeprom.h b/drivers/net/wireless/mediatek/mt7601u/eeprom.h
new file mode 100644
index 000000000000..662d12703b69
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/eeprom.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#ifndef __MT7601U_EEPROM_H
+#define __MT7601U_EEPROM_H
+
+struct mt7601u_dev;
+
+#define MT7601U_EE_MAX_VER 0x0c
+#define MT7601U_EEPROM_SIZE 256
+
+#define MT7601U_DEFAULT_TX_POWER 6
+
+enum mt76_eeprom_field {
+ MT_EE_CHIP_ID = 0x00,
+ MT_EE_VERSION_FAE = 0x02,
+ MT_EE_VERSION_EE = 0x03,
+ MT_EE_MAC_ADDR = 0x04,
+ MT_EE_NIC_CONF_0 = 0x34,
+ MT_EE_NIC_CONF_1 = 0x36,
+ MT_EE_COUNTRY_REGION = 0x39,
+ MT_EE_FREQ_OFFSET = 0x3a,
+ MT_EE_NIC_CONF_2 = 0x42,
+
+ MT_EE_LNA_GAIN = 0x44,
+ MT_EE_RSSI_OFFSET = 0x46,
+
+ MT_EE_TX_POWER_DELTA_BW40 = 0x50,
+ MT_EE_TX_POWER_OFFSET = 0x52,
+
+ MT_EE_TX_TSSI_SLOPE = 0x6e,
+ MT_EE_TX_TSSI_OFFSET_GROUP = 0x6f,
+ MT_EE_TX_TSSI_OFFSET = 0x76,
+
+ MT_EE_TX_TSSI_TARGET_POWER = 0xd0,
+ MT_EE_REF_TEMP = 0xd1,
+ MT_EE_FREQ_OFFSET_COMPENSATION = 0xdb,
+ MT_EE_TX_POWER_BYRATE_BASE = 0xde,
+
+ MT_EE_USAGE_MAP_START = 0x1e0,
+ MT_EE_USAGE_MAP_END = 0x1fc,
+};
+
+#define MT_EE_NIC_CONF_0_RX_PATH GENMASK(3, 0)
+#define MT_EE_NIC_CONF_0_TX_PATH GENMASK(7, 4)
+#define MT_EE_NIC_CONF_0_BOARD_TYPE GENMASK(13, 12)
+
+#define MT_EE_NIC_CONF_1_HW_RF_CTRL BIT(0)
+#define MT_EE_NIC_CONF_1_TEMP_TX_ALC BIT(1)
+#define MT_EE_NIC_CONF_1_LNA_EXT_2G BIT(2)
+#define MT_EE_NIC_CONF_1_LNA_EXT_5G BIT(3)
+#define MT_EE_NIC_CONF_1_TX_ALC_EN BIT(13)
+
+#define MT_EE_NIC_CONF_2_RX_STREAM GENMASK(3, 0)
+#define MT_EE_NIC_CONF_2_TX_STREAM GENMASK(7, 4)
+#define MT_EE_NIC_CONF_2_HW_ANTDIV BIT(8)
+#define MT_EE_NIC_CONF_2_XTAL_OPTION GENMASK(10, 9)
+#define MT_EE_NIC_CONF_2_TEMP_DISABLE BIT(11)
+#define MT_EE_NIC_CONF_2_COEX_METHOD GENMASK(15, 13)
+
+#define MT_EE_TX_POWER_BYRATE(i) (MT_EE_TX_POWER_BYRATE_BASE + \
+ (i) * 4)
+
+#define MT_EFUSE_USAGE_MAP_SIZE (MT_EE_USAGE_MAP_END - \
+ MT_EE_USAGE_MAP_START + 1)
+
+enum mt7601u_eeprom_access_modes {
+ MT_EE_READ = 0,
+ MT_EE_PHYSICAL_READ = 1,
+};
+
+struct power_per_rate {
+ u8 raw; /* validated s6 value */
+ s8 bw20; /* sign-extended int */
+ s8 bw40; /* sign-extended int */
+};
+
+/* Power per rate - one value per two rates */
+struct mt7601u_rate_power {
+ struct power_per_rate cck[2];
+ struct power_per_rate ofdm[4];
+ struct power_per_rate ht[4];
+};
+
+struct reg_channel_bounds {
+ u8 start;
+ u8 num;
+};
+
+struct mt7601u_eeprom_params {
+ bool tssi_enabled;
+ u8 rf_freq_off;
+ s8 rssi_offset[2];
+ s8 ref_temp;
+ s8 lna_gain;
+
+ u8 chan_pwr[14];
+ struct mt7601u_rate_power power_rate_table;
+ s8 real_cck_bw20[2];
+
+ /* TSSI stuff - only with internal TX ALC */
+ struct tssi_data {
+ int tx0_delta_offset;
+ u8 slope;
+ u8 offset[3];
+ } tssi_data;
+
+ struct reg_channel_bounds reg;
+};
+
+int mt7601u_eeprom_init(struct mt7601u_dev *dev);
+
+static inline u32 s6_validate(u32 reg)
+{
+ WARN_ON(reg & ~GENMASK(5, 0));
+ return reg & GENMASK(5, 0);
+}
+
+static inline int s6_to_int(u32 reg)
+{
+ int s6;
+
+ s6 = s6_validate(reg);
+ if (s6 & BIT(5))
+ s6 -= BIT(6);
+
+ return s6;
+}
+
+static inline u32 int_to_s6(int val)
+{
+ if (val < -0x20)
+ return 0x20;
+ if (val > 0x1f)
+ return 0x1f;
+
+ return val & 0x3f;
+}
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c
new file mode 100644
index 000000000000..df3dd56199a7
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/init.c
@@ -0,0 +1,628 @@
+/*
+ * (c) Copyright 2002-2010, Ralink Technology, Inc.
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#include "mt7601u.h"
+#include "eeprom.h"
+#include "trace.h"
+#include "mcu.h"
+
+#include "initvals.h"
+
+static void
+mt7601u_set_wlan_state(struct mt7601u_dev *dev, u32 val, bool enable)
+{
+ int i;
+
+ /* Note: we don't turn off WLAN_CLK because that makes the device
+ * not respond properly on the probe path.
+ * In case anyone (PSM?) wants to use this function we can
+ * bring the clock stuff back and fixup the probe path.
+ */
+
+ if (enable)
+ val |= (MT_WLAN_FUN_CTRL_WLAN_EN |
+ MT_WLAN_FUN_CTRL_WLAN_CLK_EN);
+ else
+ val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN);
+
+ mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val);
+ udelay(20);
+
+ if (enable) {
+ set_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state);
+ } else {
+ clear_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state);
+ return;
+ }
+
+ for (i = 200; i; i--) {
+ val = mt7601u_rr(dev, MT_CMB_CTRL);
+
+ if (val & MT_CMB_CTRL_XTAL_RDY && val & MT_CMB_CTRL_PLL_LD)
+ break;
+
+ udelay(20);
+ }
+
+ /* Note: vendor driver tries to disable/enable wlan here and retry
+ * but the code which does it is so buggy it must have never
+ * triggered, so don't bother.
+ */
+ if (!i)
+ dev_err(dev->dev, "Error: PLL and XTAL check failed!\n");
+}
+
+static void mt7601u_chip_onoff(struct mt7601u_dev *dev, bool enable, bool reset)
+{
+ u32 val;
+
+ mutex_lock(&dev->hw_atomic_mutex);
+
+ val = mt7601u_rr(dev, MT_WLAN_FUN_CTRL);
+
+ if (reset) {
+ val |= MT_WLAN_FUN_CTRL_GPIO_OUT_EN;
+ val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL;
+
+ if (val & MT_WLAN_FUN_CTRL_WLAN_EN) {
+ val |= (MT_WLAN_FUN_CTRL_WLAN_RESET |
+ MT_WLAN_FUN_CTRL_WLAN_RESET_RF);
+ mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val);
+ udelay(20);
+
+ val &= ~(MT_WLAN_FUN_CTRL_WLAN_RESET |
+ MT_WLAN_FUN_CTRL_WLAN_RESET_RF);
+ }
+ }
+
+ mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val);
+ udelay(20);
+
+ mt7601u_set_wlan_state(dev, val, enable);
+
+ mutex_unlock(&dev->hw_atomic_mutex);
+}
+
+static void mt7601u_reset_csr_bbp(struct mt7601u_dev *dev)
+{
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, (MT_MAC_SYS_CTRL_RESET_CSR |
+ MT_MAC_SYS_CTRL_RESET_BBP));
+ mt7601u_wr(dev, MT_USB_DMA_CFG, 0);
+ msleep(1);
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0);
+}
+
+static void mt7601u_init_usb_dma(struct mt7601u_dev *dev)
+{
+ u32 val;
+
+ val = MT76_SET(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, MT_USB_AGGR_TIMEOUT) |
+ MT76_SET(MT_USB_DMA_CFG_RX_BULK_AGG_LMT, MT_USB_AGGR_SIZE_LIMIT) |
+ MT_USB_DMA_CFG_RX_BULK_EN |
+ MT_USB_DMA_CFG_TX_BULK_EN;
+ if (dev->in_max_packet == 512)
+ val |= MT_USB_DMA_CFG_RX_BULK_AGG_EN;
+ mt7601u_wr(dev, MT_USB_DMA_CFG, val);
+
+ val |= MT_USB_DMA_CFG_UDMA_RX_WL_DROP;
+ mt7601u_wr(dev, MT_USB_DMA_CFG, val);
+ val &= ~MT_USB_DMA_CFG_UDMA_RX_WL_DROP;
+ mt7601u_wr(dev, MT_USB_DMA_CFG, val);
+}
+
+static int mt7601u_init_bbp(struct mt7601u_dev *dev)
+{
+ int ret;
+
+ ret = mt7601u_wait_bbp_ready(dev);
+ if (ret)
+ return ret;
+
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, bbp_common_vals,
+ ARRAY_SIZE(bbp_common_vals));
+ if (ret)
+ return ret;
+
+ return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, bbp_chip_vals,
+ ARRAY_SIZE(bbp_chip_vals));
+}
+
+static void
+mt76_init_beacon_offsets(struct mt7601u_dev *dev)
+{
+ u16 base = MT_BEACON_BASE;
+ u32 regs[4] = {};
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ u16 addr = dev->beacon_offsets[i];
+
+ regs[i / 4] |= ((addr - base) / 64) << (8 * (i % 4));
+ }
+
+ for (i = 0; i < 4; i++)
+ mt7601u_wr(dev, MT_BCN_OFFSET(i), regs[i]);
+}
+
+static int mt7601u_write_mac_initvals(struct mt7601u_dev *dev)
+{
+ int ret;
+
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN, mac_common_vals,
+ ARRAY_SIZE(mac_common_vals));
+ if (ret)
+ return ret;
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN,
+ mac_chip_vals, ARRAY_SIZE(mac_chip_vals));
+ if (ret)
+ return ret;
+
+ mt76_init_beacon_offsets(dev);
+
+ mt7601u_wr(dev, MT_AUX_CLK_CFG, 0);
+
+ return 0;
+}
+
+static int mt7601u_init_wcid_mem(struct mt7601u_dev *dev)
+{
+ u32 *vals;
+ int i, ret;
+
+ vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL);
+ if (!vals)
+ return -ENOMEM;
+
+ for (i = 0; i < N_WCIDS; i++) {
+ vals[i * 2] = 0xffffffff;
+ vals[i * 2 + 1] = 0x00ffffff;
+ }
+
+ ret = mt7601u_burst_write_regs(dev, MT_WCID_ADDR_BASE,
+ vals, N_WCIDS * 2);
+ kfree(vals);
+
+ return ret;
+}
+
+static int mt7601u_init_key_mem(struct mt7601u_dev *dev)
+{
+ u32 vals[4] = {};
+
+ return mt7601u_burst_write_regs(dev, MT_SKEY_MODE_BASE_0,
+ vals, ARRAY_SIZE(vals));
+}
+
+static int mt7601u_init_wcid_attr_mem(struct mt7601u_dev *dev)
+{
+ u32 *vals;
+ int i, ret;
+
+ vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL);
+ if (!vals)
+ return -ENOMEM;
+
+ for (i = 0; i < N_WCIDS * 2; i++)
+ vals[i] = 1;
+
+ ret = mt7601u_burst_write_regs(dev, MT_WCID_ATTR_BASE,
+ vals, N_WCIDS * 2);
+ kfree(vals);
+
+ return ret;
+}
+
+static void mt7601u_reset_counters(struct mt7601u_dev *dev)
+{
+ mt7601u_rr(dev, MT_RX_STA_CNT0);
+ mt7601u_rr(dev, MT_RX_STA_CNT1);
+ mt7601u_rr(dev, MT_RX_STA_CNT2);
+ mt7601u_rr(dev, MT_TX_STA_CNT0);
+ mt7601u_rr(dev, MT_TX_STA_CNT1);
+ mt7601u_rr(dev, MT_TX_STA_CNT2);
+}
+
+int mt7601u_mac_start(struct mt7601u_dev *dev)
+{
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
+
+ if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
+ MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 200000))
+ return -ETIMEDOUT;
+
+ dev->rxfilter = MT_RX_FILTR_CFG_CRC_ERR |
+ MT_RX_FILTR_CFG_PHY_ERR | MT_RX_FILTR_CFG_PROMISC |
+ MT_RX_FILTR_CFG_VER_ERR | MT_RX_FILTR_CFG_DUP |
+ MT_RX_FILTR_CFG_CFACK | MT_RX_FILTR_CFG_CFEND |
+ MT_RX_FILTR_CFG_ACK | MT_RX_FILTR_CFG_CTS |
+ MT_RX_FILTR_CFG_RTS | MT_RX_FILTR_CFG_PSPOLL |
+ MT_RX_FILTR_CFG_BA | MT_RX_FILTR_CFG_CTRL_RSV;
+ mt7601u_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter);
+
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL,
+ MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
+
+ if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
+ MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 50))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static void mt7601u_mac_stop_hw(struct mt7601u_dev *dev)
+{
+ int i, ok;
+
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return;
+
+ mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN |
+ MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN |
+ MT_BEACON_TIME_CFG_BEACON_TX);
+
+ if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000))
+ dev_warn(dev->dev, "Warning: TX DMA did not stop!\n");
+
+ /* Page count on TxQ */
+ i = 200;
+ while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) ||
+ (mt76_rr(dev, 0x0a30) & 0x000000ff) ||
+ (mt76_rr(dev, 0x0a34) & 0x00ff00ff)))
+ msleep(10);
+
+ if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000))
+ dev_warn(dev->dev, "Warning: MAC TX did not stop!\n");
+
+ mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX |
+ MT_MAC_SYS_CTRL_ENABLE_TX);
+
+ /* Page count on RxQ */
+ ok = 0;
+ i = 200;
+ while (i--) {
+ if ((mt76_rr(dev, 0x0430) & 0x00ff0000) ||
+ (mt76_rr(dev, 0x0a30) & 0xffffffff) ||
+ (mt76_rr(dev, 0x0a34) & 0xffffffff))
+ ok++;
+ if (ok > 6)
+ break;
+
+ msleep(1);
+ }
+
+ if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000))
+ dev_warn(dev->dev, "Warning: MAC RX did not stop!\n");
+
+ if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000))
+ dev_warn(dev->dev, "Warning: RX DMA did not stop!\n");
+}
+
+void mt7601u_mac_stop(struct mt7601u_dev *dev)
+{
+ mt7601u_mac_stop_hw(dev);
+ flush_delayed_work(&dev->stat_work);
+ cancel_delayed_work_sync(&dev->stat_work);
+}
+
+static void mt7601u_stop_hardware(struct mt7601u_dev *dev)
+{
+ mt7601u_chip_onoff(dev, false, false);
+}
+
+int mt7601u_init_hardware(struct mt7601u_dev *dev)
+{
+ static const u16 beacon_offsets[16] = {
+ /* 512 byte per beacon */
+ 0xc000, 0xc200, 0xc400, 0xc600,
+ 0xc800, 0xca00, 0xcc00, 0xce00,
+ 0xd000, 0xd200, 0xd400, 0xd600,
+ 0xd800, 0xda00, 0xdc00, 0xde00
+ };
+ int ret;
+
+ dev->beacon_offsets = beacon_offsets;
+
+ mt7601u_chip_onoff(dev, true, false);
+
+ ret = mt7601u_wait_asic_ready(dev);
+ if (ret)
+ goto err;
+ ret = mt7601u_mcu_init(dev);
+ if (ret)
+ goto err;
+
+ if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG,
+ MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
+ MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) {
+ ret = -EIO;
+ goto err;
+ }
+
+ /* Wait for ASIC ready after FW load. */
+ ret = mt7601u_wait_asic_ready(dev);
+ if (ret)
+ goto err;
+
+ mt7601u_reset_csr_bbp(dev);
+ mt7601u_init_usb_dma(dev);
+
+ ret = mt7601u_mcu_cmd_init(dev);
+ if (ret)
+ goto err;
+ ret = mt7601u_dma_init(dev);
+ if (ret)
+ goto err_mcu;
+ ret = mt7601u_write_mac_initvals(dev);
+ if (ret)
+ goto err_rx;
+
+ if (!mt76_poll_msec(dev, MT_MAC_STATUS,
+ MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 100)) {
+ ret = -EIO;
+ goto err_rx;
+ }
+
+ ret = mt7601u_init_bbp(dev);
+ if (ret)
+ goto err_rx;
+ ret = mt7601u_init_wcid_mem(dev);
+ if (ret)
+ goto err_rx;
+ ret = mt7601u_init_key_mem(dev);
+ if (ret)
+ goto err_rx;
+ ret = mt7601u_init_wcid_attr_mem(dev);
+ if (ret)
+ goto err_rx;
+
+ mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN |
+ MT_BEACON_TIME_CFG_SYNC_MODE |
+ MT_BEACON_TIME_CFG_TBTT_EN |
+ MT_BEACON_TIME_CFG_BEACON_TX));
+
+ mt7601u_reset_counters(dev);
+
+ mt7601u_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e);
+
+ mt7601u_wr(dev, MT_TXOP_CTRL_CFG, MT76_SET(MT_TXOP_TRUN_EN, 0x3f) |
+ MT76_SET(MT_TXOP_EXT_CCA_DLY, 0x58));
+
+ ret = mt7601u_eeprom_init(dev);
+ if (ret)
+ goto err_rx;
+
+ ret = mt7601u_phy_init(dev);
+ if (ret)
+ goto err_rx;
+
+ mt7601u_set_rx_path(dev, 0);
+ mt7601u_set_tx_dac(dev, 0);
+
+ mt7601u_mac_set_ctrlch(dev, false);
+ mt7601u_bbp_set_ctrlch(dev, false);
+ mt7601u_bbp_set_bw(dev, MT_BW_20);
+
+ return 0;
+
+err_rx:
+ mt7601u_dma_cleanup(dev);
+err_mcu:
+ mt7601u_mcu_cmd_deinit(dev);
+err:
+ mt7601u_chip_onoff(dev, false, false);
+ return ret;
+}
+
+void mt7601u_cleanup(struct mt7601u_dev *dev)
+{
+ if (!test_and_clear_bit(MT7601U_STATE_INITIALIZED, &dev->state))
+ return;
+
+ mt7601u_stop_hardware(dev);
+ mt7601u_dma_cleanup(dev);
+ mt7601u_mcu_cmd_deinit(dev);
+}
+
+struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev)
+{
+ struct ieee80211_hw *hw;
+ struct mt7601u_dev *dev;
+
+ hw = ieee80211_alloc_hw(sizeof(*dev), &mt7601u_ops);
+ if (!hw)
+ return NULL;
+
+ dev = hw->priv;
+ dev->dev = pdev;
+ dev->hw = hw;
+ mutex_init(&dev->vendor_req_mutex);
+ mutex_init(&dev->reg_atomic_mutex);
+ mutex_init(&dev->hw_atomic_mutex);
+ mutex_init(&dev->mutex);
+ spin_lock_init(&dev->tx_lock);
+ spin_lock_init(&dev->rx_lock);
+ spin_lock_init(&dev->lock);
+ spin_lock_init(&dev->con_mon_lock);
+ atomic_set(&dev->avg_ampdu_len, 1);
+
+ dev->stat_wq = alloc_workqueue("mt7601u", WQ_UNBOUND, 0);
+ if (!dev->stat_wq) {
+ ieee80211_free_hw(hw);
+ return NULL;
+ }
+
+ return dev;
+}
+
+#define CHAN2G(_idx, _freq) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_idx), \
+ .max_power = 30, \
+}
+
+static const struct ieee80211_channel mt76_channels_2ghz[] = {
+ CHAN2G(1, 2412),
+ CHAN2G(2, 2417),
+ CHAN2G(3, 2422),
+ CHAN2G(4, 2427),
+ CHAN2G(5, 2432),
+ CHAN2G(6, 2437),
+ CHAN2G(7, 2442),
+ CHAN2G(8, 2447),
+ CHAN2G(9, 2452),
+ CHAN2G(10, 2457),
+ CHAN2G(11, 2462),
+ CHAN2G(12, 2467),
+ CHAN2G(13, 2472),
+ CHAN2G(14, 2484),
+};
+
+#define CCK_RATE(_idx, _rate) { \
+ .bitrate = _rate, \
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE, \
+ .hw_value = (MT_PHY_TYPE_CCK << 8) | _idx, \
+ .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + _idx), \
+}
+
+#define OFDM_RATE(_idx, _rate) { \
+ .bitrate = _rate, \
+ .hw_value = (MT_PHY_TYPE_OFDM << 8) | _idx, \
+ .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | _idx, \
+}
+
+static struct ieee80211_rate mt76_rates[] = {
+ CCK_RATE(0, 10),
+ CCK_RATE(1, 20),
+ CCK_RATE(2, 55),
+ CCK_RATE(3, 110),
+ OFDM_RATE(0, 60),
+ OFDM_RATE(1, 90),
+ OFDM_RATE(2, 120),
+ OFDM_RATE(3, 180),
+ OFDM_RATE(4, 240),
+ OFDM_RATE(5, 360),
+ OFDM_RATE(6, 480),
+ OFDM_RATE(7, 540),
+};
+
+static int
+mt76_init_sband(struct mt7601u_dev *dev, struct ieee80211_supported_band *sband,
+ const struct ieee80211_channel *chan, int n_chan,
+ struct ieee80211_rate *rates, int n_rates)
+{
+ struct ieee80211_sta_ht_cap *ht_cap;
+ void *chanlist;
+ int size;
+
+ size = n_chan * sizeof(*chan);
+ chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
+ if (!chanlist)
+ return -ENOMEM;
+
+ sband->channels = chanlist;
+ sband->n_channels = n_chan;
+ sband->bitrates = rates;
+ sband->n_bitrates = n_rates;
+
+ ht_cap = &sband->ht_cap;
+ ht_cap->ht_supported = true;
+ ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_GRN_FLD |
+ IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_SGI_40 |
+ (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+
+ ht_cap->mcs.rx_mask[0] = 0xff;
+ ht_cap->mcs.rx_mask[4] = 0x1;
+ ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+ ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_2;
+
+ dev->chandef.chan = &sband->channels[0];
+
+ return 0;
+}
+
+static int
+mt76_init_sband_2g(struct mt7601u_dev *dev)
+{
+ dev->sband_2g = devm_kzalloc(dev->dev, sizeof(*dev->sband_2g),
+ GFP_KERNEL);
+ dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = dev->sband_2g;
+
+ WARN_ON(dev->ee->reg.start - 1 + dev->ee->reg.num >
+ ARRAY_SIZE(mt76_channels_2ghz));
+
+ return mt76_init_sband(dev, dev->sband_2g,
+ &mt76_channels_2ghz[dev->ee->reg.start - 1],
+ dev->ee->reg.num,
+ mt76_rates, ARRAY_SIZE(mt76_rates));
+}
+
+int mt7601u_register_device(struct mt7601u_dev *dev)
+{
+ struct ieee80211_hw *hw = dev->hw;
+ struct wiphy *wiphy = hw->wiphy;
+ int ret;
+
+ /* Reserve WCID 0 for mcast - thanks to this APs WCID will go to
+ * entry no. 1 like it does in the vendor driver.
+ */
+ dev->wcid_mask[0] |= 1;
+
+ /* init fake wcid for monitor interfaces */
+ dev->mon_wcid = devm_kmalloc(dev->dev, sizeof(*dev->mon_wcid),
+ GFP_KERNEL);
+ if (!dev->mon_wcid)
+ return -ENOMEM;
+ dev->mon_wcid->idx = 0xff;
+ dev->mon_wcid->hw_key_idx = -1;
+
+ SET_IEEE80211_DEV(hw, dev->dev);
+
+ hw->queues = 4;
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
+ hw->max_rates = 1;
+ hw->max_report_rates = 7;
+ hw->max_rate_tries = 1;
+
+ hw->sta_data_size = sizeof(struct mt76_sta);
+ hw->vif_data_size = sizeof(struct mt76_vif);
+
+ SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
+
+ wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
+ ret = mt76_init_sband_2g(dev);
+ if (ret)
+ return ret;
+
+ INIT_DELAYED_WORK(&dev->mac_work, mt7601u_mac_work);
+ INIT_DELAYED_WORK(&dev->stat_work, mt7601u_tx_stat);
+
+ ret = ieee80211_register_hw(hw);
+ if (ret)
+ return ret;
+
+ mt7601u_init_debugfs(dev);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/initvals.h b/drivers/net/wireless/mediatek/mt7601u/initvals.h
new file mode 100644
index 000000000000..ec11ff66969d
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/initvals.h
@@ -0,0 +1,164 @@
+/*
+ * (c) Copyright 2002-2010, Ralink Technology, Inc.
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#ifndef __MT7601U_INITVALS_H
+#define __MT7601U_INITVALS_H
+
+static const struct mt76_reg_pair bbp_common_vals[] = {
+ { 65, 0x2c },
+ { 66, 0x38 },
+ { 68, 0x0b },
+ { 69, 0x12 },
+ { 70, 0x0a },
+ { 73, 0x10 },
+ { 81, 0x37 },
+ { 82, 0x62 },
+ { 83, 0x6a },
+ { 84, 0x99 },
+ { 86, 0x00 },
+ { 91, 0x04 },
+ { 92, 0x00 },
+ { 103, 0x00 },
+ { 105, 0x05 },
+ { 106, 0x35 },
+};
+
+static const struct mt76_reg_pair bbp_chip_vals[] = {
+ { 1, 0x04 }, { 4, 0x40 }, { 20, 0x06 }, { 31, 0x08 },
+ /* CCK Tx Control */
+ { 178, 0xff },
+ /* AGC/Sync controls */
+ { 66, 0x14 }, { 68, 0x8b }, { 69, 0x12 }, { 70, 0x09 },
+ { 73, 0x11 }, { 75, 0x60 }, { 76, 0x44 }, { 84, 0x9a },
+ { 86, 0x38 }, { 91, 0x07 }, { 92, 0x02 },
+ /* Rx Path Controls */
+ { 99, 0x50 }, { 101, 0x00 }, { 103, 0xc0 }, { 104, 0x92 },
+ { 105, 0x3c }, { 106, 0x03 }, { 128, 0x12 },
+ /* Change RXWI content: Gain Report */
+ { 142, 0x04 }, { 143, 0x37 },
+ /* Change RXWI content: Antenna Report */
+ { 142, 0x03 }, { 143, 0x99 },
+ /* Calibration Index Register */
+ /* CCK Receiver Control */
+ { 160, 0xeb }, { 161, 0xc4 }, { 162, 0x77 }, { 163, 0xf9 },
+ { 164, 0x88 }, { 165, 0x80 }, { 166, 0xff }, { 167, 0xe4 },
+ /* Added AGC controls - these AGC/GLRT registers are accessed
+ * through R195 and R196.
+ */
+ { 195, 0x00 }, { 196, 0x00 },
+ { 195, 0x01 }, { 196, 0x04 },
+ { 195, 0x02 }, { 196, 0x20 },
+ { 195, 0x03 }, { 196, 0x0a },
+ { 195, 0x06 }, { 196, 0x16 },
+ { 195, 0x07 }, { 196, 0x05 },
+ { 195, 0x08 }, { 196, 0x37 },
+ { 195, 0x0a }, { 196, 0x15 },
+ { 195, 0x0b }, { 196, 0x17 },
+ { 195, 0x0c }, { 196, 0x06 },
+ { 195, 0x0d }, { 196, 0x09 },
+ { 195, 0x0e }, { 196, 0x05 },
+ { 195, 0x0f }, { 196, 0x09 },
+ { 195, 0x10 }, { 196, 0x20 },
+ { 195, 0x20 }, { 196, 0x17 },
+ { 195, 0x21 }, { 196, 0x06 },
+ { 195, 0x22 }, { 196, 0x09 },
+ { 195, 0x23 }, { 196, 0x17 },
+ { 195, 0x24 }, { 196, 0x06 },
+ { 195, 0x25 }, { 196, 0x09 },
+ { 195, 0x26 }, { 196, 0x17 },
+ { 195, 0x27 }, { 196, 0x06 },
+ { 195, 0x28 }, { 196, 0x09 },
+ { 195, 0x29 }, { 196, 0x05 },
+ { 195, 0x2a }, { 196, 0x09 },
+ { 195, 0x80 }, { 196, 0x8b },
+ { 195, 0x81 }, { 196, 0x12 },
+ { 195, 0x82 }, { 196, 0x09 },
+ { 195, 0x83 }, { 196, 0x17 },
+ { 195, 0x84 }, { 196, 0x11 },
+ { 195, 0x85 }, { 196, 0x00 },
+ { 195, 0x86 }, { 196, 0x00 },
+ { 195, 0x87 }, { 196, 0x18 },
+ { 195, 0x88 }, { 196, 0x60 },
+ { 195, 0x89 }, { 196, 0x44 },
+ { 195, 0x8a }, { 196, 0x8b },
+ { 195, 0x8b }, { 196, 0x8b },
+ { 195, 0x8c }, { 196, 0x8b },
+ { 195, 0x8d }, { 196, 0x8b },
+ { 195, 0x8e }, { 196, 0x09 },
+ { 195, 0x8f }, { 196, 0x09 },
+ { 195, 0x90 }, { 196, 0x09 },
+ { 195, 0x91 }, { 196, 0x09 },
+ { 195, 0x92 }, { 196, 0x11 },
+ { 195, 0x93 }, { 196, 0x11 },
+ { 195, 0x94 }, { 196, 0x11 },
+ { 195, 0x95 }, { 196, 0x11 },
+ /* PPAD */
+ { 47, 0x80 }, { 60, 0x80 }, { 150, 0xd2 }, { 151, 0x32 },
+ { 152, 0x23 }, { 153, 0x41 }, { 154, 0x00 }, { 155, 0x4f },
+ { 253, 0x7e }, { 195, 0x30 }, { 196, 0x32 }, { 195, 0x31 },
+ { 196, 0x23 }, { 195, 0x32 }, { 196, 0x45 }, { 195, 0x35 },
+ { 196, 0x4a }, { 195, 0x36 }, { 196, 0x5a }, { 195, 0x37 },
+ { 196, 0x5a },
+};
+
+static const struct mt76_reg_pair mac_common_vals[] = {
+ { MT_LEGACY_BASIC_RATE, 0x0000013f },
+ { MT_HT_BASIC_RATE, 0x00008003 },
+ { MT_MAC_SYS_CTRL, 0x00000000 },
+ { MT_RX_FILTR_CFG, 0x00017f97 },
+ { MT_BKOFF_SLOT_CFG, 0x00000209 },
+ { MT_TX_SW_CFG0, 0x00000000 },
+ { MT_TX_SW_CFG1, 0x00080606 },
+ { MT_TX_LINK_CFG, 0x00001020 },
+ { MT_TX_TIMEOUT_CFG, 0x000a2090 },
+ { MT_MAX_LEN_CFG, 0x00003fff },
+ { MT_PBF_TX_MAX_PCNT, 0x1fbf1f1f },
+ { MT_PBF_RX_MAX_PCNT, 0x0000009f },
+ { MT_TX_RETRY_CFG, 0x47d01f0f },
+ { MT_AUTO_RSP_CFG, 0x00000013 },
+ { MT_CCK_PROT_CFG, 0x05740003 },
+ { MT_OFDM_PROT_CFG, 0x05740003 },
+ { MT_MM40_PROT_CFG, 0x03f44084 },
+ { MT_GF20_PROT_CFG, 0x01744004 },
+ { MT_GF40_PROT_CFG, 0x03f44084 },
+ { MT_MM20_PROT_CFG, 0x01744004 },
+ { MT_TXOP_CTRL_CFG, 0x0000583f },
+ { MT_TX_RTS_CFG, 0x01092b20 },
+ { MT_EXP_ACK_TIME, 0x002400ca },
+ { MT_TXOP_HLDR_ET, 0x00000002 },
+ { MT_XIFS_TIME_CFG, 0x33a41010 },
+ { MT_PWR_PIN_CFG, 0x00000000 },
+};
+
+static const struct mt76_reg_pair mac_chip_vals[] = {
+ { MT_TSO_CTRL, 0x00006050 },
+ { MT_BCN_OFFSET(0), 0x18100800 },
+ { MT_BCN_OFFSET(1), 0x38302820 },
+ { MT_PBF_SYS_CTRL, 0x00080c00 },
+ { MT_PBF_CFG, 0x7f723c1f },
+ { MT_FCE_PSE_CTRL, 0x00000001 },
+ { MT_PAUSE_ENABLE_CONTROL1, 0x00000000 },
+ { MT_TX0_RF_GAIN_CORR, 0x003b0005 },
+ { MT_TX0_RF_GAIN_ATTEN, 0x00006900 },
+ { MT_TX0_BB_GAIN_ATTEN, 0x00000400 },
+ { MT_TX_ALC_VGA3, 0x00060006 },
+ { MT_TX_SW_CFG0, 0x00000402 },
+ { MT_TX_SW_CFG1, 0x00000000 },
+ { MT_TX_SW_CFG2, 0x00000000 },
+ { MT_HEADER_TRANS_CTRL_REG, 0x00000000 },
+ { MT_FCE_CSO, 0x0000030f },
+ { MT_FCE_PARAMETERS, 0x00256f0f },
+};
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/initvals_phy.h b/drivers/net/wireless/mediatek/mt7601u/initvals_phy.h
new file mode 100644
index 000000000000..a2bdc3e322bf
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/initvals_phy.h
@@ -0,0 +1,291 @@
+/*
+ * (c) Copyright 2002-2010, Ralink Technology, Inc.
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#ifndef __MT7601U_PHY_INITVALS_H
+#define __MT7601U_PHY_INITVALS_H
+
+#define RF_REG_PAIR(bank, reg, value) \
+ { MT_MCU_MEMMAP_RF | (bank) << 16 | (reg), value }
+
+static const struct mt76_reg_pair rf_central[] = {
+ /* Bank 0 - for central blocks: BG, PLL, XTAL, LO, ADC/DAC */
+ RF_REG_PAIR(0, 0, 0x02),
+ RF_REG_PAIR(0, 1, 0x01),
+ RF_REG_PAIR(0, 2, 0x11),
+ RF_REG_PAIR(0, 3, 0xff),
+ RF_REG_PAIR(0, 4, 0x0a),
+ RF_REG_PAIR(0, 5, 0x20),
+ RF_REG_PAIR(0, 6, 0x00),
+ /* B/G */
+ RF_REG_PAIR(0, 7, 0x00),
+ RF_REG_PAIR(0, 8, 0x00),
+ RF_REG_PAIR(0, 9, 0x00),
+ RF_REG_PAIR(0, 10, 0x00),
+ RF_REG_PAIR(0, 11, 0x21),
+ /* XO */
+ RF_REG_PAIR(0, 13, 0x00), /* 40mhz xtal */
+ /* RF_REG_PAIR(0, 13, 0x13), */ /* 20mhz xtal */
+ RF_REG_PAIR(0, 14, 0x7c),
+ RF_REG_PAIR(0, 15, 0x22),
+ RF_REG_PAIR(0, 16, 0x80),
+ /* PLL */
+ RF_REG_PAIR(0, 17, 0x99),
+ RF_REG_PAIR(0, 18, 0x99),
+ RF_REG_PAIR(0, 19, 0x09),
+ RF_REG_PAIR(0, 20, 0x50),
+ RF_REG_PAIR(0, 21, 0xb0),
+ RF_REG_PAIR(0, 22, 0x00),
+ RF_REG_PAIR(0, 23, 0xc5),
+ RF_REG_PAIR(0, 24, 0xfc),
+ RF_REG_PAIR(0, 25, 0x40),
+ RF_REG_PAIR(0, 26, 0x4d),
+ RF_REG_PAIR(0, 27, 0x02),
+ RF_REG_PAIR(0, 28, 0x72),
+ RF_REG_PAIR(0, 29, 0x01),
+ RF_REG_PAIR(0, 30, 0x00),
+ RF_REG_PAIR(0, 31, 0x00),
+ /* test ports */
+ RF_REG_PAIR(0, 32, 0x00),
+ RF_REG_PAIR(0, 33, 0x00),
+ RF_REG_PAIR(0, 34, 0x23),
+ RF_REG_PAIR(0, 35, 0x01), /* change setting to reduce spurs */
+ RF_REG_PAIR(0, 36, 0x00),
+ RF_REG_PAIR(0, 37, 0x00),
+ /* ADC/DAC */
+ RF_REG_PAIR(0, 38, 0x00),
+ RF_REG_PAIR(0, 39, 0x20),
+ RF_REG_PAIR(0, 40, 0x00),
+ RF_REG_PAIR(0, 41, 0xd0),
+ RF_REG_PAIR(0, 42, 0x1b),
+ RF_REG_PAIR(0, 43, 0x02),
+ RF_REG_PAIR(0, 44, 0x00),
+};
+
+static const struct mt76_reg_pair rf_channel[] = {
+ RF_REG_PAIR(4, 0, 0x01),
+ RF_REG_PAIR(4, 1, 0x00),
+ RF_REG_PAIR(4, 2, 0x00),
+ RF_REG_PAIR(4, 3, 0x00),
+ /* LDO */
+ RF_REG_PAIR(4, 4, 0x00),
+ RF_REG_PAIR(4, 5, 0x08),
+ RF_REG_PAIR(4, 6, 0x00),
+ /* RX */
+ RF_REG_PAIR(4, 7, 0x5b),
+ RF_REG_PAIR(4, 8, 0x52),
+ RF_REG_PAIR(4, 9, 0xb6),
+ RF_REG_PAIR(4, 10, 0x57),
+ RF_REG_PAIR(4, 11, 0x33),
+ RF_REG_PAIR(4, 12, 0x22),
+ RF_REG_PAIR(4, 13, 0x3d),
+ RF_REG_PAIR(4, 14, 0x3e),
+ RF_REG_PAIR(4, 15, 0x13),
+ RF_REG_PAIR(4, 16, 0x22),
+ RF_REG_PAIR(4, 17, 0x23),
+ RF_REG_PAIR(4, 18, 0x02),
+ RF_REG_PAIR(4, 19, 0xa4),
+ RF_REG_PAIR(4, 20, 0x01),
+ RF_REG_PAIR(4, 21, 0x12),
+ RF_REG_PAIR(4, 22, 0x80),
+ RF_REG_PAIR(4, 23, 0xb3),
+ RF_REG_PAIR(4, 24, 0x00), /* reserved */
+ RF_REG_PAIR(4, 25, 0x00), /* reserved */
+ RF_REG_PAIR(4, 26, 0x00), /* reserved */
+ RF_REG_PAIR(4, 27, 0x00), /* reserved */
+ /* LOGEN */
+ RF_REG_PAIR(4, 28, 0x18),
+ RF_REG_PAIR(4, 29, 0xee),
+ RF_REG_PAIR(4, 30, 0x6b),
+ RF_REG_PAIR(4, 31, 0x31),
+ RF_REG_PAIR(4, 32, 0x5d),
+ RF_REG_PAIR(4, 33, 0x00), /* reserved */
+ /* TX */
+ RF_REG_PAIR(4, 34, 0x96),
+ RF_REG_PAIR(4, 35, 0x55),
+ RF_REG_PAIR(4, 36, 0x08),
+ RF_REG_PAIR(4, 37, 0xbb),
+ RF_REG_PAIR(4, 38, 0xb3),
+ RF_REG_PAIR(4, 39, 0xb3),
+ RF_REG_PAIR(4, 40, 0x03),
+ RF_REG_PAIR(4, 41, 0x00), /* reserved */
+ RF_REG_PAIR(4, 42, 0x00), /* reserved */
+ RF_REG_PAIR(4, 43, 0xc5),
+ RF_REG_PAIR(4, 44, 0xc5),
+ RF_REG_PAIR(4, 45, 0xc5),
+ RF_REG_PAIR(4, 46, 0x07),
+ RF_REG_PAIR(4, 47, 0xa8),
+ RF_REG_PAIR(4, 48, 0xef),
+ RF_REG_PAIR(4, 49, 0x1a),
+ /* PA */
+ RF_REG_PAIR(4, 54, 0x07),
+ RF_REG_PAIR(4, 55, 0xa7),
+ RF_REG_PAIR(4, 56, 0xcc),
+ RF_REG_PAIR(4, 57, 0x14),
+ RF_REG_PAIR(4, 58, 0x07),
+ RF_REG_PAIR(4, 59, 0xa8),
+ RF_REG_PAIR(4, 60, 0xd7),
+ RF_REG_PAIR(4, 61, 0x10),
+ RF_REG_PAIR(4, 62, 0x1c),
+ RF_REG_PAIR(4, 63, 0x00), /* reserved */
+};
+
+static const struct mt76_reg_pair rf_vga[] = {
+ RF_REG_PAIR(5, 0, 0x47),
+ RF_REG_PAIR(5, 1, 0x00),
+ RF_REG_PAIR(5, 2, 0x00),
+ RF_REG_PAIR(5, 3, 0x08),
+ RF_REG_PAIR(5, 4, 0x04),
+ RF_REG_PAIR(5, 5, 0x20),
+ RF_REG_PAIR(5, 6, 0x3a),
+ RF_REG_PAIR(5, 7, 0x3a),
+ RF_REG_PAIR(5, 8, 0x00),
+ RF_REG_PAIR(5, 9, 0x00),
+ RF_REG_PAIR(5, 10, 0x10),
+ RF_REG_PAIR(5, 11, 0x10),
+ RF_REG_PAIR(5, 12, 0x10),
+ RF_REG_PAIR(5, 13, 0x10),
+ RF_REG_PAIR(5, 14, 0x10),
+ RF_REG_PAIR(5, 15, 0x20),
+ RF_REG_PAIR(5, 16, 0x22),
+ RF_REG_PAIR(5, 17, 0x7c),
+ RF_REG_PAIR(5, 18, 0x00),
+ RF_REG_PAIR(5, 19, 0x00),
+ RF_REG_PAIR(5, 20, 0x00),
+ RF_REG_PAIR(5, 21, 0xf1),
+ RF_REG_PAIR(5, 22, 0x11),
+ RF_REG_PAIR(5, 23, 0x02),
+ RF_REG_PAIR(5, 24, 0x41),
+ RF_REG_PAIR(5, 25, 0x20),
+ RF_REG_PAIR(5, 26, 0x00),
+ RF_REG_PAIR(5, 27, 0xd7),
+ RF_REG_PAIR(5, 28, 0xa2),
+ RF_REG_PAIR(5, 29, 0x20),
+ RF_REG_PAIR(5, 30, 0x49),
+ RF_REG_PAIR(5, 31, 0x20),
+ RF_REG_PAIR(5, 32, 0x04),
+ RF_REG_PAIR(5, 33, 0xf1),
+ RF_REG_PAIR(5, 34, 0xa1),
+ RF_REG_PAIR(5, 35, 0x01),
+ RF_REG_PAIR(5, 41, 0x00),
+ RF_REG_PAIR(5, 42, 0x00),
+ RF_REG_PAIR(5, 43, 0x00),
+ RF_REG_PAIR(5, 44, 0x00),
+ RF_REG_PAIR(5, 45, 0x00),
+ RF_REG_PAIR(5, 46, 0x00),
+ RF_REG_PAIR(5, 47, 0x00),
+ RF_REG_PAIR(5, 48, 0x00),
+ RF_REG_PAIR(5, 49, 0x00),
+ RF_REG_PAIR(5, 50, 0x00),
+ RF_REG_PAIR(5, 51, 0x00),
+ RF_REG_PAIR(5, 52, 0x00),
+ RF_REG_PAIR(5, 53, 0x00),
+ RF_REG_PAIR(5, 54, 0x00),
+ RF_REG_PAIR(5, 55, 0x00),
+ RF_REG_PAIR(5, 56, 0x00),
+ RF_REG_PAIR(5, 57, 0x00),
+ RF_REG_PAIR(5, 58, 0x31),
+ RF_REG_PAIR(5, 59, 0x31),
+ RF_REG_PAIR(5, 60, 0x0a),
+ RF_REG_PAIR(5, 61, 0x02),
+ RF_REG_PAIR(5, 62, 0x00),
+ RF_REG_PAIR(5, 63, 0x00),
+};
+
+/* TODO: BBP178 is set to 0xff for "CCK CH14 OBW" which overrides the settings
+ * from channel switching. Seems stupid at best.
+ */
+static const struct mt76_reg_pair bbp_high_temp[] = {
+ { 75, 0x60 },
+ { 92, 0x02 },
+ { 178, 0xff }, /* For CCK CH14 OBW */
+ { 195, 0x88 }, { 196, 0x60 },
+}, bbp_high_temp_bw20[] = {
+ { 69, 0x12 },
+ { 91, 0x07 },
+ { 195, 0x23 }, { 196, 0x17 },
+ { 195, 0x24 }, { 196, 0x06 },
+ { 195, 0x81 }, { 196, 0x12 },
+ { 195, 0x83 }, { 196, 0x17 },
+}, bbp_high_temp_bw40[] = {
+ { 69, 0x15 },
+ { 91, 0x04 },
+ { 195, 0x23 }, { 196, 0x12 },
+ { 195, 0x24 }, { 196, 0x08 },
+ { 195, 0x81 }, { 196, 0x15 },
+ { 195, 0x83 }, { 196, 0x16 },
+}, bbp_low_temp[] = {
+ { 178, 0xff }, /* For CCK CH14 OBW */
+}, bbp_low_temp_bw20[] = {
+ { 69, 0x12 },
+ { 75, 0x5e },
+ { 91, 0x07 },
+ { 92, 0x02 },
+ { 195, 0x23 }, { 196, 0x17 },
+ { 195, 0x24 }, { 196, 0x06 },
+ { 195, 0x81 }, { 196, 0x12 },
+ { 195, 0x83 }, { 196, 0x17 },
+ { 195, 0x88 }, { 196, 0x5e },
+}, bbp_low_temp_bw40[] = {
+ { 69, 0x15 },
+ { 75, 0x5c },
+ { 91, 0x04 },
+ { 92, 0x03 },
+ { 195, 0x23 }, { 196, 0x10 },
+ { 195, 0x24 }, { 196, 0x08 },
+ { 195, 0x81 }, { 196, 0x15 },
+ { 195, 0x83 }, { 196, 0x16 },
+ { 195, 0x88 }, { 196, 0x5b },
+}, bbp_normal_temp[] = {
+ { 75, 0x60 },
+ { 92, 0x02 },
+ { 178, 0xff }, /* For CCK CH14 OBW */
+ { 195, 0x88 }, { 196, 0x60 },
+}, bbp_normal_temp_bw20[] = {
+ { 69, 0x12 },
+ { 91, 0x07 },
+ { 195, 0x23 }, { 196, 0x17 },
+ { 195, 0x24 }, { 196, 0x06 },
+ { 195, 0x81 }, { 196, 0x12 },
+ { 195, 0x83 }, { 196, 0x17 },
+}, bbp_normal_temp_bw40[] = {
+ { 69, 0x15 },
+ { 91, 0x04 },
+ { 195, 0x23 }, { 196, 0x12 },
+ { 195, 0x24 }, { 196, 0x08 },
+ { 195, 0x81 }, { 196, 0x15 },
+ { 195, 0x83 }, { 196, 0x16 },
+};
+
+#define BBP_TABLE(arr) { arr, ARRAY_SIZE(arr), }
+
+static const struct reg_table {
+ const struct mt76_reg_pair *regs;
+ size_t n;
+} bbp_mode_table[3][3] = {
+ {
+ BBP_TABLE(bbp_normal_temp_bw20),
+ BBP_TABLE(bbp_normal_temp_bw40),
+ BBP_TABLE(bbp_normal_temp),
+ }, {
+ BBP_TABLE(bbp_high_temp_bw20),
+ BBP_TABLE(bbp_high_temp_bw40),
+ BBP_TABLE(bbp_high_temp),
+ }, {
+ BBP_TABLE(bbp_low_temp_bw20),
+ BBP_TABLE(bbp_low_temp_bw40),
+ BBP_TABLE(bbp_low_temp),
+ }
+};
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c
new file mode 100644
index 000000000000..7514bce1ac91
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/mac.c
@@ -0,0 +1,573 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#include "mt7601u.h"
+#include "trace.h"
+#include <linux/etherdevice.h>
+
+static void
+mt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate)
+{
+ u8 idx = MT76_GET(MT_TXWI_RATE_MCS, rate);
+
+ txrate->idx = 0;
+ txrate->flags = 0;
+ txrate->count = 1;
+
+ switch (MT76_GET(MT_TXWI_RATE_PHY_MODE, rate)) {
+ case MT_PHY_TYPE_OFDM:
+ txrate->idx = idx + 4;
+ return;
+ case MT_PHY_TYPE_CCK:
+ if (idx >= 8)
+ idx -= 8;
+
+ txrate->idx = idx;
+ return;
+ case MT_PHY_TYPE_HT_GF:
+ txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
+ /* fall through */
+ case MT_PHY_TYPE_HT:
+ txrate->flags |= IEEE80211_TX_RC_MCS;
+ txrate->idx = idx;
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ if (MT76_GET(MT_TXWI_RATE_BW, rate) == MT_PHY_BW_40)
+ txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+
+ if (rate & MT_TXWI_RATE_SGI)
+ txrate->flags |= IEEE80211_TX_RC_SHORT_GI;
+}
+
+static void
+mt76_mac_fill_tx_status(struct mt7601u_dev *dev, struct ieee80211_tx_info *info,
+ struct mt76_tx_status *st)
+{
+ struct ieee80211_tx_rate *rate = info->status.rates;
+ int cur_idx, last_rate;
+ int i;
+
+ last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1);
+ mt76_mac_process_tx_rate(&rate[last_rate], st->rate);
+ if (last_rate < IEEE80211_TX_MAX_RATES - 1)
+ rate[last_rate + 1].idx = -1;
+
+ cur_idx = rate[last_rate].idx + st->retry;
+ for (i = 0; i <= last_rate; i++) {
+ rate[i].flags = rate[last_rate].flags;
+ rate[i].idx = max_t(int, 0, cur_idx - i);
+ rate[i].count = 1;
+ }
+
+ if (last_rate > 0)
+ rate[last_rate - 1].count = st->retry + 1 - last_rate;
+
+ info->status.ampdu_len = 1;
+ info->status.ampdu_ack_len = st->success;
+
+ if (st->is_probe)
+ info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+
+ if (st->aggr)
+ info->flags |= IEEE80211_TX_CTL_AMPDU |
+ IEEE80211_TX_STAT_AMPDU;
+
+ if (!st->ack_req)
+ info->flags |= IEEE80211_TX_CTL_NO_ACK;
+ else if (st->success)
+ info->flags |= IEEE80211_TX_STAT_ACK;
+}
+
+u16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev,
+ const struct ieee80211_tx_rate *rate, u8 *nss_val)
+{
+ u16 rateval;
+ u8 phy, rate_idx;
+ u8 nss = 1;
+ u8 bw = 0;
+
+ if (rate->flags & IEEE80211_TX_RC_MCS) {
+ rate_idx = rate->idx;
+ nss = 1 + (rate->idx >> 3);
+ phy = MT_PHY_TYPE_HT;
+ if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD)
+ phy = MT_PHY_TYPE_HT_GF;
+ if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ bw = 1;
+ } else {
+ const struct ieee80211_rate *r;
+ int band = dev->chandef.chan->band;
+ u16 val;
+
+ r = &dev->hw->wiphy->bands[band]->bitrates[rate->idx];
+ if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+ val = r->hw_value_short;
+ else
+ val = r->hw_value;
+
+ phy = val >> 8;
+ rate_idx = val & 0xff;
+ bw = 0;
+ }
+
+ rateval = MT76_SET(MT_RXWI_RATE_MCS, rate_idx);
+ rateval |= MT76_SET(MT_RXWI_RATE_PHY, phy);
+ rateval |= MT76_SET(MT_RXWI_RATE_BW, bw);
+ if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+ rateval |= MT_RXWI_RATE_SGI;
+
+ *nss_val = nss;
+ return rateval;
+}
+
+void mt76_mac_wcid_set_rate(struct mt7601u_dev *dev, struct mt76_wcid *wcid,
+ const struct ieee80211_tx_rate *rate)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ wcid->tx_rate = mt76_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss);
+ wcid->tx_rate_set = true;
+ spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+struct mt76_tx_status mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev)
+{
+ struct mt76_tx_status stat = {};
+ u32 val;
+
+ val = mt7601u_rr(dev, MT_TX_STAT_FIFO);
+ stat.valid = !!(val & MT_TX_STAT_FIFO_VALID);
+ stat.success = !!(val & MT_TX_STAT_FIFO_SUCCESS);
+ stat.aggr = !!(val & MT_TX_STAT_FIFO_AGGR);
+ stat.ack_req = !!(val & MT_TX_STAT_FIFO_ACKREQ);
+ stat.pktid = MT76_GET(MT_TX_STAT_FIFO_PID_TYPE, val);
+ stat.wcid = MT76_GET(MT_TX_STAT_FIFO_WCID, val);
+ stat.rate = MT76_GET(MT_TX_STAT_FIFO_RATE, val);
+
+ return stat;
+}
+
+void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat)
+{
+ struct ieee80211_tx_info info = {};
+ struct ieee80211_sta *sta = NULL;
+ struct mt76_wcid *wcid = NULL;
+ void *msta;
+
+ rcu_read_lock();
+ if (stat->wcid < ARRAY_SIZE(dev->wcid))
+ wcid = rcu_dereference(dev->wcid[stat->wcid]);
+
+ if (wcid) {
+ msta = container_of(wcid, struct mt76_sta, wcid);
+ sta = container_of(msta, struct ieee80211_sta,
+ drv_priv);
+ }
+
+ mt76_mac_fill_tx_status(dev, &info, stat);
+ ieee80211_tx_status_noskb(dev->hw, sta, &info);
+ rcu_read_unlock();
+}
+
+void mt7601u_mac_set_protection(struct mt7601u_dev *dev, bool legacy_prot,
+ int ht_mode)
+{
+ int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION;
+ bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+ u32 prot[6];
+ bool ht_rts[4] = {};
+ int i;
+
+ prot[0] = MT_PROT_NAV_SHORT |
+ MT_PROT_TXOP_ALLOW_ALL |
+ MT_PROT_RTS_THR_EN;
+ prot[1] = prot[0];
+ if (legacy_prot)
+ prot[1] |= MT_PROT_CTRL_CTS2SELF;
+
+ prot[2] = prot[4] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_BW20;
+ prot[3] = prot[5] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_ALL;
+
+ if (legacy_prot) {
+ prot[2] |= MT_PROT_RATE_CCK_11;
+ prot[3] |= MT_PROT_RATE_CCK_11;
+ prot[4] |= MT_PROT_RATE_CCK_11;
+ prot[5] |= MT_PROT_RATE_CCK_11;
+ } else {
+ prot[2] |= MT_PROT_RATE_OFDM_24;
+ prot[3] |= MT_PROT_RATE_DUP_OFDM_24;
+ prot[4] |= MT_PROT_RATE_OFDM_24;
+ prot[5] |= MT_PROT_RATE_DUP_OFDM_24;
+ }
+
+ switch (mode) {
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
+ break;
+
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
+ ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true;
+ break;
+
+ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
+ ht_rts[1] = ht_rts[3] = true;
+ break;
+
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
+ ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true;
+ break;
+ }
+
+ if (non_gf)
+ ht_rts[2] = ht_rts[3] = true;
+
+ for (i = 0; i < 4; i++)
+ if (ht_rts[i])
+ prot[i + 2] |= MT_PROT_CTRL_RTS_CTS;
+
+ for (i = 0; i < 6; i++)
+ mt7601u_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]);
+}
+
+void mt7601u_mac_set_short_preamble(struct mt7601u_dev *dev, bool short_preamb)
+{
+ if (short_preamb)
+ mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
+ else
+ mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
+}
+
+void mt7601u_mac_config_tsf(struct mt7601u_dev *dev, bool enable, int interval)
+{
+ u32 val = mt7601u_rr(dev, MT_BEACON_TIME_CFG);
+
+ val &= ~(MT_BEACON_TIME_CFG_TIMER_EN |
+ MT_BEACON_TIME_CFG_SYNC_MODE |
+ MT_BEACON_TIME_CFG_TBTT_EN);
+
+ if (!enable) {
+ mt7601u_wr(dev, MT_BEACON_TIME_CFG, val);
+ return;
+ }
+
+ val &= ~MT_BEACON_TIME_CFG_INTVAL;
+ val |= MT76_SET(MT_BEACON_TIME_CFG_INTVAL, interval << 4) |
+ MT_BEACON_TIME_CFG_TIMER_EN |
+ MT_BEACON_TIME_CFG_SYNC_MODE |
+ MT_BEACON_TIME_CFG_TBTT_EN;
+}
+
+static void mt7601u_check_mac_err(struct mt7601u_dev *dev)
+{
+ u32 val = mt7601u_rr(dev, 0x10f4);
+
+ if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5))))
+ return;
+
+ dev_err(dev->dev, "Error: MAC specific condition occurred\n");
+
+ mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR);
+ udelay(10);
+ mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR);
+}
+
+void mt7601u_mac_work(struct work_struct *work)
+{
+ struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev,
+ mac_work.work);
+ struct {
+ u32 addr_base;
+ u32 span;
+ u64 *stat_base;
+ } spans[] = {
+ { MT_RX_STA_CNT0, 3, dev->stats.rx_stat },
+ { MT_TX_STA_CNT0, 3, dev->stats.tx_stat },
+ { MT_TX_AGG_STAT, 1, dev->stats.aggr_stat },
+ { MT_MPDU_DENSITY_CNT, 1, dev->stats.zero_len_del },
+ { MT_TX_AGG_CNT_BASE0, 8, &dev->stats.aggr_n[0] },
+ { MT_TX_AGG_CNT_BASE1, 8, &dev->stats.aggr_n[16] },
+ };
+ u32 sum, n;
+ int i, j, k;
+
+ /* Note: using MCU_RANDOM_READ is actually slower then reading all the
+ * registers by hand. MCU takes ca. 20ms to complete read of 24
+ * registers while reading them one by one will takes roughly
+ * 24*200us =~ 5ms.
+ */
+
+ k = 0;
+ n = 0;
+ sum = 0;
+ for (i = 0; i < ARRAY_SIZE(spans); i++)
+ for (j = 0; j < spans[i].span; j++) {
+ u32 val = mt7601u_rr(dev, spans[i].addr_base + j * 4);
+
+ spans[i].stat_base[j * 2] += val & 0xffff;
+ spans[i].stat_base[j * 2 + 1] += val >> 16;
+
+ /* Calculate average AMPDU length */
+ if (spans[i].addr_base != MT_TX_AGG_CNT_BASE0 &&
+ spans[i].addr_base != MT_TX_AGG_CNT_BASE1)
+ continue;
+
+ n += (val >> 16) + (val & 0xffff);
+ sum += (val & 0xffff) * (1 + k * 2) +
+ (val >> 16) * (2 + k * 2);
+ k++;
+ }
+
+ atomic_set(&dev->avg_ampdu_len, n ? DIV_ROUND_CLOSEST(sum, n) : 1);
+
+ mt7601u_check_mac_err(dev);
+
+ ieee80211_queue_delayed_work(dev->hw, &dev->mac_work, 10 * HZ);
+}
+
+void
+mt7601u_mac_wcid_setup(struct mt7601u_dev *dev, u8 idx, u8 vif_idx, u8 *mac)
+{
+ u8 zmac[ETH_ALEN] = {};
+ u32 attr;
+
+ attr = MT76_SET(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) |
+ MT76_SET(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8));
+
+ mt76_wr(dev, MT_WCID_ATTR(idx), attr);
+
+ if (mac)
+ memcpy(zmac, mac, sizeof(zmac));
+
+ mt7601u_addr_wr(dev, MT_WCID_ADDR(idx), zmac);
+}
+
+void mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev)
+{
+ struct ieee80211_sta *sta;
+ struct mt76_wcid *wcid;
+ void *msta;
+ u8 min_factor = 3;
+ int i;
+
+ rcu_read_lock();
+ for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) {
+ wcid = rcu_dereference(dev->wcid[i]);
+ if (!wcid)
+ continue;
+
+ msta = container_of(wcid, struct mt76_sta, wcid);
+ sta = container_of(msta, struct ieee80211_sta, drv_priv);
+
+ min_factor = min(min_factor, sta->ht_cap.ampdu_factor);
+ }
+ rcu_read_unlock();
+
+ mt7601u_wr(dev, MT_MAX_LEN_CFG, 0xa0fff |
+ MT76_SET(MT_MAX_LEN_CFG_AMPDU, min_factor));
+}
+
+static void
+mt76_mac_process_rate(struct ieee80211_rx_status *status, u16 rate)
+{
+ u8 idx = MT76_GET(MT_RXWI_RATE_MCS, rate);
+
+ switch (MT76_GET(MT_RXWI_RATE_PHY, rate)) {
+ case MT_PHY_TYPE_OFDM:
+ if (WARN_ON(idx >= 8))
+ idx = 0;
+ idx += 4;
+
+ status->rate_idx = idx;
+ return;
+ case MT_PHY_TYPE_CCK:
+ if (idx >= 8) {
+ idx -= 8;
+ status->flag |= RX_FLAG_SHORTPRE;
+ }
+
+ if (WARN_ON(idx >= 4))
+ idx = 0;
+
+ status->rate_idx = idx;
+ return;
+ case MT_PHY_TYPE_HT_GF:
+ status->flag |= RX_FLAG_HT_GF;
+ /* fall through */
+ case MT_PHY_TYPE_HT:
+ status->flag |= RX_FLAG_HT;
+ status->rate_idx = idx;
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ if (rate & MT_RXWI_RATE_SGI)
+ status->flag |= RX_FLAG_SHORT_GI;
+
+ if (rate & MT_RXWI_RATE_STBC)
+ status->flag |= 1 << RX_FLAG_STBC_SHIFT;
+
+ if (rate & MT_RXWI_RATE_BW)
+ status->flag |= RX_FLAG_40MHZ;
+}
+
+static void
+mt7601u_rx_monitor_beacon(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi,
+ u16 rate, int rssi)
+{
+ dev->bcn_freq_off = rxwi->freq_off;
+ dev->bcn_phy_mode = MT76_GET(MT_RXWI_RATE_PHY, rate);
+ dev->avg_rssi = (dev->avg_rssi * 15) / 16 + (rssi << 8);
+}
+
+static int
+mt7601u_rx_is_our_beacon(struct mt7601u_dev *dev, u8 *data)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data;
+
+ return ieee80211_is_beacon(hdr->frame_control) &&
+ ether_addr_equal(hdr->addr2, dev->ap_bssid);
+}
+
+u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb,
+ u8 *data, void *rxi)
+{
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+ struct mt7601u_rxwi *rxwi = rxi;
+ u32 len, ctl = le32_to_cpu(rxwi->ctl);
+ u16 rate = le16_to_cpu(rxwi->rate);
+ int rssi;
+
+ len = MT76_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
+ if (len < 10)
+ return 0;
+
+ if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) {
+ status->flag |= RX_FLAG_DECRYPTED;
+ status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
+ }
+
+ status->chains = BIT(0);
+ rssi = mt7601u_phy_get_rssi(dev, rxwi, rate);
+ status->chain_signal[0] = status->signal = rssi;
+ status->freq = dev->chandef.chan->center_freq;
+ status->band = dev->chandef.chan->band;
+
+ mt76_mac_process_rate(status, rate);
+
+ spin_lock_bh(&dev->con_mon_lock);
+ if (mt7601u_rx_is_our_beacon(dev, data))
+ mt7601u_rx_monitor_beacon(dev, rxwi, rate, rssi);
+ else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_U2M))
+ dev->avg_rssi = (dev->avg_rssi * 15) / 16 + (rssi << 8);
+ spin_unlock_bh(&dev->con_mon_lock);
+
+ return len;
+}
+
+static enum mt76_cipher_type
+mt76_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
+{
+ memset(key_data, 0, 32);
+ if (!key)
+ return MT_CIPHER_NONE;
+
+ if (key->keylen > 32)
+ return MT_CIPHER_NONE;
+
+ memcpy(key_data, key->key, key->keylen);
+
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ return MT_CIPHER_WEP40;
+ case WLAN_CIPHER_SUITE_WEP104:
+ return MT_CIPHER_WEP104;
+ case WLAN_CIPHER_SUITE_TKIP:
+ return MT_CIPHER_TKIP;
+ case WLAN_CIPHER_SUITE_CCMP:
+ return MT_CIPHER_AES_CCMP;
+ default:
+ return MT_CIPHER_NONE;
+ }
+}
+
+int mt76_mac_wcid_set_key(struct mt7601u_dev *dev, u8 idx,
+ struct ieee80211_key_conf *key)
+{
+ enum mt76_cipher_type cipher;
+ u8 key_data[32];
+ u8 iv_data[8];
+ u32 val;
+
+ cipher = mt76_mac_get_key_info(key, key_data);
+ if (cipher == MT_CIPHER_NONE && key)
+ return -EINVAL;
+
+ trace_set_key(dev, idx);
+
+ mt7601u_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data));
+
+ memset(iv_data, 0, sizeof(iv_data));
+ if (key) {
+ iv_data[3] = key->keyidx << 6;
+ if (cipher >= MT_CIPHER_TKIP) {
+ /* Note: start with 1 to comply with spec,
+ * (see comment on common/cmm_wpa.c:4291).
+ */
+ iv_data[0] |= 1;
+ iv_data[3] |= 0x20;
+ }
+ }
+ mt7601u_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data));
+
+ val = mt7601u_rr(dev, MT_WCID_ATTR(idx));
+ val &= ~MT_WCID_ATTR_PKEY_MODE & ~MT_WCID_ATTR_PKEY_MODE_EXT;
+ val |= MT76_SET(MT_WCID_ATTR_PKEY_MODE, cipher & 7) |
+ MT76_SET(MT_WCID_ATTR_PKEY_MODE_EXT, cipher >> 3);
+ val &= ~MT_WCID_ATTR_PAIRWISE;
+ val |= MT_WCID_ATTR_PAIRWISE *
+ !!(key && key->flags & IEEE80211_KEY_FLAG_PAIRWISE);
+ mt7601u_wr(dev, MT_WCID_ATTR(idx), val);
+
+ return 0;
+}
+
+int mt76_mac_shared_key_setup(struct mt7601u_dev *dev, u8 vif_idx, u8 key_idx,
+ struct ieee80211_key_conf *key)
+{
+ enum mt76_cipher_type cipher;
+ u8 key_data[32];
+ u32 val;
+
+ cipher = mt76_mac_get_key_info(key, key_data);
+ if (cipher == MT_CIPHER_NONE && key)
+ return -EINVAL;
+
+ trace_set_shared_key(dev, vif_idx, key_idx);
+
+ mt7601u_wr_copy(dev, MT_SKEY(vif_idx, key_idx),
+ key_data, sizeof(key_data));
+
+ val = mt76_rr(dev, MT_SKEY_MODE(vif_idx));
+ val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx));
+ val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx);
+ mt76_wr(dev, MT_SKEY_MODE(vif_idx), val);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.h b/drivers/net/wireless/mediatek/mt7601u/mac.h
new file mode 100644
index 000000000000..2c22d63c63a2
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/mac.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#ifndef __MT76_MAC_H
+#define __MT76_MAC_H
+
+struct mt76_tx_status {
+ u8 valid:1;
+ u8 success:1;
+ u8 aggr:1;
+ u8 ack_req:1;
+ u8 is_probe:1;
+ u8 wcid;
+ u8 pktid;
+ u8 retry;
+ u16 rate;
+} __packed __aligned(2);
+
+/* Note: values in original "RSSI" and "SNR" fields are not actually what they
+ * are called for MT7601U, names used by this driver are educated guesses
+ * (see vendor mac/ral_omac.c).
+ */
+struct mt7601u_rxwi {
+ __le32 rxinfo;
+
+ __le32 ctl;
+
+ __le16 frag_sn;
+ __le16 rate;
+
+ u8 unknown;
+ u8 zero[3];
+
+ u8 snr;
+ u8 ant;
+ u8 gain;
+ u8 freq_off;
+
+ __le32 resv2;
+ __le32 expert_ant;
+} __packed __aligned(4);
+
+#define MT_RXINFO_BA BIT(0)
+#define MT_RXINFO_DATA BIT(1)
+#define MT_RXINFO_NULL BIT(2)
+#define MT_RXINFO_FRAG BIT(3)
+#define MT_RXINFO_U2M BIT(4)
+#define MT_RXINFO_MULTICAST BIT(5)
+#define MT_RXINFO_BROADCAST BIT(6)
+#define MT_RXINFO_MYBSS BIT(7)
+#define MT_RXINFO_CRCERR BIT(8)
+#define MT_RXINFO_ICVERR BIT(9)
+#define MT_RXINFO_MICERR BIT(10)
+#define MT_RXINFO_AMSDU BIT(11)
+#define MT_RXINFO_HTC BIT(12)
+#define MT_RXINFO_RSSI BIT(13)
+#define MT_RXINFO_L2PAD BIT(14)
+#define MT_RXINFO_AMPDU BIT(15)
+#define MT_RXINFO_DECRYPT BIT(16)
+#define MT_RXINFO_BSSIDX3 BIT(17)
+#define MT_RXINFO_WAPI_KEY BIT(18)
+#define MT_RXINFO_PN_LEN GENMASK(21, 19)
+#define MT_RXINFO_SW_PKT_80211 BIT(22)
+#define MT_RXINFO_TCP_SUM_BYPASS BIT(28)
+#define MT_RXINFO_IP_SUM_BYPASS BIT(29)
+#define MT_RXINFO_TCP_SUM_ERR BIT(30)
+#define MT_RXINFO_IP_SUM_ERR BIT(31)
+
+#define MT_RXWI_CTL_WCID GENMASK(7, 0)
+#define MT_RXWI_CTL_KEY_IDX GENMASK(9, 8)
+#define MT_RXWI_CTL_BSS_IDX GENMASK(12, 10)
+#define MT_RXWI_CTL_UDF GENMASK(15, 13)
+#define MT_RXWI_CTL_MPDU_LEN GENMASK(27, 16)
+#define MT_RXWI_CTL_TID GENMASK(31, 28)
+
+#define MT_RXWI_FRAG GENMASK(3, 0)
+#define MT_RXWI_SN GENMASK(15, 4)
+
+#define MT_RXWI_RATE_MCS GENMASK(6, 0)
+#define MT_RXWI_RATE_BW BIT(7)
+#define MT_RXWI_RATE_SGI BIT(8)
+#define MT_RXWI_RATE_STBC GENMASK(10, 9)
+#define MT_RXWI_RATE_ETXBF BIT(11)
+#define MT_RXWI_RATE_SND BIT(12)
+#define MT_RXWI_RATE_ITXBF BIT(13)
+#define MT_RXWI_RATE_PHY GENMASK(15, 14)
+
+#define MT_RXWI_GAIN_RSSI_VAL GENMASK(5, 0)
+#define MT_RXWI_GAIN_RSSI_LNA_ID GENMASK(7, 6)
+#define MT_RXWI_ANT_AUX_LNA BIT(7)
+
+#define MT_RXWI_EANT_ENC_ANT_ID GENMASK(7, 0)
+
+enum mt76_phy_type {
+ MT_PHY_TYPE_CCK,
+ MT_PHY_TYPE_OFDM,
+ MT_PHY_TYPE_HT,
+ MT_PHY_TYPE_HT_GF,
+};
+
+enum mt76_phy_bandwidth {
+ MT_PHY_BW_20,
+ MT_PHY_BW_40,
+};
+
+struct mt76_txwi {
+ __le16 flags;
+ __le16 rate_ctl;
+
+ u8 ack_ctl;
+ u8 wcid;
+ __le16 len_ctl;
+
+ __le32 iv;
+
+ __le32 eiv;
+
+ u8 aid;
+ u8 txstream;
+ __le16 ctl;
+} __packed __aligned(4);
+
+#define MT_TXWI_FLAGS_FRAG BIT(0)
+#define MT_TXWI_FLAGS_MMPS BIT(1)
+#define MT_TXWI_FLAGS_CFACK BIT(2)
+#define MT_TXWI_FLAGS_TS BIT(3)
+#define MT_TXWI_FLAGS_AMPDU BIT(4)
+#define MT_TXWI_FLAGS_MPDU_DENSITY GENMASK(7, 5)
+#define MT_TXWI_FLAGS_TXOP GENMASK(9, 8)
+#define MT_TXWI_FLAGS_CWMIN GENMASK(12, 10)
+#define MT_TXWI_FLAGS_NO_RATE_FALLBACK BIT(13)
+#define MT_TXWI_FLAGS_TX_RPT BIT(14)
+#define MT_TXWI_FLAGS_TX_RATE_LUT BIT(15)
+
+#define MT_TXWI_RATE_MCS GENMASK(6, 0)
+#define MT_TXWI_RATE_BW BIT(7)
+#define MT_TXWI_RATE_SGI BIT(8)
+#define MT_TXWI_RATE_STBC GENMASK(10, 9)
+#define MT_TXWI_RATE_PHY_MODE GENMASK(15, 14)
+
+#define MT_TXWI_ACK_CTL_REQ BIT(0)
+#define MT_TXWI_ACK_CTL_NSEQ BIT(1)
+#define MT_TXWI_ACK_CTL_BA_WINDOW GENMASK(7, 2)
+
+#define MT_TXWI_LEN_BYTE_CNT GENMASK(11, 0)
+#define MT_TXWI_LEN_PKTID GENMASK(15, 12)
+
+#define MT_TXWI_CTL_TX_POWER_ADJ GENMASK(3, 0)
+#define MT_TXWI_CTL_CHAN_CHECK_PKT BIT(4)
+#define MT_TXWI_CTL_PIFS_REV BIT(6)
+
+u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb,
+ u8 *data, void *rxi);
+int mt76_mac_wcid_set_key(struct mt7601u_dev *dev, u8 idx,
+ struct ieee80211_key_conf *key);
+void mt76_mac_wcid_set_rate(struct mt7601u_dev *dev, struct mt76_wcid *wcid,
+ const struct ieee80211_tx_rate *rate);
+
+int mt76_mac_shared_key_setup(struct mt7601u_dev *dev, u8 vif_idx, u8 key_idx,
+ struct ieee80211_key_conf *key);
+u16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev,
+ const struct ieee80211_tx_rate *rate, u8 *nss_val);
+struct mt76_tx_status
+mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev);
+void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat);
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/main.c b/drivers/net/wireless/mediatek/mt7601u/main.c
new file mode 100644
index 000000000000..169384b48b27
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/main.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#include "mt7601u.h"
+#include "mac.h"
+#include <linux/etherdevice.h>
+#include <linux/version.h>
+
+static int mt7601u_start(struct ieee80211_hw *hw)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ int ret;
+
+ mutex_lock(&dev->mutex);
+
+ ret = mt7601u_mac_start(dev);
+ if (ret)
+ goto out;
+
+ ieee80211_queue_delayed_work(dev->hw, &dev->mac_work,
+ MT_CALIBRATE_INTERVAL);
+ ieee80211_queue_delayed_work(dev->hw, &dev->cal_work,
+ MT_CALIBRATE_INTERVAL);
+out:
+ mutex_unlock(&dev->mutex);
+ return ret;
+}
+
+static void mt7601u_stop(struct ieee80211_hw *hw)
+{
+ struct mt7601u_dev *dev = hw->priv;
+
+ mutex_lock(&dev->mutex);
+
+ cancel_delayed_work_sync(&dev->cal_work);
+ cancel_delayed_work_sync(&dev->mac_work);
+ mt7601u_mac_stop(dev);
+
+ mutex_unlock(&dev->mutex);
+}
+
+static int mt7601u_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
+ unsigned int idx = 0;
+ unsigned int wcid = GROUP_WCID(idx);
+
+ /* Note: for AP do the AP-STA things mt76 does:
+ * - beacon offsets
+ * - do mac address tricks
+ * - shift vif idx
+ */
+ mvif->idx = idx;
+
+ if (dev->wcid_mask[wcid / BITS_PER_LONG] & BIT(wcid % BITS_PER_LONG))
+ return -ENOSPC;
+ dev->wcid_mask[wcid / BITS_PER_LONG] |= BIT(wcid % BITS_PER_LONG);
+ mvif->group_wcid.idx = wcid;
+ mvif->group_wcid.hw_key_idx = -1;
+
+ return 0;
+}
+
+static void mt7601u_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
+ unsigned int wcid = mvif->group_wcid.idx;
+
+ dev->wcid_mask[wcid / BITS_PER_LONG] &= ~BIT(wcid % BITS_PER_LONG);
+}
+
+static int mt7601u_config(struct ieee80211_hw *hw, u32 changed)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ int ret = 0;
+
+ mutex_lock(&dev->mutex);
+
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ ieee80211_stop_queues(hw);
+ ret = mt7601u_phy_set_channel(dev, &hw->conf.chandef);
+ ieee80211_wake_queues(hw);
+ }
+
+ mutex_unlock(&dev->mutex);
+
+ return ret;
+}
+
+static void
+mt76_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
+ unsigned int *total_flags, u64 multicast)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ u32 flags = 0;
+
+#define MT76_FILTER(_flag, _hw) do { \
+ flags |= *total_flags & FIF_##_flag; \
+ dev->rxfilter &= ~(_hw); \
+ dev->rxfilter |= !(flags & FIF_##_flag) * (_hw); \
+ } while (0)
+
+ mutex_lock(&dev->mutex);
+
+ dev->rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS;
+
+ MT76_FILTER(OTHER_BSS, MT_RX_FILTR_CFG_PROMISC);
+ MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR);
+ MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR);
+ MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK |
+ MT_RX_FILTR_CFG_CTS |
+ MT_RX_FILTR_CFG_CFEND |
+ MT_RX_FILTR_CFG_CFACK |
+ MT_RX_FILTR_CFG_BA |
+ MT_RX_FILTR_CFG_CTRL_RSV);
+ MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL);
+
+ *total_flags = flags;
+ mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter);
+
+ mutex_unlock(&dev->mutex);
+}
+
+static void
+mt7601u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info, u32 changed)
+{
+ struct mt7601u_dev *dev = hw->priv;
+
+ mutex_lock(&dev->mutex);
+
+ if (changed & BSS_CHANGED_ASSOC)
+ mt7601u_phy_con_cal_onoff(dev, info);
+
+ if (changed & BSS_CHANGED_BSSID) {
+ mt7601u_addr_wr(dev, MT_MAC_BSSID_DW0, info->bssid);
+
+ /* Note: this is a hack because beacon_int is not changed
+ * on leave nor is any more appropriate event generated.
+ * rt2x00 doesn't seem to be bothered though.
+ */
+ if (is_zero_ether_addr(info->bssid))
+ mt7601u_mac_config_tsf(dev, false, 0);
+ }
+
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ mt7601u_wr(dev, MT_LEGACY_BASIC_RATE, info->basic_rates);
+ mt7601u_wr(dev, MT_HT_FBK_CFG0, 0x65432100);
+ mt7601u_wr(dev, MT_HT_FBK_CFG1, 0xedcba980);
+ mt7601u_wr(dev, MT_LG_FBK_CFG0, 0xedcba988);
+ mt7601u_wr(dev, MT_LG_FBK_CFG1, 0x00002100);
+ }
+
+ if (changed & BSS_CHANGED_BEACON_INT)
+ mt7601u_mac_config_tsf(dev, true, info->beacon_int);
+
+ if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT)
+ mt7601u_mac_set_protection(dev, info->use_cts_prot,
+ info->ht_operation_mode);
+
+ if (changed & BSS_CHANGED_ERP_PREAMBLE)
+ mt7601u_mac_set_short_preamble(dev, info->use_short_preamble);
+
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ int slottime = info->use_short_slot ? 9 : 20;
+
+ mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG,
+ MT_BKOFF_SLOT_CFG_SLOTTIME, slottime);
+ }
+
+ if (changed & BSS_CHANGED_ASSOC)
+ mt7601u_phy_recalibrate_after_assoc(dev);
+
+ mutex_unlock(&dev->mutex);
+}
+
+static int
+mt76_wcid_alloc(struct mt7601u_dev *dev)
+{
+ int i, idx = 0;
+
+ for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) {
+ idx = ffs(~dev->wcid_mask[i]);
+ if (!idx)
+ continue;
+
+ idx--;
+ dev->wcid_mask[i] |= BIT(idx);
+ break;
+ }
+
+ idx = i * BITS_PER_LONG + idx;
+ if (idx > 119)
+ return -1;
+
+ return idx;
+}
+
+static int
+mt7601u_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
+ struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
+ int ret = 0;
+ int idx = 0;
+
+ mutex_lock(&dev->mutex);
+
+ idx = mt76_wcid_alloc(dev);
+ if (idx < 0) {
+ ret = -ENOSPC;
+ goto out;
+ }
+
+ msta->wcid.idx = idx;
+ msta->wcid.hw_key_idx = -1;
+ mt7601u_mac_wcid_setup(dev, idx, mvif->idx, sta->addr);
+ mt76_clear(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx));
+ rcu_assign_pointer(dev->wcid[idx], &msta->wcid);
+ mt7601u_mac_set_ampdu_factor(dev);
+
+out:
+ mutex_unlock(&dev->mutex);
+
+ return ret;
+}
+
+static int
+mt7601u_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
+ int idx = msta->wcid.idx;
+
+ mutex_lock(&dev->mutex);
+ rcu_assign_pointer(dev->wcid[idx], NULL);
+ mt76_set(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx));
+ dev->wcid_mask[idx / BITS_PER_LONG] &= ~BIT(idx % BITS_PER_LONG);
+ mt7601u_mac_wcid_setup(dev, idx, 0, NULL);
+ mt7601u_mac_set_ampdu_factor(dev);
+ mutex_unlock(&dev->mutex);
+
+ return 0;
+}
+
+static void
+mt7601u_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ enum sta_notify_cmd cmd, struct ieee80211_sta *sta)
+{
+}
+
+static void
+mt7601u_sw_scan(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ const u8 *mac_addr)
+{
+ struct mt7601u_dev *dev = hw->priv;
+
+ mt7601u_agc_save(dev);
+ set_bit(MT7601U_STATE_SCANNING, &dev->state);
+}
+
+static void
+mt7601u_sw_scan_complete(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct mt7601u_dev *dev = hw->priv;
+
+ mt7601u_agc_restore(dev);
+ clear_bit(MT7601U_STATE_SCANNING, &dev->state);
+}
+
+static int
+mt7601u_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 mt7601u_dev *dev = hw->priv;
+ struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
+ struct mt76_sta *msta = sta ? (struct mt76_sta *) sta->drv_priv : NULL;
+ struct mt76_wcid *wcid = msta ? &msta->wcid : &mvif->group_wcid;
+ int idx = key->keyidx;
+ int ret;
+
+ if (cmd == SET_KEY) {
+ key->hw_key_idx = wcid->idx;
+ wcid->hw_key_idx = idx;
+ } else {
+ if (idx == wcid->hw_key_idx)
+ wcid->hw_key_idx = -1;
+
+ key = NULL;
+ }
+
+ if (!msta) {
+ if (key || wcid->hw_key_idx == idx) {
+ ret = mt76_mac_wcid_set_key(dev, wcid->idx, key);
+ if (ret)
+ return ret;
+ }
+
+ return mt76_mac_shared_key_setup(dev, mvif->idx, idx, key);
+ }
+
+ return mt76_mac_wcid_set_key(dev, msta->wcid.idx, key);
+}
+
+static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+{
+ struct mt7601u_dev *dev = hw->priv;
+
+ mt76_rmw_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH, value);
+
+ return 0;
+}
+
+static int
+mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
+
+ WARN_ON(msta->wcid.idx > GROUP_WCID(0));
+
+ switch (action) {
+ case IEEE80211_AMPDU_RX_START:
+ mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
+ break;
+ case IEEE80211_AMPDU_RX_STOP:
+ mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4,
+ BIT(16 + tid));
+ break;
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+ ieee80211_send_bar(vif, sta->addr, tid, msta->agg_ssn[tid]);
+ break;
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+ break;
+ case IEEE80211_AMPDU_TX_START:
+ msta->agg_ssn[tid] = *ssn << 4;
+ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+ }
+
+ return 0;
+}
+
+static void
+mt76_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
+ struct ieee80211_sta_rates *rates;
+ struct ieee80211_tx_rate rate = {};
+
+ rcu_read_lock();
+ rates = rcu_dereference(sta->rates);
+
+ if (!rates)
+ goto out;
+
+ rate.idx = rates->rate[0].idx;
+ rate.flags = rates->rate[0].flags;
+ mt76_mac_wcid_set_rate(dev, &msta->wcid, &rate);
+
+out:
+ rcu_read_unlock();
+}
+
+const struct ieee80211_ops mt7601u_ops = {
+ .tx = mt7601u_tx,
+ .start = mt7601u_start,
+ .stop = mt7601u_stop,
+ .add_interface = mt7601u_add_interface,
+ .remove_interface = mt7601u_remove_interface,
+ .config = mt7601u_config,
+ .configure_filter = mt76_configure_filter,
+ .bss_info_changed = mt7601u_bss_info_changed,
+ .sta_add = mt7601u_sta_add,
+ .sta_remove = mt7601u_sta_remove,
+ .sta_notify = mt7601u_sta_notify,
+ .set_key = mt7601u_set_key,
+ .conf_tx = mt7601u_conf_tx,
+ .sw_scan_start = mt7601u_sw_scan,
+ .sw_scan_complete = mt7601u_sw_scan_complete,
+ .ampdu_action = mt76_ampdu_action,
+ .sta_rate_tbl_update = mt76_sta_rate_tbl_update,
+ .set_rts_threshold = mt7601u_set_rts_threshold,
+};
diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.c b/drivers/net/wireless/mediatek/mt7601u/mcu.c
new file mode 100644
index 000000000000..fbb1986eda3c
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/mcu.c
@@ -0,0 +1,534 @@
+/*
+ * (c) Copyright 2002-2010, Ralink Technology, Inc.
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/usb.h>
+#include <linux/skbuff.h>
+
+#include "mt7601u.h"
+#include "dma.h"
+#include "mcu.h"
+#include "usb.h"
+#include "trace.h"
+
+#define MCU_FW_URB_MAX_PAYLOAD 0x3800
+#define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12)
+#define MCU_RESP_URB_SIZE 1024
+
+static inline int firmware_running(struct mt7601u_dev *dev)
+{
+ return mt7601u_rr(dev, MT_MCU_COM_REG0) == 1;
+}
+
+static inline void skb_put_le32(struct sk_buff *skb, u32 val)
+{
+ put_unaligned_le32(val, skb_put(skb, 4));
+}
+
+static inline void mt7601u_dma_skb_wrap_cmd(struct sk_buff *skb,
+ u8 seq, enum mcu_cmd cmd)
+{
+ WARN_ON(mt7601u_dma_skb_wrap(skb, CPU_TX_PORT, DMA_COMMAND,
+ MT76_SET(MT_TXD_CMD_INFO_SEQ, seq) |
+ MT76_SET(MT_TXD_CMD_INFO_TYPE, cmd)));
+}
+
+static inline void trace_mt_mcu_msg_send_cs(struct mt7601u_dev *dev,
+ struct sk_buff *skb, bool need_resp)
+{
+ u32 i, csum = 0;
+
+ for (i = 0; i < skb->len / 4; i++)
+ csum ^= get_unaligned_le32(skb->data + i * 4);
+
+ trace_mt_mcu_msg_send(dev, skb, csum, need_resp);
+}
+
+static struct sk_buff *
+mt7601u_mcu_msg_alloc(struct mt7601u_dev *dev, const void *data, int len)
+{
+ struct sk_buff *skb;
+
+ WARN_ON(len % 4); /* if length is not divisible by 4 we need to pad */
+
+ skb = alloc_skb(len + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
+ skb_reserve(skb, MT_DMA_HDR_LEN);
+ memcpy(skb_put(skb, len), data, len);
+
+ return skb;
+}
+
+static int mt7601u_mcu_wait_resp(struct mt7601u_dev *dev, u8 seq)
+{
+ struct urb *urb = dev->mcu.resp.urb;
+ u32 rxfce;
+ int urb_status, ret, i = 5;
+
+ while (i--) {
+ if (!wait_for_completion_timeout(&dev->mcu.resp_cmpl,
+ msecs_to_jiffies(300))) {
+ dev_warn(dev->dev, "Warning: %s retrying\n", __func__);
+ continue;
+ }
+
+ /* Make copies of important data before reusing the urb */
+ rxfce = get_unaligned_le32(dev->mcu.resp.buf);
+ urb_status = urb->status * mt7601u_urb_has_error(urb);
+
+ ret = mt7601u_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP,
+ &dev->mcu.resp, GFP_KERNEL,
+ mt7601u_complete_urb,
+ &dev->mcu.resp_cmpl);
+ if (ret)
+ return ret;
+
+ if (urb_status)
+ dev_err(dev->dev, "Error: MCU resp urb failed:%d\n",
+ urb_status);
+
+ if (MT76_GET(MT_RXD_CMD_INFO_CMD_SEQ, rxfce) == seq &&
+ MT76_GET(MT_RXD_CMD_INFO_EVT_TYPE, rxfce) == CMD_DONE)
+ return 0;
+
+ dev_err(dev->dev, "Error: MCU resp evt:%hhx seq:%hhx-%hhx!\n",
+ MT76_GET(MT_RXD_CMD_INFO_EVT_TYPE, rxfce),
+ seq, MT76_GET(MT_RXD_CMD_INFO_CMD_SEQ, rxfce));
+ }
+
+ dev_err(dev->dev, "Error: %s timed out\n", __func__);
+ return -ETIMEDOUT;
+}
+
+static int
+mt7601u_mcu_msg_send(struct mt7601u_dev *dev, struct sk_buff *skb,
+ enum mcu_cmd cmd, bool wait_resp)
+{
+ struct usb_device *usb_dev = mt7601u_to_usb_dev(dev);
+ unsigned cmd_pipe = usb_sndbulkpipe(usb_dev,
+ dev->out_eps[MT_EP_OUT_INBAND_CMD]);
+ int sent, ret;
+ u8 seq = 0;
+
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return 0;
+
+ mutex_lock(&dev->mcu.mutex);
+
+ if (wait_resp)
+ while (!seq)
+ seq = ++dev->mcu.msg_seq & 0xf;
+
+ mt7601u_dma_skb_wrap_cmd(skb, seq, cmd);
+
+ if (dev->mcu.resp_cmpl.done)
+ dev_err(dev->dev, "Error: MCU response pre-completed!\n");
+
+ trace_mt_mcu_msg_send_cs(dev, skb, wait_resp);
+ trace_mt_submit_urb_sync(dev, cmd_pipe, skb->len);
+ ret = usb_bulk_msg(usb_dev, cmd_pipe, skb->data, skb->len, &sent, 500);
+ if (ret) {
+ dev_err(dev->dev, "Error: send MCU cmd failed:%d\n", ret);
+ goto out;
+ }
+ if (sent != skb->len)
+ dev_err(dev->dev, "Error: %s sent != skb->len\n", __func__);
+
+ if (wait_resp)
+ ret = mt7601u_mcu_wait_resp(dev, seq);
+out:
+ mutex_unlock(&dev->mcu.mutex);
+
+ consume_skb(skb);
+
+ return ret;
+}
+
+static int mt7601u_mcu_function_select(struct mt7601u_dev *dev,
+ enum mcu_function func, u32 val)
+{
+ struct sk_buff *skb;
+ struct {
+ __le32 id;
+ __le32 value;
+ } __packed __aligned(4) msg = {
+ .id = cpu_to_le32(func),
+ .value = cpu_to_le32(val),
+ };
+
+ skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg));
+ return mt7601u_mcu_msg_send(dev, skb, CMD_FUN_SET_OP, func == 5);
+}
+
+int mt7601u_mcu_tssi_read_kick(struct mt7601u_dev *dev, int use_hvga)
+{
+ int ret;
+
+ if (!test_bit(MT7601U_STATE_MCU_RUNNING, &dev->state))
+ return 0;
+
+ ret = mt7601u_mcu_function_select(dev, ATOMIC_TSSI_SETTING,
+ use_hvga);
+ if (ret) {
+ dev_warn(dev->dev, "Warning: MCU TSSI read kick failed\n");
+ return ret;
+ }
+
+ dev->tssi_read_trig = true;
+
+ return 0;
+}
+
+int
+mt7601u_mcu_calibrate(struct mt7601u_dev *dev, enum mcu_calibrate cal, u32 val)
+{
+ struct sk_buff *skb;
+ struct {
+ __le32 id;
+ __le32 value;
+ } __packed __aligned(4) msg = {
+ .id = cpu_to_le32(cal),
+ .value = cpu_to_le32(val),
+ };
+
+ skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg));
+ return mt7601u_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP, true);
+}
+
+int mt7601u_write_reg_pairs(struct mt7601u_dev *dev, u32 base,
+ const struct mt76_reg_pair *data, int n)
+{
+ const int max_vals_per_cmd = INBAND_PACKET_MAX_LEN / 8;
+ struct sk_buff *skb;
+ int cnt, i, ret;
+
+ if (!n)
+ return 0;
+
+ cnt = min(max_vals_per_cmd, n);
+
+ skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+ skb_reserve(skb, MT_DMA_HDR_LEN);
+
+ for (i = 0; i < cnt; i++) {
+ skb_put_le32(skb, base + data[i].reg);
+ skb_put_le32(skb, data[i].value);
+ }
+
+ ret = mt7601u_mcu_msg_send(dev, skb, CMD_RANDOM_WRITE, cnt == n);
+ if (ret)
+ return ret;
+
+ return mt7601u_write_reg_pairs(dev, base, data + cnt, n - cnt);
+}
+
+int mt7601u_burst_write_regs(struct mt7601u_dev *dev, u32 offset,
+ const u32 *data, int n)
+{
+ const int max_regs_per_cmd = INBAND_PACKET_MAX_LEN / 4 - 1;
+ struct sk_buff *skb;
+ int cnt, i, ret;
+
+ if (!n)
+ return 0;
+
+ cnt = min(max_regs_per_cmd, n);
+
+ skb = alloc_skb(cnt * 4 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+ skb_reserve(skb, MT_DMA_HDR_LEN);
+
+ skb_put_le32(skb, MT_MCU_MEMMAP_WLAN + offset);
+ for (i = 0; i < cnt; i++)
+ skb_put_le32(skb, data[i]);
+
+ ret = mt7601u_mcu_msg_send(dev, skb, CMD_BURST_WRITE, cnt == n);
+ if (ret)
+ return ret;
+
+ return mt7601u_burst_write_regs(dev, offset + cnt * 4,
+ data + cnt, n - cnt);
+}
+
+struct mt76_fw_header {
+ __le32 ilm_len;
+ __le32 dlm_len;
+ __le16 build_ver;
+ __le16 fw_ver;
+ u8 pad[4];
+ char build_time[16];
+};
+
+struct mt76_fw {
+ struct mt76_fw_header hdr;
+ u8 ivb[MT_MCU_IVB_SIZE];
+ u8 ilm[];
+};
+
+static int __mt7601u_dma_fw(struct mt7601u_dev *dev,
+ const struct mt7601u_dma_buf *dma_buf,
+ const void *data, u32 len, u32 dst_addr)
+{
+ DECLARE_COMPLETION_ONSTACK(cmpl);
+ struct mt7601u_dma_buf buf = *dma_buf; /* we need to fake length */
+ __le32 reg;
+ u32 val;
+ int ret;
+
+ reg = cpu_to_le32(MT76_SET(MT_TXD_INFO_TYPE, DMA_PACKET) |
+ MT76_SET(MT_TXD_INFO_D_PORT, CPU_TX_PORT) |
+ MT76_SET(MT_TXD_INFO_LEN, len));
+ memcpy(buf.buf, &reg, sizeof(reg));
+ memcpy(buf.buf + sizeof(reg), data, len);
+ memset(buf.buf + sizeof(reg) + len, 0, 8);
+
+ ret = mt7601u_vendor_single_wr(dev, MT_VEND_WRITE_FCE,
+ MT_FCE_DMA_ADDR, dst_addr);
+ if (ret)
+ return ret;
+ len = roundup(len, 4);
+ ret = mt7601u_vendor_single_wr(dev, MT_VEND_WRITE_FCE,
+ MT_FCE_DMA_LEN, len << 16);
+ if (ret)
+ return ret;
+
+ buf.len = MT_DMA_HDR_LEN + len + 4;
+ ret = mt7601u_usb_submit_buf(dev, USB_DIR_OUT, MT_EP_OUT_INBAND_CMD,
+ &buf, GFP_KERNEL,
+ mt7601u_complete_urb, &cmpl);
+ if (ret)
+ return ret;
+
+ if (!wait_for_completion_timeout(&cmpl, msecs_to_jiffies(1000))) {
+ dev_err(dev->dev, "Error: firmware upload timed out\n");
+ usb_kill_urb(buf.urb);
+ return -ETIMEDOUT;
+ }
+ if (mt7601u_urb_has_error(buf.urb)) {
+ dev_err(dev->dev, "Error: firmware upload urb failed:%d\n",
+ buf.urb->status);
+ return buf.urb->status;
+ }
+
+ val = mt7601u_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX);
+ val++;
+ mt7601u_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val);
+
+ return 0;
+}
+
+static int
+mt7601u_dma_fw(struct mt7601u_dev *dev, struct mt7601u_dma_buf *dma_buf,
+ const void *data, int len, u32 dst_addr)
+{
+ int n, ret;
+
+ if (len == 0)
+ return 0;
+
+ n = min(MCU_FW_URB_MAX_PAYLOAD, len);
+ ret = __mt7601u_dma_fw(dev, dma_buf, data, n, dst_addr);
+ if (ret)
+ return ret;
+
+ if (!mt76_poll_msec(dev, MT_MCU_COM_REG1, BIT(31), BIT(31), 500))
+ return -ETIMEDOUT;
+
+ return mt7601u_dma_fw(dev, dma_buf, data + n, len - n, dst_addr + n);
+}
+
+static int
+mt7601u_upload_firmware(struct mt7601u_dev *dev, const struct mt76_fw *fw)
+{
+ struct mt7601u_dma_buf dma_buf;
+ void *ivb;
+ u32 ilm_len, dlm_len;
+ int i, ret;
+
+ ivb = kmemdup(fw->ivb, sizeof(fw->ivb), GFP_KERNEL);
+ if (!ivb || mt7601u_usb_alloc_buf(dev, MCU_FW_URB_SIZE, &dma_buf)) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ilm_len = le32_to_cpu(fw->hdr.ilm_len) - sizeof(fw->ivb);
+ dev_dbg(dev->dev, "loading FW - ILM %u + IVB %zu\n",
+ ilm_len, sizeof(fw->ivb));
+ ret = mt7601u_dma_fw(dev, &dma_buf, fw->ilm, ilm_len, sizeof(fw->ivb));
+ if (ret)
+ goto error;
+
+ dlm_len = le32_to_cpu(fw->hdr.dlm_len);
+ dev_dbg(dev->dev, "loading FW - DLM %u\n", dlm_len);
+ ret = mt7601u_dma_fw(dev, &dma_buf, fw->ilm + ilm_len,
+ dlm_len, MT_MCU_DLM_OFFSET);
+ if (ret)
+ goto error;
+
+ ret = mt7601u_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT,
+ 0x12, 0, ivb, sizeof(fw->ivb));
+ if (ret < 0)
+ goto error;
+ ret = 0;
+
+ for (i = 100; i && !firmware_running(dev); i--)
+ msleep(10);
+ if (!i) {
+ ret = -ETIMEDOUT;
+ goto error;
+ }
+
+ dev_dbg(dev->dev, "Firmware running!\n");
+error:
+ kfree(ivb);
+ mt7601u_usb_free_buf(dev, &dma_buf);
+
+ return ret;
+}
+
+static int mt7601u_load_firmware(struct mt7601u_dev *dev)
+{
+ const struct firmware *fw;
+ const struct mt76_fw_header *hdr;
+ int len, ret;
+ u32 val;
+
+ mt7601u_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
+ MT_USB_DMA_CFG_TX_BULK_EN));
+
+ if (firmware_running(dev))
+ return 0;
+
+ ret = request_firmware(&fw, MT7601U_FIRMWARE, dev->dev);
+ if (ret)
+ return ret;
+
+ if (!fw || !fw->data || fw->size < sizeof(*hdr))
+ goto err_inv_fw;
+
+ hdr = (const struct mt76_fw_header *) fw->data;
+
+ if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE)
+ goto err_inv_fw;
+
+ len = sizeof(*hdr);
+ len += le32_to_cpu(hdr->ilm_len);
+ len += le32_to_cpu(hdr->dlm_len);
+
+ if (fw->size != len)
+ goto err_inv_fw;
+
+ val = le16_to_cpu(hdr->fw_ver);
+ dev_info(dev->dev,
+ "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n",
+ (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf,
+ le16_to_cpu(hdr->build_ver), hdr->build_time);
+
+ len = le32_to_cpu(hdr->ilm_len);
+
+ mt7601u_wr(dev, 0x94c, 0);
+ mt7601u_wr(dev, MT_FCE_PSE_CTRL, 0);
+
+ mt7601u_vendor_reset(dev);
+ msleep(5);
+
+ mt7601u_wr(dev, 0xa44, 0);
+ mt7601u_wr(dev, 0x230, 0x84210);
+ mt7601u_wr(dev, 0x400, 0x80c00);
+ mt7601u_wr(dev, 0x800, 1);
+
+ mt7601u_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN |
+ MT_PBF_CFG_TX1Q_EN |
+ MT_PBF_CFG_TX2Q_EN |
+ MT_PBF_CFG_TX3Q_EN));
+
+ mt7601u_wr(dev, MT_FCE_PSE_CTRL, 1);
+
+ mt7601u_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
+ MT_USB_DMA_CFG_TX_BULK_EN));
+ val = mt76_set(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_CLR);
+ val &= ~MT_USB_DMA_CFG_TX_CLR;
+ mt7601u_wr(dev, MT_USB_DMA_CFG, val);
+
+ /* FCE tx_fs_base_ptr */
+ mt7601u_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230);
+ /* FCE tx_fs_max_cnt */
+ mt7601u_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1);
+ /* FCE pdma enable */
+ mt7601u_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44);
+ /* FCE skip_fs_en */
+ mt7601u_wr(dev, MT_FCE_SKIP_FS, 3);
+
+ ret = mt7601u_upload_firmware(dev, (const struct mt76_fw *)fw->data);
+
+ release_firmware(fw);
+
+ return ret;
+
+err_inv_fw:
+ dev_err(dev->dev, "Invalid firmware image\n");
+ release_firmware(fw);
+ return -ENOENT;
+}
+
+int mt7601u_mcu_init(struct mt7601u_dev *dev)
+{
+ int ret;
+
+ mutex_init(&dev->mcu.mutex);
+
+ ret = mt7601u_load_firmware(dev);
+ if (ret)
+ return ret;
+
+ set_bit(MT7601U_STATE_MCU_RUNNING, &dev->state);
+
+ return 0;
+}
+
+int mt7601u_mcu_cmd_init(struct mt7601u_dev *dev)
+{
+ int ret;
+
+ ret = mt7601u_mcu_function_select(dev, Q_SELECT, 1);
+ if (ret)
+ return ret;
+
+ init_completion(&dev->mcu.resp_cmpl);
+ if (mt7601u_usb_alloc_buf(dev, MCU_RESP_URB_SIZE, &dev->mcu.resp)) {
+ mt7601u_usb_free_buf(dev, &dev->mcu.resp);
+ return -ENOMEM;
+ }
+
+ ret = mt7601u_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP,
+ &dev->mcu.resp, GFP_KERNEL,
+ mt7601u_complete_urb, &dev->mcu.resp_cmpl);
+ if (ret) {
+ mt7601u_usb_free_buf(dev, &dev->mcu.resp);
+ return ret;
+ }
+
+ return 0;
+}
+
+void mt7601u_mcu_cmd_deinit(struct mt7601u_dev *dev)
+{
+ usb_kill_urb(dev->mcu.resp.urb);
+ mt7601u_usb_free_buf(dev, &dev->mcu.resp);
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.h b/drivers/net/wireless/mediatek/mt7601u/mcu.h
new file mode 100644
index 000000000000..4a66d1092a18
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/mcu.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#ifndef __MT7601U_MCU_H
+#define __MT7601U_MCU_H
+
+struct mt7601u_dev;
+
+/* Register definitions */
+#define MT_MCU_RESET_CTL 0x070C
+#define MT_MCU_INT_LEVEL 0x0718
+#define MT_MCU_COM_REG0 0x0730
+#define MT_MCU_COM_REG1 0x0734
+#define MT_MCU_COM_REG2 0x0738
+#define MT_MCU_COM_REG3 0x073C
+
+#define MT_MCU_IVB_SIZE 0x40
+#define MT_MCU_DLM_OFFSET 0x80000
+
+#define MT_MCU_MEMMAP_WLAN 0x00410000
+#define MT_MCU_MEMMAP_BBP 0x40000000
+#define MT_MCU_MEMMAP_RF 0x80000000
+
+#define INBAND_PACKET_MAX_LEN 192
+
+enum mcu_cmd {
+ CMD_FUN_SET_OP = 1,
+ CMD_LOAD_CR = 2,
+ CMD_INIT_GAIN_OP = 3,
+ CMD_DYNC_VGA_OP = 6,
+ CMD_TDLS_CH_SW = 7,
+ CMD_BURST_WRITE = 8,
+ CMD_READ_MODIFY_WRITE = 9,
+ CMD_RANDOM_READ = 10,
+ CMD_BURST_READ = 11,
+ CMD_RANDOM_WRITE = 12,
+ CMD_LED_MODE_OP = 16,
+ CMD_POWER_SAVING_OP = 20,
+ CMD_WOW_CONFIG = 21,
+ CMD_WOW_QUERY = 22,
+ CMD_WOW_FEATURE = 24,
+ CMD_CARRIER_DETECT_OP = 28,
+ CMD_RADOR_DETECT_OP = 29,
+ CMD_SWITCH_CHANNEL_OP = 30,
+ CMD_CALIBRATION_OP = 31,
+ CMD_BEACON_OP = 32,
+ CMD_ANTENNA_OP = 33,
+};
+
+enum mcu_function {
+ Q_SELECT = 1,
+ ATOMIC_TSSI_SETTING = 5,
+};
+
+enum mcu_power_mode {
+ RADIO_OFF = 0x30,
+ RADIO_ON = 0x31,
+ RADIO_OFF_AUTO_WAKEUP = 0x32,
+ RADIO_OFF_ADVANCE = 0x33,
+ RADIO_ON_ADVANCE = 0x34,
+};
+
+enum mcu_calibrate {
+ MCU_CAL_R = 1,
+ MCU_CAL_DCOC,
+ MCU_CAL_LC,
+ MCU_CAL_LOFT,
+ MCU_CAL_TXIQ,
+ MCU_CAL_BW,
+ MCU_CAL_DPD,
+ MCU_CAL_RXIQ,
+ MCU_CAL_TXDCOC,
+};
+
+int mt7601u_mcu_init(struct mt7601u_dev *dev);
+int mt7601u_mcu_cmd_init(struct mt7601u_dev *dev);
+void mt7601u_mcu_cmd_deinit(struct mt7601u_dev *dev);
+
+int
+mt7601u_mcu_calibrate(struct mt7601u_dev *dev, enum mcu_calibrate cal, u32 val);
+int mt7601u_mcu_tssi_read_kick(struct mt7601u_dev *dev, int use_hvga);
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
new file mode 100644
index 000000000000..9102be6b95cb
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#ifndef MT7601U_H
+#define MT7601U_H
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/usb.h>
+#include <linux/completion.h>
+#include <net/mac80211.h>
+#include <linux/debugfs.h>
+
+#include "regs.h"
+#include "util.h"
+
+#define MT_CALIBRATE_INTERVAL (4 * HZ)
+
+#define MT_FREQ_CAL_INIT_DELAY (30 * HZ)
+#define MT_FREQ_CAL_CHECK_INTERVAL (10 * HZ)
+#define MT_FREQ_CAL_ADJ_INTERVAL (HZ / 2)
+
+#define MT_BBP_REG_VERSION 0x00
+
+#define MT_USB_AGGR_SIZE_LIMIT 28 /* * 1024B */
+#define MT_USB_AGGR_TIMEOUT 0x80 /* * 33ns */
+#define MT_RX_ORDER 3
+#define MT_RX_URB_SIZE (PAGE_SIZE << MT_RX_ORDER)
+
+struct mt7601u_dma_buf {
+ struct urb *urb;
+ void *buf;
+ dma_addr_t dma;
+ size_t len;
+};
+
+struct mt7601u_mcu {
+ struct mutex mutex;
+
+ u8 msg_seq;
+
+ struct mt7601u_dma_buf resp;
+ struct completion resp_cmpl;
+};
+
+struct mt7601u_freq_cal {
+ struct delayed_work work;
+ u8 freq;
+ bool enabled;
+ bool adjusting;
+};
+
+struct mac_stats {
+ u64 rx_stat[6];
+ u64 tx_stat[6];
+ u64 aggr_stat[2];
+ u64 aggr_n[32];
+ u64 zero_len_del[2];
+};
+
+#define N_RX_ENTRIES 16
+struct mt7601u_rx_queue {
+ struct mt7601u_dev *dev;
+
+ struct mt7601u_dma_buf_rx {
+ struct urb *urb;
+ struct page *p;
+ } e[N_RX_ENTRIES];
+
+ unsigned int start;
+ unsigned int end;
+ unsigned int entries;
+ unsigned int pending;
+};
+
+#define N_TX_ENTRIES 64
+
+struct mt7601u_tx_queue {
+ struct mt7601u_dev *dev;
+
+ struct mt7601u_dma_buf_tx {
+ struct urb *urb;
+ struct sk_buff *skb;
+ } e[N_TX_ENTRIES];
+
+ unsigned int start;
+ unsigned int end;
+ unsigned int entries;
+ unsigned int used;
+ unsigned int fifo_seq;
+};
+
+/* WCID allocation:
+ * 0: mcast wcid
+ * 1: bssid wcid
+ * 1...: STAs
+ * ...7e: group wcids
+ * 7f: reserved
+ */
+#define N_WCIDS 128
+#define GROUP_WCID(idx) (N_WCIDS - 2 - idx)
+
+struct mt7601u_eeprom_params;
+
+#define MT_EE_TEMPERATURE_SLOPE 39
+#define MT_FREQ_OFFSET_INVALID -128
+
+enum mt_temp_mode {
+ MT_TEMP_MODE_NORMAL,
+ MT_TEMP_MODE_HIGH,
+ MT_TEMP_MODE_LOW,
+};
+
+enum mt_bw {
+ MT_BW_20,
+ MT_BW_40,
+};
+
+enum {
+ MT7601U_STATE_INITIALIZED,
+ MT7601U_STATE_REMOVED,
+ MT7601U_STATE_WLAN_RUNNING,
+ MT7601U_STATE_MCU_RUNNING,
+ MT7601U_STATE_SCANNING,
+ MT7601U_STATE_READING_STATS,
+ MT7601U_STATE_MORE_STATS,
+};
+
+/**
+ * struct mt7601u_dev - adapter structure
+ * @lock: protects @wcid->tx_rate.
+ * @tx_lock: protects @tx_q and changes of MT7601U_STATE_*_STATS
+ flags in @state.
+ * @rx_lock: protects @rx_q.
+ * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi.
+ * @mutex: ensures exclusive access from mac80211 callbacks.
+ * @vendor_req_mutex: ensures atomicity of vendor requests.
+ * @reg_atomic_mutex: ensures atomicity of indirect register accesses
+ * (accesses to RF and BBP).
+ * @hw_atomic_mutex: ensures exclusive access to HW during critical
+ * operations (power management, channel switch).
+ */
+struct mt7601u_dev {
+ struct ieee80211_hw *hw;
+ struct device *dev;
+
+ unsigned long state;
+
+ struct mutex mutex;
+
+ unsigned long wcid_mask[N_WCIDS / BITS_PER_LONG];
+
+ struct cfg80211_chan_def chandef;
+ struct ieee80211_supported_band *sband_2g;
+
+ struct mt7601u_mcu mcu;
+
+ struct delayed_work cal_work;
+ struct delayed_work mac_work;
+
+ struct workqueue_struct *stat_wq;
+ struct delayed_work stat_work;
+
+ struct mt76_wcid *mon_wcid;
+ struct mt76_wcid __rcu *wcid[N_WCIDS];
+
+ spinlock_t lock;
+
+ const u16 *beacon_offsets;
+
+ u8 macaddr[ETH_ALEN];
+ struct mt7601u_eeprom_params *ee;
+
+ struct mutex vendor_req_mutex;
+ struct mutex reg_atomic_mutex;
+ struct mutex hw_atomic_mutex;
+
+ u32 rxfilter;
+ u32 debugfs_reg;
+
+ u8 out_eps[8];
+ u8 in_eps[8];
+ u16 out_max_packet;
+ u16 in_max_packet;
+
+ /* TX */
+ spinlock_t tx_lock;
+ struct mt7601u_tx_queue *tx_q;
+
+ atomic_t avg_ampdu_len;
+
+ /* RX */
+ spinlock_t rx_lock;
+ struct tasklet_struct rx_tasklet;
+ struct mt7601u_rx_queue rx_q;
+
+ /* Connection monitoring things */
+ spinlock_t con_mon_lock;
+ u8 ap_bssid[ETH_ALEN];
+
+ s8 bcn_freq_off;
+ u8 bcn_phy_mode;
+
+ int avg_rssi; /* starts at 0 and converges */
+
+ u8 agc_save;
+
+ struct mt7601u_freq_cal freq_cal;
+
+ bool tssi_read_trig;
+
+ s8 tssi_init;
+ s8 tssi_init_hvga;
+ s16 tssi_init_hvga_offset_db;
+
+ int prev_pwr_diff;
+
+ enum mt_temp_mode temp_mode;
+ int curr_temp;
+ int dpd_temp;
+ s8 raw_temp;
+ bool pll_lock_protect;
+
+ u8 bw;
+ bool chan_ext_below;
+
+ /* PA mode */
+ u32 rf_pa_mode[2];
+
+ struct mac_stats stats;
+};
+
+struct mt7601u_tssi_params {
+ char tssi0;
+ int trgt_power;
+};
+
+struct mt76_wcid {
+ u8 idx;
+ u8 hw_key_idx;
+
+ u16 tx_rate;
+ bool tx_rate_set;
+ u8 tx_rate_nss;
+};
+
+struct mt76_vif {
+ u8 idx;
+
+ struct mt76_wcid group_wcid;
+};
+
+struct mt76_sta {
+ struct mt76_wcid wcid;
+ u16 agg_ssn[IEEE80211_NUM_TIDS];
+};
+
+struct mt76_reg_pair {
+ u32 reg;
+ u32 value;
+};
+
+struct mt7601u_rxwi;
+
+extern const struct ieee80211_ops mt7601u_ops;
+
+void mt7601u_init_debugfs(struct mt7601u_dev *dev);
+
+u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset);
+void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val);
+u32 mt7601u_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val);
+u32 mt7601u_rmc(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val);
+void mt7601u_wr_copy(struct mt7601u_dev *dev, u32 offset,
+ const void *data, int len);
+
+int mt7601u_wait_asic_ready(struct mt7601u_dev *dev);
+bool mt76_poll(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val,
+ int timeout);
+bool mt76_poll_msec(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val,
+ int timeout);
+
+/* Compatibility with mt76 */
+#define mt76_rmw_field(_dev, _reg, _field, _val) \
+ mt76_rmw(_dev, _reg, _field, MT76_SET(_field, _val))
+
+static inline u32 mt76_rr(struct mt7601u_dev *dev, u32 offset)
+{
+ return mt7601u_rr(dev, offset);
+}
+
+static inline void mt76_wr(struct mt7601u_dev *dev, u32 offset, u32 val)
+{
+ return mt7601u_wr(dev, offset, val);
+}
+
+static inline u32
+mt76_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val)
+{
+ return mt7601u_rmw(dev, offset, mask, val);
+}
+
+static inline u32 mt76_set(struct mt7601u_dev *dev, u32 offset, u32 val)
+{
+ return mt76_rmw(dev, offset, 0, val);
+}
+
+static inline u32 mt76_clear(struct mt7601u_dev *dev, u32 offset, u32 val)
+{
+ return mt76_rmw(dev, offset, val, 0);
+}
+
+int mt7601u_write_reg_pairs(struct mt7601u_dev *dev, u32 base,
+ const struct mt76_reg_pair *data, int len);
+int mt7601u_burst_write_regs(struct mt7601u_dev *dev, u32 offset,
+ const u32 *data, int n);
+void mt7601u_addr_wr(struct mt7601u_dev *dev, const u32 offset, const u8 *addr);
+
+/* Init */
+struct mt7601u_dev *mt7601u_alloc_device(struct device *dev);
+int mt7601u_init_hardware(struct mt7601u_dev *dev);
+int mt7601u_register_device(struct mt7601u_dev *dev);
+void mt7601u_cleanup(struct mt7601u_dev *dev);
+
+int mt7601u_mac_start(struct mt7601u_dev *dev);
+void mt7601u_mac_stop(struct mt7601u_dev *dev);
+
+/* PHY */
+int mt7601u_phy_init(struct mt7601u_dev *dev);
+int mt7601u_wait_bbp_ready(struct mt7601u_dev *dev);
+void mt7601u_set_rx_path(struct mt7601u_dev *dev, u8 path);
+void mt7601u_set_tx_dac(struct mt7601u_dev *dev, u8 path);
+int mt7601u_bbp_set_bw(struct mt7601u_dev *dev, int bw);
+void mt7601u_agc_save(struct mt7601u_dev *dev);
+void mt7601u_agc_restore(struct mt7601u_dev *dev);
+int mt7601u_phy_set_channel(struct mt7601u_dev *dev,
+ struct cfg80211_chan_def *chandef);
+void mt7601u_phy_recalibrate_after_assoc(struct mt7601u_dev *dev);
+int mt7601u_phy_get_rssi(struct mt7601u_dev *dev,
+ struct mt7601u_rxwi *rxwi, u16 rate);
+void mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev,
+ struct ieee80211_bss_conf *info);
+
+/* MAC */
+void mt7601u_mac_work(struct work_struct *work);
+void mt7601u_mac_set_protection(struct mt7601u_dev *dev, bool legacy_prot,
+ int ht_mode);
+void mt7601u_mac_set_short_preamble(struct mt7601u_dev *dev, bool short_preamb);
+void mt7601u_mac_config_tsf(struct mt7601u_dev *dev, bool enable, int interval);
+void
+mt7601u_mac_wcid_setup(struct mt7601u_dev *dev, u8 idx, u8 vif_idx, u8 *mac);
+void mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev);
+
+/* TX */
+void mt7601u_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
+ struct sk_buff *skb);
+int mt7601u_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u16 queue, const struct ieee80211_tx_queue_params *params);
+void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb);
+void mt7601u_tx_stat(struct work_struct *work);
+
+/* util */
+void mt76_remove_hdr_pad(struct sk_buff *skb);
+int mt76_insert_hdr_pad(struct sk_buff *skb);
+
+u32 mt7601u_bbp_set_ctrlch(struct mt7601u_dev *dev, bool below);
+
+static inline u32 mt7601u_mac_set_ctrlch(struct mt7601u_dev *dev, bool below)
+{
+ return mt7601u_rmc(dev, MT_TX_BAND_CFG, 1, below);
+}
+
+int mt7601u_dma_init(struct mt7601u_dev *dev);
+void mt7601u_dma_cleanup(struct mt7601u_dev *dev);
+
+int mt7601u_dma_enqueue_tx(struct mt7601u_dev *dev, struct sk_buff *skb,
+ struct mt76_wcid *wcid, int hw_q);
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/phy.c b/drivers/net/wireless/mediatek/mt7601u/phy.c
new file mode 100644
index 000000000000..1908af6add87
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/phy.c
@@ -0,0 +1,1251 @@
+/*
+ * (c) Copyright 2002-2010, Ralink Technology, Inc.
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#include "mt7601u.h"
+#include "mcu.h"
+#include "eeprom.h"
+#include "trace.h"
+#include "initvals_phy.h"
+
+#include <linux/etherdevice.h>
+
+static void mt7601u_agc_reset(struct mt7601u_dev *dev);
+
+static int
+mt7601u_rf_wr(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 value)
+{
+ int ret = 0;
+
+ if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) ||
+ WARN_ON(offset > 63))
+ return -EINVAL;
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return 0;
+
+ mutex_lock(&dev->reg_atomic_mutex);
+
+ if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100)) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ mt7601u_wr(dev, MT_RF_CSR_CFG, MT76_SET(MT_RF_CSR_CFG_DATA, value) |
+ MT76_SET(MT_RF_CSR_CFG_REG_BANK, bank) |
+ MT76_SET(MT_RF_CSR_CFG_REG_ID, offset) |
+ MT_RF_CSR_CFG_WR |
+ MT_RF_CSR_CFG_KICK);
+ trace_rf_write(dev, bank, offset, value);
+out:
+ mutex_unlock(&dev->reg_atomic_mutex);
+
+ if (ret < 0)
+ dev_err(dev->dev, "Error: RF write %02hhx:%02hhx failed:%d!!\n",
+ bank, offset, ret);
+
+ return ret;
+}
+
+static int
+mt7601u_rf_rr(struct mt7601u_dev *dev, u8 bank, u8 offset)
+{
+ int ret = -ETIMEDOUT;
+ u32 val;
+
+ if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) ||
+ WARN_ON(offset > 63))
+ return -EINVAL;
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return 0xff;
+
+ mutex_lock(&dev->reg_atomic_mutex);
+
+ if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100))
+ goto out;
+
+ mt7601u_wr(dev, MT_RF_CSR_CFG, MT76_SET(MT_RF_CSR_CFG_REG_BANK, bank) |
+ MT76_SET(MT_RF_CSR_CFG_REG_ID, offset) |
+ MT_RF_CSR_CFG_KICK);
+
+ if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100))
+ goto out;
+
+ val = mt7601u_rr(dev, MT_RF_CSR_CFG);
+ if (MT76_GET(MT_RF_CSR_CFG_REG_ID, val) == offset &&
+ MT76_GET(MT_RF_CSR_CFG_REG_BANK, val) == bank) {
+ ret = MT76_GET(MT_RF_CSR_CFG_DATA, val);
+ trace_rf_read(dev, bank, offset, ret);
+ }
+out:
+ mutex_unlock(&dev->reg_atomic_mutex);
+
+ if (ret < 0)
+ dev_err(dev->dev, "Error: RF read %02hhx:%02hhx failed:%d!!\n",
+ bank, offset, ret);
+
+ return ret;
+}
+
+static int
+mt7601u_rf_rmw(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 mask, u8 val)
+{
+ int ret;
+
+ ret = mt7601u_rf_rr(dev, bank, offset);
+ if (ret < 0)
+ return ret;
+ val |= ret & ~mask;
+ ret = mt7601u_rf_wr(dev, bank, offset, val);
+ if (ret)
+ return ret;
+
+ return val;
+}
+
+static int
+mt7601u_rf_set(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 val)
+{
+ return mt7601u_rf_rmw(dev, bank, offset, 0, val);
+}
+
+static int
+mt7601u_rf_clear(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 mask)
+{
+ return mt7601u_rf_rmw(dev, bank, offset, mask, 0);
+}
+
+static void mt7601u_bbp_wr(struct mt7601u_dev *dev, u8 offset, u8 val)
+{
+ if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) ||
+ test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return;
+
+ mutex_lock(&dev->reg_atomic_mutex);
+
+ if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, 0, 1000)) {
+ dev_err(dev->dev, "Error: BBP write %02hhx failed!!\n", offset);
+ goto out;
+ }
+
+ mt7601u_wr(dev, MT_BBP_CSR_CFG,
+ MT76_SET(MT_BBP_CSR_CFG_VAL, val) |
+ MT76_SET(MT_BBP_CSR_CFG_REG_NUM, offset) |
+ MT_BBP_CSR_CFG_RW_MODE | MT_BBP_CSR_CFG_BUSY);
+ trace_bbp_write(dev, offset, val);
+out:
+ mutex_unlock(&dev->reg_atomic_mutex);
+}
+
+static int mt7601u_bbp_rr(struct mt7601u_dev *dev, u8 offset)
+{
+ u32 val;
+ int ret = -ETIMEDOUT;
+
+ if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)))
+ return -EINVAL;
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return 0xff;
+
+ mutex_lock(&dev->reg_atomic_mutex);
+
+ if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, 0, 1000))
+ goto out;
+
+ mt7601u_wr(dev, MT_BBP_CSR_CFG,
+ MT76_SET(MT_BBP_CSR_CFG_REG_NUM, offset) |
+ MT_BBP_CSR_CFG_RW_MODE | MT_BBP_CSR_CFG_BUSY |
+ MT_BBP_CSR_CFG_READ);
+
+ if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, 0, 1000))
+ goto out;
+
+ val = mt7601u_rr(dev, MT_BBP_CSR_CFG);
+ if (MT76_GET(MT_BBP_CSR_CFG_REG_NUM, val) == offset) {
+ ret = MT76_GET(MT_BBP_CSR_CFG_VAL, val);
+ trace_bbp_read(dev, offset, ret);
+ }
+out:
+ mutex_unlock(&dev->reg_atomic_mutex);
+
+ if (ret < 0)
+ dev_err(dev->dev, "Error: BBP read %02hhx failed:%d!!\n",
+ offset, ret);
+
+ return ret;
+}
+
+static int mt7601u_bbp_rmw(struct mt7601u_dev *dev, u8 offset, u8 mask, u8 val)
+{
+ int ret;
+
+ ret = mt7601u_bbp_rr(dev, offset);
+ if (ret < 0)
+ return ret;
+ val |= ret & ~mask;
+ mt7601u_bbp_wr(dev, offset, val);
+
+ return val;
+}
+
+static u8 mt7601u_bbp_rmc(struct mt7601u_dev *dev, u8 offset, u8 mask, u8 val)
+{
+ int ret;
+
+ ret = mt7601u_bbp_rr(dev, offset);
+ if (ret < 0)
+ return ret;
+ val |= ret & ~mask;
+ if (ret != val)
+ mt7601u_bbp_wr(dev, offset, val);
+
+ return val;
+}
+
+int mt7601u_wait_bbp_ready(struct mt7601u_dev *dev)
+{
+ int i = 20;
+ u8 val;
+
+ do {
+ val = mt7601u_bbp_rr(dev, MT_BBP_REG_VERSION);
+ if (val && ~val)
+ break;
+ } while (--i);
+
+ if (!i) {
+ dev_err(dev->dev, "Error: BBP is not ready\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+u32 mt7601u_bbp_set_ctrlch(struct mt7601u_dev *dev, bool below)
+{
+ return mt7601u_bbp_rmc(dev, 3, 0x20, below ? 0x20 : 0);
+}
+
+int mt7601u_phy_get_rssi(struct mt7601u_dev *dev,
+ struct mt7601u_rxwi *rxwi, u16 rate)
+{
+ static const s8 lna[2][2][3] = {
+ /* main LNA */ {
+ /* bw20 */ { -2, 15, 33 },
+ /* bw40 */ { 0, 16, 34 }
+ },
+ /* aux LNA */ {
+ /* bw20 */ { -2, 15, 33 },
+ /* bw40 */ { -2, 16, 34 }
+ }
+ };
+ int bw = MT76_GET(MT_RXWI_RATE_BW, rate);
+ int aux_lna = MT76_GET(MT_RXWI_ANT_AUX_LNA, rxwi->ant);
+ int lna_id = MT76_GET(MT_RXWI_GAIN_RSSI_LNA_ID, rxwi->gain);
+ int val;
+
+ if (lna_id) /* LNA id can be 0, 2, 3. */
+ lna_id--;
+
+ val = 8;
+ val -= lna[aux_lna][bw][lna_id];
+ val -= MT76_GET(MT_RXWI_GAIN_RSSI_VAL, rxwi->gain);
+ val -= dev->ee->lna_gain;
+ val -= dev->ee->rssi_offset[0];
+
+ return val;
+}
+
+static void mt7601u_vco_cal(struct mt7601u_dev *dev)
+{
+ mt7601u_rf_wr(dev, 0, 4, 0x0a);
+ mt7601u_rf_wr(dev, 0, 5, 0x20);
+ mt7601u_rf_set(dev, 0, 4, BIT(7));
+ msleep(2);
+}
+
+static int mt7601u_set_bw_filter(struct mt7601u_dev *dev, bool cal)
+{
+ u32 filter = 0;
+ int ret;
+
+ if (!cal)
+ filter |= 0x10000;
+ if (dev->bw != MT_BW_20)
+ filter |= 0x00100;
+
+ /* TX */
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_BW, filter | 1);
+ if (ret)
+ return ret;
+ /* RX */
+ return mt7601u_mcu_calibrate(dev, MCU_CAL_BW, filter);
+}
+
+static int mt7601u_load_bbp_temp_table_bw(struct mt7601u_dev *dev)
+{
+ const struct reg_table *t;
+
+ if (WARN_ON(dev->temp_mode > MT_TEMP_MODE_LOW))
+ return -EINVAL;
+
+ t = &bbp_mode_table[dev->temp_mode][dev->bw];
+
+ return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, t->regs, t->n);
+}
+
+static int mt7601u_bbp_temp(struct mt7601u_dev *dev, int mode, const char *name)
+{
+ const struct reg_table *t;
+ int ret;
+
+ if (dev->temp_mode == mode)
+ return 0;
+
+ dev->temp_mode = mode;
+ trace_temp_mode(dev, mode);
+
+ t = bbp_mode_table[dev->temp_mode];
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP,
+ t[2].regs, t[2].n);
+ if (ret)
+ return ret;
+
+ return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP,
+ t[dev->bw].regs, t[dev->bw].n);
+}
+
+static void mt7601u_apply_ch14_fixup(struct mt7601u_dev *dev, int hw_chan)
+{
+ struct mt7601u_rate_power *t = &dev->ee->power_rate_table;
+
+ if (hw_chan != 14 || dev->bw != MT_BW_20) {
+ mt7601u_bbp_rmw(dev, 4, 0x20, 0);
+ mt7601u_bbp_wr(dev, 178, 0xff);
+
+ t->cck[0].bw20 = dev->ee->real_cck_bw20[0];
+ t->cck[1].bw20 = dev->ee->real_cck_bw20[1];
+ } else { /* Apply CH14 OBW fixup */
+ mt7601u_bbp_wr(dev, 4, 0x60);
+ mt7601u_bbp_wr(dev, 178, 0);
+
+ /* Note: vendor code is buggy here for negative values */
+ t->cck[0].bw20 = dev->ee->real_cck_bw20[0] - 2;
+ t->cck[1].bw20 = dev->ee->real_cck_bw20[1] - 2;
+ }
+}
+
+static int __mt7601u_phy_set_channel(struct mt7601u_dev *dev,
+ struct cfg80211_chan_def *chandef)
+{
+#define FREQ_PLAN_REGS 4
+ static const u8 freq_plan[14][FREQ_PLAN_REGS] = {
+ { 0x99, 0x99, 0x09, 0x50 },
+ { 0x46, 0x44, 0x0a, 0x50 },
+ { 0xec, 0xee, 0x0a, 0x50 },
+ { 0x99, 0x99, 0x0b, 0x50 },
+ { 0x46, 0x44, 0x08, 0x51 },
+ { 0xec, 0xee, 0x08, 0x51 },
+ { 0x99, 0x99, 0x09, 0x51 },
+ { 0x46, 0x44, 0x0a, 0x51 },
+ { 0xec, 0xee, 0x0a, 0x51 },
+ { 0x99, 0x99, 0x0b, 0x51 },
+ { 0x46, 0x44, 0x08, 0x52 },
+ { 0xec, 0xee, 0x08, 0x52 },
+ { 0x99, 0x99, 0x09, 0x52 },
+ { 0x33, 0x33, 0x0b, 0x52 },
+ };
+ struct mt76_reg_pair channel_freq_plan[FREQ_PLAN_REGS] = {
+ { 17, 0 }, { 18, 0 }, { 19, 0 }, { 20, 0 },
+ };
+ struct mt76_reg_pair bbp_settings[3] = {
+ { 62, 0x37 - dev->ee->lna_gain },
+ { 63, 0x37 - dev->ee->lna_gain },
+ { 64, 0x37 - dev->ee->lna_gain },
+ };
+
+ struct ieee80211_channel *chan = chandef->chan;
+ enum nl80211_channel_type chan_type =
+ cfg80211_get_chandef_type(chandef);
+ struct mt7601u_rate_power *t = &dev->ee->power_rate_table;
+ int chan_idx;
+ bool chan_ext_below;
+ u8 bw;
+ int i, ret;
+
+ bw = MT_BW_20;
+ chan_ext_below = (chan_type == NL80211_CHAN_HT40MINUS);
+ chan_idx = chan->hw_value - 1;
+
+ if (chandef->width == NL80211_CHAN_WIDTH_40) {
+ bw = MT_BW_40;
+
+ if (chan_idx > 1 && chan_type == NL80211_CHAN_HT40MINUS)
+ chan_idx -= 2;
+ else if (chan_idx < 12 && chan_type == NL80211_CHAN_HT40PLUS)
+ chan_idx += 2;
+ else
+ dev_err(dev->dev, "Error: invalid 40MHz channel!!\n");
+ }
+
+ if (bw != dev->bw || chan_ext_below != dev->chan_ext_below) {
+ dev_dbg(dev->dev, "Info: switching HT mode bw:%d below:%d\n",
+ bw, chan_ext_below);
+
+ mt7601u_bbp_set_bw(dev, bw);
+
+ mt7601u_bbp_set_ctrlch(dev, chan_ext_below);
+ mt7601u_mac_set_ctrlch(dev, chan_ext_below);
+ dev->chan_ext_below = chan_ext_below;
+ }
+
+ for (i = 0; i < FREQ_PLAN_REGS; i++)
+ channel_freq_plan[i].value = freq_plan[chan_idx][i];
+
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_RF,
+ channel_freq_plan, FREQ_PLAN_REGS);
+ if (ret)
+ return ret;
+
+ mt7601u_rmw(dev, MT_TX_ALC_CFG_0, 0x3f3f,
+ dev->ee->chan_pwr[chan_idx] & 0x3f);
+
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP,
+ bbp_settings, ARRAY_SIZE(bbp_settings));
+ if (ret)
+ return ret;
+
+ mt7601u_vco_cal(dev);
+ mt7601u_bbp_set_bw(dev, bw);
+ ret = mt7601u_set_bw_filter(dev, false);
+ if (ret)
+ return ret;
+
+ mt7601u_apply_ch14_fixup(dev, chan->hw_value);
+ mt7601u_wr(dev, MT_TX_PWR_CFG_0, int_to_s6(t->ofdm[1].bw20) << 24 |
+ int_to_s6(t->ofdm[0].bw20) << 16 |
+ int_to_s6(t->cck[1].bw20) << 8 |
+ int_to_s6(t->cck[0].bw20));
+
+ if (test_bit(MT7601U_STATE_SCANNING, &dev->state))
+ mt7601u_agc_reset(dev);
+
+ dev->chandef = *chandef;
+
+ return 0;
+}
+
+int mt7601u_phy_set_channel(struct mt7601u_dev *dev,
+ struct cfg80211_chan_def *chandef)
+{
+ int ret;
+
+ cancel_delayed_work_sync(&dev->cal_work);
+ cancel_delayed_work_sync(&dev->freq_cal.work);
+
+ mutex_lock(&dev->hw_atomic_mutex);
+ ret = __mt7601u_phy_set_channel(dev, chandef);
+ mutex_unlock(&dev->hw_atomic_mutex);
+ if (ret)
+ return ret;
+
+ if (test_bit(MT7601U_STATE_SCANNING, &dev->state))
+ return 0;
+
+ ieee80211_queue_delayed_work(dev->hw, &dev->cal_work,
+ MT_CALIBRATE_INTERVAL);
+ if (dev->freq_cal.enabled)
+ ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work,
+ MT_FREQ_CAL_INIT_DELAY);
+ return 0;
+}
+
+#define BBP_R47_FLAG GENMASK(2, 0)
+#define BBP_R47_F_TSSI 0
+#define BBP_R47_F_PKT_T 1
+#define BBP_R47_F_TX_RATE 2
+#define BBP_R47_F_TEMP 4
+/**
+ * mt7601u_bbp_r47_get - read value through BBP R47/R49 pair
+ * @dev: pointer to adapter structure
+ * @reg: value of BBP R47 before the operation
+ * @flag: one of the BBP_R47_F_* flags
+ *
+ * Convenience helper for reading values through BBP R47/R49 pair.
+ * Takes old value of BBP R47 as @reg, because callers usually have it
+ * cached already.
+ *
+ * Return: value of BBP R49.
+ */
+static u8 mt7601u_bbp_r47_get(struct mt7601u_dev *dev, u8 reg, u8 flag)
+{
+ flag |= reg & ~BBP_R47_FLAG;
+ mt7601u_bbp_wr(dev, 47, flag);
+ usleep_range(500, 700);
+ return mt7601u_bbp_rr(dev, 49);
+}
+
+static s8 mt7601u_read_bootup_temp(struct mt7601u_dev *dev)
+{
+ u8 bbp_val, temp;
+ u32 rf_bp, rf_set;
+ int i;
+
+ rf_set = mt7601u_rr(dev, MT_RF_SETTING_0);
+ rf_bp = mt7601u_rr(dev, MT_RF_BYPASS_0);
+
+ mt7601u_wr(dev, MT_RF_BYPASS_0, 0);
+ mt7601u_wr(dev, MT_RF_SETTING_0, 0x00000010);
+ mt7601u_wr(dev, MT_RF_BYPASS_0, 0x00000010);
+
+ bbp_val = mt7601u_bbp_rmw(dev, 47, 0, 0x10);
+
+ mt7601u_bbp_wr(dev, 22, 0x40);
+
+ for (i = 100; i && (bbp_val & 0x10); i--)
+ bbp_val = mt7601u_bbp_rr(dev, 47);
+
+ temp = mt7601u_bbp_r47_get(dev, bbp_val, BBP_R47_F_TEMP);
+
+ mt7601u_bbp_wr(dev, 22, 0);
+
+ bbp_val = mt7601u_bbp_rr(dev, 21);
+ bbp_val |= 0x02;
+ mt7601u_bbp_wr(dev, 21, bbp_val);
+ bbp_val &= ~0x02;
+ mt7601u_bbp_wr(dev, 21, bbp_val);
+
+ mt7601u_wr(dev, MT_RF_BYPASS_0, 0);
+ mt7601u_wr(dev, MT_RF_SETTING_0, rf_set);
+ mt7601u_wr(dev, MT_RF_BYPASS_0, rf_bp);
+
+ trace_read_temp(dev, temp);
+ return temp;
+}
+
+static s8 mt7601u_read_temp(struct mt7601u_dev *dev)
+{
+ int i;
+ u8 val;
+ s8 temp;
+
+ val = mt7601u_bbp_rmw(dev, 47, 0x7f, 0x10);
+
+ /* Note: this rarely succeeds, temp can change even if it fails. */
+ for (i = 100; i && (val & 0x10); i--)
+ val = mt7601u_bbp_rr(dev, 47);
+
+ temp = mt7601u_bbp_r47_get(dev, val, BBP_R47_F_TEMP);
+
+ trace_read_temp(dev, temp);
+ return temp;
+}
+
+static void mt7601u_rxdc_cal(struct mt7601u_dev *dev)
+{
+ static const struct mt76_reg_pair intro[] = {
+ { 158, 0x8d }, { 159, 0xfc },
+ { 158, 0x8c }, { 159, 0x4c },
+ }, outro[] = {
+ { 158, 0x8d }, { 159, 0xe0 },
+ };
+ u32 mac_ctrl;
+ int i, ret;
+
+ mac_ctrl = mt7601u_rr(dev, MT_MAC_SYS_CTRL);
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX);
+
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP,
+ intro, ARRAY_SIZE(intro));
+ if (ret)
+ dev_err(dev->dev, "%s intro failed:%d\n", __func__, ret);
+
+ for (i = 20; i; i--) {
+ usleep_range(300, 500);
+
+ mt7601u_bbp_wr(dev, 158, 0x8c);
+ if (mt7601u_bbp_rr(dev, 159) == 0x0c)
+ break;
+ }
+ if (!i)
+ dev_err(dev->dev, "%s timed out\n", __func__);
+
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0);
+
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP,
+ outro, ARRAY_SIZE(outro));
+ if (ret)
+ dev_err(dev->dev, "%s outro failed:%d\n", __func__, ret);
+
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, mac_ctrl);
+}
+
+void mt7601u_phy_recalibrate_after_assoc(struct mt7601u_dev *dev)
+{
+ mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->curr_temp);
+
+ mt7601u_rxdc_cal(dev);
+}
+
+/* Note: function copied from vendor driver */
+static s16 lin2dBd(u16 linear)
+{
+ short exp = 0;
+ unsigned int mantisa;
+ int app, dBd;
+
+ if (WARN_ON(!linear))
+ return -10000;
+
+ mantisa = linear;
+
+ exp = fls(mantisa) - 16;
+ if (exp > 0)
+ mantisa >>= exp;
+ else
+ mantisa <<= abs(exp);
+
+ if (mantisa <= 0xb800)
+ app = (mantisa + (mantisa >> 3) + (mantisa >> 4) - 0x9600);
+ else
+ app = (mantisa - (mantisa >> 3) - (mantisa >> 6) - 0x5a00);
+ if (app < 0)
+ app = 0;
+
+ dBd = ((15 + exp) << 15) + app;
+ dBd = (dBd << 2) + (dBd << 1) + (dBd >> 6) + (dBd >> 7);
+ dBd = (dBd >> 10);
+
+ return dBd;
+}
+
+static void
+mt7601u_set_initial_tssi(struct mt7601u_dev *dev, s16 tssi_db, s16 tssi_hvga_db)
+{
+ struct tssi_data *d = &dev->ee->tssi_data;
+ int init_offset;
+
+ init_offset = -((tssi_db * d->slope + d->offset[1]) / 4096) + 10;
+
+ mt76_rmw(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP,
+ int_to_s6(init_offset) & MT_TX_ALC_CFG_1_TEMP_COMP);
+}
+
+static void mt7601u_tssi_dc_gain_cal(struct mt7601u_dev *dev)
+{
+ u8 rf_vga, rf_mixer, bbp_r47;
+ int i, j;
+ s8 res[4];
+ s16 tssi_init_db, tssi_init_hvga_db;
+
+ mt7601u_wr(dev, MT_RF_SETTING_0, 0x00000030);
+ mt7601u_wr(dev, MT_RF_BYPASS_0, 0x000c0030);
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0);
+
+ mt7601u_bbp_wr(dev, 58, 0);
+ mt7601u_bbp_wr(dev, 241, 0x2);
+ mt7601u_bbp_wr(dev, 23, 0x8);
+ bbp_r47 = mt7601u_bbp_rr(dev, 47);
+
+ /* Set VGA gain */
+ rf_vga = mt7601u_rf_rr(dev, 5, 3);
+ mt7601u_rf_wr(dev, 5, 3, 8);
+
+ /* Mixer disable */
+ rf_mixer = mt7601u_rf_rr(dev, 4, 39);
+ mt7601u_rf_wr(dev, 4, 39, 0);
+
+ for (i = 0; i < 4; i++) {
+ mt7601u_rf_wr(dev, 4, 39, (i & 1) ? rf_mixer : 0);
+
+ mt7601u_bbp_wr(dev, 23, (i < 2) ? 0x08 : 0x02);
+ mt7601u_rf_wr(dev, 5, 3, (i < 2) ? 0x08 : 0x11);
+
+ /* BBP TSSI initial and soft reset */
+ mt7601u_bbp_wr(dev, 22, 0);
+ mt7601u_bbp_wr(dev, 244, 0);
+
+ mt7601u_bbp_wr(dev, 21, 1);
+ udelay(1);
+ mt7601u_bbp_wr(dev, 21, 0);
+
+ /* TSSI measurement */
+ mt7601u_bbp_wr(dev, 47, 0x50);
+ mt7601u_bbp_wr(dev, (i & 1) ? 244 : 22, (i & 1) ? 0x31 : 0x40);
+
+ for (j = 20; j; j--)
+ if (!(mt7601u_bbp_rr(dev, 47) & 0x10))
+ break;
+ if (!j)
+ dev_err(dev->dev, "%s timed out\n", __func__);
+
+ /* TSSI read */
+ mt7601u_bbp_wr(dev, 47, 0x40);
+ res[i] = mt7601u_bbp_rr(dev, 49);
+ }
+
+ tssi_init_db = lin2dBd((short)res[1] - res[0]);
+ tssi_init_hvga_db = lin2dBd(((short)res[3] - res[2]) * 4);
+ dev->tssi_init = res[0];
+ dev->tssi_init_hvga = res[2];
+ dev->tssi_init_hvga_offset_db = tssi_init_hvga_db - tssi_init_db;
+
+ dev_dbg(dev->dev,
+ "TSSI_init:%hhx db:%hx hvga:%hhx hvga_db:%hx off_db:%hx\n",
+ dev->tssi_init, tssi_init_db, dev->tssi_init_hvga,
+ tssi_init_hvga_db, dev->tssi_init_hvga_offset_db);
+
+ mt7601u_bbp_wr(dev, 22, 0);
+ mt7601u_bbp_wr(dev, 244, 0);
+
+ mt7601u_bbp_wr(dev, 21, 1);
+ udelay(1);
+ mt7601u_bbp_wr(dev, 21, 0);
+
+ mt7601u_wr(dev, MT_RF_BYPASS_0, 0);
+ mt7601u_wr(dev, MT_RF_SETTING_0, 0);
+
+ mt7601u_rf_wr(dev, 5, 3, rf_vga);
+ mt7601u_rf_wr(dev, 4, 39, rf_mixer);
+ mt7601u_bbp_wr(dev, 47, bbp_r47);
+
+ mt7601u_set_initial_tssi(dev, tssi_init_db, tssi_init_hvga_db);
+}
+
+static int mt7601u_temp_comp(struct mt7601u_dev *dev, bool on)
+{
+ int ret, temp, hi_temp = 400, lo_temp = -200;
+
+ temp = (dev->raw_temp - dev->ee->ref_temp) * MT_EE_TEMPERATURE_SLOPE;
+ dev->curr_temp = temp;
+
+ /* DPD Calibration */
+ if (temp - dev->dpd_temp > 450 || temp - dev->dpd_temp < -450) {
+ dev->dpd_temp = temp;
+
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->dpd_temp);
+ if (ret)
+ return ret;
+
+ mt7601u_vco_cal(dev);
+
+ dev_dbg(dev->dev, "Recalibrate DPD\n");
+ }
+
+ /* PLL Lock Protect */
+ if (temp < -50 && !dev->pll_lock_protect) { /* < 20C */
+ dev->pll_lock_protect = true;
+
+ mt7601u_rf_wr(dev, 4, 4, 6);
+ mt7601u_rf_clear(dev, 4, 10, 0x30);
+
+ dev_dbg(dev->dev, "PLL lock protect on - too cold\n");
+ } else if (temp > 50 && dev->pll_lock_protect) { /* > 30C */
+ dev->pll_lock_protect = false;
+
+ mt7601u_rf_wr(dev, 4, 4, 0);
+ mt7601u_rf_rmw(dev, 4, 10, 0x30, 0x10);
+
+ dev_dbg(dev->dev, "PLL lock protect off\n");
+ }
+
+ if (on) {
+ hi_temp -= 50;
+ lo_temp -= 50;
+ }
+
+ /* BBP CR for H, L, N temperature */
+ if (temp > hi_temp)
+ return mt7601u_bbp_temp(dev, MT_TEMP_MODE_HIGH, "high");
+ else if (temp > lo_temp)
+ return mt7601u_bbp_temp(dev, MT_TEMP_MODE_NORMAL, "normal");
+ else
+ return mt7601u_bbp_temp(dev, MT_TEMP_MODE_LOW, "low");
+}
+
+/* Note: this is used only with TSSI, we can just use trgt_pwr from eeprom. */
+static int mt7601u_current_tx_power(struct mt7601u_dev *dev)
+{
+ return dev->ee->chan_pwr[dev->chandef.chan->hw_value - 1];
+}
+
+static bool mt7601u_use_hvga(struct mt7601u_dev *dev)
+{
+ return !(mt7601u_current_tx_power(dev) > 20);
+}
+
+static s16
+mt7601u_phy_rf_pa_mode_val(struct mt7601u_dev *dev, int phy_mode, int tx_rate)
+{
+ static const s16 decode_tb[] = { 0, 8847, -5734, -5734 };
+ u32 reg;
+
+ switch (phy_mode) {
+ case MT_PHY_TYPE_OFDM:
+ tx_rate += 4;
+ case MT_PHY_TYPE_CCK:
+ reg = dev->rf_pa_mode[0];
+ break;
+ default:
+ reg = dev->rf_pa_mode[1];
+ break;
+ }
+
+ return decode_tb[(reg >> (tx_rate * 2)) & 0x3];
+}
+
+static struct mt7601u_tssi_params
+mt7601u_tssi_params_get(struct mt7601u_dev *dev)
+{
+ static const u8 ofdm_pkt2rate[8] = { 6, 4, 2, 0, 7, 5, 3, 1 };
+ static const int static_power[4] = { 0, -49152, -98304, 49152 };
+ struct mt7601u_tssi_params p;
+ u8 bbp_r47, pkt_type, tx_rate;
+ struct power_per_rate *rate_table;
+
+ bbp_r47 = mt7601u_bbp_rr(dev, 47);
+
+ p.tssi0 = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_TSSI);
+ dev->raw_temp = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_TEMP);
+ pkt_type = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_PKT_T);
+
+ p.trgt_power = mt7601u_current_tx_power(dev);
+
+ switch (pkt_type & 0x03) {
+ case MT_PHY_TYPE_CCK:
+ tx_rate = (pkt_type >> 4) & 0x03;
+ rate_table = dev->ee->power_rate_table.cck;
+ break;
+
+ case MT_PHY_TYPE_OFDM:
+ tx_rate = ofdm_pkt2rate[(pkt_type >> 4) & 0x07];
+ rate_table = dev->ee->power_rate_table.ofdm;
+ break;
+
+ default:
+ tx_rate = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_TX_RATE);
+ tx_rate &= 0x7f;
+ rate_table = dev->ee->power_rate_table.ht;
+ break;
+ }
+
+ if (dev->bw == MT_BW_20)
+ p.trgt_power += rate_table[tx_rate / 2].bw20;
+ else
+ p.trgt_power += rate_table[tx_rate / 2].bw40;
+
+ p.trgt_power <<= 12;
+
+ dev_dbg(dev->dev, "tx_rate:%02hhx pwr:%08x\n", tx_rate, p.trgt_power);
+
+ p.trgt_power += mt7601u_phy_rf_pa_mode_val(dev, pkt_type & 0x03,
+ tx_rate);
+
+ /* Channel 14, cck, bw20 */
+ if ((pkt_type & 0x03) == MT_PHY_TYPE_CCK) {
+ if (mt7601u_bbp_rr(dev, 4) & 0x20)
+ p.trgt_power += mt7601u_bbp_rr(dev, 178) ? 18022 : 9830;
+ else
+ p.trgt_power += mt7601u_bbp_rr(dev, 178) ? 819 : 24576;
+ }
+
+ p.trgt_power += static_power[mt7601u_bbp_rr(dev, 1) & 0x03];
+
+ p.trgt_power += dev->ee->tssi_data.tx0_delta_offset;
+
+ dev_dbg(dev->dev,
+ "tssi:%02hhx t_power:%08x temp:%02hhx pkt_type:%02hhx\n",
+ p.tssi0, p.trgt_power, dev->raw_temp, pkt_type);
+
+ return p;
+}
+
+static bool mt7601u_tssi_read_ready(struct mt7601u_dev *dev)
+{
+ return !(mt7601u_bbp_rr(dev, 47) & 0x10);
+}
+
+static int mt7601u_tssi_cal(struct mt7601u_dev *dev)
+{
+ struct mt7601u_tssi_params params;
+ int curr_pwr, diff_pwr;
+ char tssi_offset;
+ s8 tssi_init;
+ s16 tssi_m_dc, tssi_db;
+ bool hvga;
+ u32 val;
+
+ if (!dev->ee->tssi_enabled)
+ return 0;
+
+ hvga = mt7601u_use_hvga(dev);
+ if (!dev->tssi_read_trig)
+ return mt7601u_mcu_tssi_read_kick(dev, hvga);
+
+ if (!mt7601u_tssi_read_ready(dev))
+ return 0;
+
+ params = mt7601u_tssi_params_get(dev);
+
+ tssi_init = (hvga ? dev->tssi_init_hvga : dev->tssi_init);
+ tssi_m_dc = params.tssi0 - tssi_init;
+ tssi_db = lin2dBd(tssi_m_dc);
+ dev_dbg(dev->dev, "tssi dc:%04hx db:%04hx hvga:%d\n",
+ tssi_m_dc, tssi_db, hvga);
+
+ if (dev->chandef.chan->hw_value < 5)
+ tssi_offset = dev->ee->tssi_data.offset[0];
+ else if (dev->chandef.chan->hw_value < 9)
+ tssi_offset = dev->ee->tssi_data.offset[1];
+ else
+ tssi_offset = dev->ee->tssi_data.offset[2];
+
+ if (hvga)
+ tssi_db -= dev->tssi_init_hvga_offset_db;
+
+ curr_pwr = tssi_db * dev->ee->tssi_data.slope + (tssi_offset << 9);
+ diff_pwr = params.trgt_power - curr_pwr;
+ dev_dbg(dev->dev, "Power curr:%08x diff:%08x\n", curr_pwr, diff_pwr);
+
+ if (params.tssi0 > 126 && diff_pwr > 0) {
+ dev_err(dev->dev, "Error: TSSI upper saturation\n");
+ diff_pwr = 0;
+ }
+ if (params.tssi0 - tssi_init < 1 && diff_pwr < 0) {
+ dev_err(dev->dev, "Error: TSSI lower saturation\n");
+ diff_pwr = 0;
+ }
+
+ if ((dev->prev_pwr_diff ^ diff_pwr) < 0 && abs(diff_pwr) < 4096 &&
+ (abs(diff_pwr) > abs(dev->prev_pwr_diff) ||
+ (diff_pwr > 0 && diff_pwr == -dev->prev_pwr_diff)))
+ diff_pwr = 0;
+ else
+ dev->prev_pwr_diff = diff_pwr;
+
+ diff_pwr += (diff_pwr > 0) ? 2048 : -2048;
+ diff_pwr /= 4096;
+
+ dev_dbg(dev->dev, "final diff: %08x\n", diff_pwr);
+
+ val = mt7601u_rr(dev, MT_TX_ALC_CFG_1);
+ curr_pwr = s6_to_int(MT76_GET(MT_TX_ALC_CFG_1_TEMP_COMP, val));
+ diff_pwr += curr_pwr;
+ val = (val & ~MT_TX_ALC_CFG_1_TEMP_COMP) | int_to_s6(diff_pwr);
+ mt7601u_wr(dev, MT_TX_ALC_CFG_1, val);
+
+ return mt7601u_mcu_tssi_read_kick(dev, hvga);
+}
+
+static u8 mt7601u_agc_default(struct mt7601u_dev *dev)
+{
+ return (dev->ee->lna_gain - 8) * 2 + 0x34;
+}
+
+static void mt7601u_agc_reset(struct mt7601u_dev *dev)
+{
+ u8 agc = mt7601u_agc_default(dev);
+
+ mt7601u_bbp_wr(dev, 66, agc);
+}
+
+void mt7601u_agc_save(struct mt7601u_dev *dev)
+{
+ dev->agc_save = mt7601u_bbp_rr(dev, 66);
+}
+
+void mt7601u_agc_restore(struct mt7601u_dev *dev)
+{
+ mt7601u_bbp_wr(dev, 66, dev->agc_save);
+}
+
+static void mt7601u_agc_tune(struct mt7601u_dev *dev)
+{
+ u8 val = mt7601u_agc_default(dev);
+
+ if (test_bit(MT7601U_STATE_SCANNING, &dev->state))
+ return;
+
+ /* Note: only in STA mode and not dozing; perhaps do this only if
+ * there is enough rssi updates since last run?
+ * Rssi updates are only on beacons and U2M so should work...
+ */
+ spin_lock_bh(&dev->con_mon_lock);
+ if (dev->avg_rssi <= -70)
+ val -= 0x20;
+ else if (dev->avg_rssi <= -60)
+ val -= 0x10;
+ spin_unlock_bh(&dev->con_mon_lock);
+
+ if (val != mt7601u_bbp_rr(dev, 66))
+ mt7601u_bbp_wr(dev, 66, val);
+
+ /* TODO: also if lost a lot of beacons try resetting
+ * (see RTMPSetAGCInitValue() call in mlme.c).
+ */
+}
+
+static void mt7601u_phy_calibrate(struct work_struct *work)
+{
+ struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev,
+ cal_work.work);
+
+ mt7601u_agc_tune(dev);
+ mt7601u_tssi_cal(dev);
+ /* If TSSI calibration was run it already updated temperature. */
+ if (!dev->ee->tssi_enabled)
+ dev->raw_temp = mt7601u_read_temp(dev);
+ mt7601u_temp_comp(dev, true); /* TODO: find right value for @on */
+
+ ieee80211_queue_delayed_work(dev->hw, &dev->cal_work,
+ MT_CALIBRATE_INTERVAL);
+}
+
+static unsigned long
+__mt7601u_phy_freq_cal(struct mt7601u_dev *dev, s8 last_offset, u8 phy_mode)
+{
+ u8 activate_threshold, deactivate_threshold;
+
+ trace_freq_cal_offset(dev, phy_mode, last_offset);
+
+ /* No beacons received - reschedule soon */
+ if (last_offset == MT_FREQ_OFFSET_INVALID)
+ return MT_FREQ_CAL_ADJ_INTERVAL;
+
+ switch (phy_mode) {
+ case MT_PHY_TYPE_CCK:
+ activate_threshold = 19;
+ deactivate_threshold = 5;
+ break;
+ case MT_PHY_TYPE_OFDM:
+ activate_threshold = 102;
+ deactivate_threshold = 32;
+ break;
+ case MT_PHY_TYPE_HT:
+ case MT_PHY_TYPE_HT_GF:
+ activate_threshold = 82;
+ deactivate_threshold = 20;
+ break;
+ default:
+ WARN_ON(1);
+ return MT_FREQ_CAL_CHECK_INTERVAL;
+ }
+
+ if (abs(last_offset) >= activate_threshold)
+ dev->freq_cal.adjusting = true;
+ else if (abs(last_offset) <= deactivate_threshold)
+ dev->freq_cal.adjusting = false;
+
+ if (!dev->freq_cal.adjusting)
+ return MT_FREQ_CAL_CHECK_INTERVAL;
+
+ if (last_offset > deactivate_threshold) {
+ if (dev->freq_cal.freq > 0)
+ dev->freq_cal.freq--;
+ else
+ dev->freq_cal.adjusting = false;
+ } else if (last_offset < -deactivate_threshold) {
+ if (dev->freq_cal.freq < 0xbf)
+ dev->freq_cal.freq++;
+ else
+ dev->freq_cal.adjusting = false;
+ }
+
+ trace_freq_cal_adjust(dev, dev->freq_cal.freq);
+ mt7601u_rf_wr(dev, 0, 12, dev->freq_cal.freq);
+ mt7601u_vco_cal(dev);
+
+ return dev->freq_cal.adjusting ? MT_FREQ_CAL_ADJ_INTERVAL :
+ MT_FREQ_CAL_CHECK_INTERVAL;
+}
+
+static void mt7601u_phy_freq_cal(struct work_struct *work)
+{
+ struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev,
+ freq_cal.work.work);
+ s8 last_offset;
+ u8 phy_mode;
+ unsigned long delay;
+
+ spin_lock_bh(&dev->con_mon_lock);
+ last_offset = dev->bcn_freq_off;
+ phy_mode = dev->bcn_phy_mode;
+ spin_unlock_bh(&dev->con_mon_lock);
+
+ delay = __mt7601u_phy_freq_cal(dev, last_offset, phy_mode);
+ ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work, delay);
+
+ spin_lock_bh(&dev->con_mon_lock);
+ dev->bcn_freq_off = MT_FREQ_OFFSET_INVALID;
+ spin_unlock_bh(&dev->con_mon_lock);
+}
+
+void mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev,
+ struct ieee80211_bss_conf *info)
+{
+ if (!info->assoc)
+ cancel_delayed_work_sync(&dev->freq_cal.work);
+
+ /* Start/stop collecting beacon data */
+ spin_lock_bh(&dev->con_mon_lock);
+ ether_addr_copy(dev->ap_bssid, info->bssid);
+ dev->avg_rssi = 0;
+ dev->bcn_freq_off = MT_FREQ_OFFSET_INVALID;
+ spin_unlock_bh(&dev->con_mon_lock);
+
+ dev->freq_cal.freq = dev->ee->rf_freq_off;
+ dev->freq_cal.enabled = info->assoc;
+ dev->freq_cal.adjusting = false;
+
+ if (info->assoc)
+ ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work,
+ MT_FREQ_CAL_INIT_DELAY);
+}
+
+static int mt7601u_init_cal(struct mt7601u_dev *dev)
+{
+ u32 mac_ctrl;
+ int ret;
+
+ dev->raw_temp = mt7601u_read_bootup_temp(dev);
+ dev->curr_temp = (dev->raw_temp - dev->ee->ref_temp) *
+ MT_EE_TEMPERATURE_SLOPE;
+ dev->dpd_temp = dev->curr_temp;
+
+ mac_ctrl = mt7601u_rr(dev, MT_MAC_SYS_CTRL);
+
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_R, 0);
+ if (ret)
+ return ret;
+
+ ret = mt7601u_rf_rr(dev, 0, 4);
+ if (ret < 0)
+ return ret;
+ ret |= 0x80;
+ ret = mt7601u_rf_wr(dev, 0, 4, ret);
+ if (ret)
+ return ret;
+ msleep(2);
+
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_TXDCOC, 0);
+ if (ret)
+ return ret;
+
+ mt7601u_rxdc_cal(dev);
+
+ ret = mt7601u_set_bw_filter(dev, true);
+ if (ret)
+ return ret;
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_LOFT, 0);
+ if (ret)
+ return ret;
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_TXIQ, 0);
+ if (ret)
+ return ret;
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_RXIQ, 0);
+ if (ret)
+ return ret;
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->dpd_temp);
+ if (ret)
+ return ret;
+
+ mt7601u_rxdc_cal(dev);
+
+ mt7601u_tssi_dc_gain_cal(dev);
+
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, mac_ctrl);
+
+ mt7601u_temp_comp(dev, true);
+
+ return 0;
+}
+
+int mt7601u_bbp_set_bw(struct mt7601u_dev *dev, int bw)
+{
+ u32 val, old;
+
+ if (bw == dev->bw) {
+ /* Vendor driver does the rmc even when no change is needed. */
+ mt7601u_bbp_rmc(dev, 4, 0x18, bw == MT_BW_20 ? 0 : 0x10);
+
+ return 0;
+ }
+ dev->bw = bw;
+
+ /* Stop MAC for the time of bw change */
+ old = mt7601u_rr(dev, MT_MAC_SYS_CTRL);
+ val = old & ~(MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, val);
+ mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX | MT_MAC_STATUS_RX,
+ 0, 500000);
+
+ mt7601u_bbp_rmc(dev, 4, 0x18, bw == MT_BW_20 ? 0 : 0x10);
+
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, old);
+
+ return mt7601u_load_bbp_temp_table_bw(dev);
+}
+
+/**
+ * mt7601u_set_rx_path - set rx path in BBP
+ * @dev: pointer to adapter structure
+ * @path: rx path to set values are 0-based
+ */
+void mt7601u_set_rx_path(struct mt7601u_dev *dev, u8 path)
+{
+ mt7601u_bbp_rmw(dev, 3, 0x18, path << 3);
+}
+
+/**
+ * mt7601u_set_tx_dac - set which tx DAC to use
+ * @dev: pointer to adapter structure
+ * @path: DAC index, values are 0-based
+ */
+void mt7601u_set_tx_dac(struct mt7601u_dev *dev, u8 dac)
+{
+ mt7601u_bbp_rmc(dev, 1, 0x18, dac << 3);
+}
+
+int mt7601u_phy_init(struct mt7601u_dev *dev)
+{
+ int ret;
+
+ dev->rf_pa_mode[0] = mt7601u_rr(dev, MT_RF_PA_MODE_CFG0);
+ dev->rf_pa_mode[1] = mt7601u_rr(dev, MT_RF_PA_MODE_CFG1);
+
+ ret = mt7601u_rf_wr(dev, 0, 12, dev->ee->rf_freq_off);
+ if (ret)
+ return ret;
+ ret = mt7601u_write_reg_pairs(dev, 0, rf_central,
+ ARRAY_SIZE(rf_central));
+ if (ret)
+ return ret;
+ ret = mt7601u_write_reg_pairs(dev, 0, rf_channel,
+ ARRAY_SIZE(rf_channel));
+ if (ret)
+ return ret;
+ ret = mt7601u_write_reg_pairs(dev, 0, rf_vga, ARRAY_SIZE(rf_vga));
+ if (ret)
+ return ret;
+
+ ret = mt7601u_init_cal(dev);
+ if (ret)
+ return ret;
+
+ dev->prev_pwr_diff = 100;
+
+ INIT_DELAYED_WORK(&dev->cal_work, mt7601u_phy_calibrate);
+ INIT_DELAYED_WORK(&dev->freq_cal.work, mt7601u_phy_freq_cal);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/regs.h b/drivers/net/wireless/mediatek/mt7601u/regs.h
new file mode 100644
index 000000000000..afd8978e83fa
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/regs.h
@@ -0,0 +1,636 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#ifndef __MT76_REGS_H
+#define __MT76_REGS_H
+
+#include <linux/bitops.h>
+
+#ifndef GENMASK
+#define GENMASK(h, l) (((U32_C(1) << ((h) - (l) + 1)) - 1) << (l))
+#endif
+
+#define MT_ASIC_VERSION 0x0000
+
+#define MT76XX_REV_E3 0x22
+#define MT76XX_REV_E4 0x33
+
+#define MT_CMB_CTRL 0x0020
+#define MT_CMB_CTRL_XTAL_RDY BIT(22)
+#define MT_CMB_CTRL_PLL_LD BIT(23)
+
+#define MT_EFUSE_CTRL 0x0024
+#define MT_EFUSE_CTRL_AOUT GENMASK(5, 0)
+#define MT_EFUSE_CTRL_MODE GENMASK(7, 6)
+#define MT_EFUSE_CTRL_LDO_OFF_TIME GENMASK(13, 8)
+#define MT_EFUSE_CTRL_LDO_ON_TIME GENMASK(15, 14)
+#define MT_EFUSE_CTRL_AIN GENMASK(25, 16)
+#define MT_EFUSE_CTRL_KICK BIT(30)
+#define MT_EFUSE_CTRL_SEL BIT(31)
+
+#define MT_EFUSE_DATA_BASE 0x0028
+#define MT_EFUSE_DATA(_n) (MT_EFUSE_DATA_BASE + ((_n) << 2))
+
+#define MT_COEXCFG0 0x0040
+#define MT_COEXCFG0_COEX_EN BIT(0)
+
+#define MT_WLAN_FUN_CTRL 0x0080
+#define MT_WLAN_FUN_CTRL_WLAN_EN BIT(0)
+#define MT_WLAN_FUN_CTRL_WLAN_CLK_EN BIT(1)
+#define MT_WLAN_FUN_CTRL_WLAN_RESET_RF BIT(2)
+
+#define MT_WLAN_FUN_CTRL_WLAN_RESET BIT(3) /* MT76x0 */
+#define MT_WLAN_FUN_CTRL_CSR_F20M_CKEN BIT(3) /* MT76x2 */
+
+#define MT_WLAN_FUN_CTRL_PCIE_CLK_REQ BIT(4)
+#define MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL BIT(5)
+#define MT_WLAN_FUN_CTRL_INV_ANT_SEL BIT(6)
+#define MT_WLAN_FUN_CTRL_WAKE_HOST BIT(7)
+
+#define MT_WLAN_FUN_CTRL_THERM_RST BIT(8) /* MT76x2 */
+#define MT_WLAN_FUN_CTRL_THERM_CKEN BIT(9) /* MT76x2 */
+
+#define MT_WLAN_FUN_CTRL_GPIO_IN GENMASK(15, 8) /* MT76x0 */
+#define MT_WLAN_FUN_CTRL_GPIO_OUT GENMASK(23, 16) /* MT76x0 */
+#define MT_WLAN_FUN_CTRL_GPIO_OUT_EN GENMASK(31, 24) /* MT76x0 */
+
+#define MT_XO_CTRL0 0x0100
+#define MT_XO_CTRL1 0x0104
+#define MT_XO_CTRL2 0x0108
+#define MT_XO_CTRL3 0x010c
+#define MT_XO_CTRL4 0x0110
+
+#define MT_XO_CTRL5 0x0114
+#define MT_XO_CTRL5_C2_VAL GENMASK(14, 8)
+
+#define MT_XO_CTRL6 0x0118
+#define MT_XO_CTRL6_C2_CTRL GENMASK(14, 8)
+
+#define MT_XO_CTRL7 0x011c
+
+#define MT_WLAN_MTC_CTRL 0x10148
+#define MT_WLAN_MTC_CTRL_MTCMOS_PWR_UP BIT(0)
+#define MT_WLAN_MTC_CTRL_PWR_ACK BIT(12)
+#define MT_WLAN_MTC_CTRL_PWR_ACK_S BIT(13)
+#define MT_WLAN_MTC_CTRL_BBP_MEM_PD GENMASK(19, 16)
+#define MT_WLAN_MTC_CTRL_PBF_MEM_PD BIT(20)
+#define MT_WLAN_MTC_CTRL_FCE_MEM_PD BIT(21)
+#define MT_WLAN_MTC_CTRL_TSO_MEM_PD BIT(22)
+#define MT_WLAN_MTC_CTRL_BBP_MEM_RB BIT(24)
+#define MT_WLAN_MTC_CTRL_PBF_MEM_RB BIT(25)
+#define MT_WLAN_MTC_CTRL_FCE_MEM_RB BIT(26)
+#define MT_WLAN_MTC_CTRL_TSO_MEM_RB BIT(27)
+#define MT_WLAN_MTC_CTRL_STATE_UP BIT(28)
+
+#define MT_INT_SOURCE_CSR 0x0200
+#define MT_INT_MASK_CSR 0x0204
+
+#define MT_INT_RX_DONE(_n) BIT(_n)
+#define MT_INT_RX_DONE_ALL GENMASK(1, 0)
+#define MT_INT_TX_DONE_ALL GENMASK(13, 4)
+#define MT_INT_TX_DONE(_n) BIT(_n + 4)
+#define MT_INT_RX_COHERENT BIT(16)
+#define MT_INT_TX_COHERENT BIT(17)
+#define MT_INT_ANY_COHERENT BIT(18)
+#define MT_INT_MCU_CMD BIT(19)
+#define MT_INT_TBTT BIT(20)
+#define MT_INT_PRE_TBTT BIT(21)
+#define MT_INT_TX_STAT BIT(22)
+#define MT_INT_AUTO_WAKEUP BIT(23)
+#define MT_INT_GPTIMER BIT(24)
+#define MT_INT_RXDELAYINT BIT(26)
+#define MT_INT_TXDELAYINT BIT(27)
+
+#define MT_WPDMA_GLO_CFG 0x0208
+#define MT_WPDMA_GLO_CFG_TX_DMA_EN BIT(0)
+#define MT_WPDMA_GLO_CFG_TX_DMA_BUSY BIT(1)
+#define MT_WPDMA_GLO_CFG_RX_DMA_EN BIT(2)
+#define MT_WPDMA_GLO_CFG_RX_DMA_BUSY BIT(3)
+#define MT_WPDMA_GLO_CFG_DMA_BURST_SIZE GENMASK(5, 4)
+#define MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE BIT(6)
+#define MT_WPDMA_GLO_CFG_BIG_ENDIAN BIT(7)
+#define MT_WPDMA_GLO_CFG_HDR_SEG_LEN GENMASK(15, 8)
+#define MT_WPDMA_GLO_CFG_CLK_GATE_DIS BIT(30)
+#define MT_WPDMA_GLO_CFG_RX_2B_OFFSET BIT(31)
+
+#define MT_WPDMA_RST_IDX 0x020c
+
+#define MT_WPDMA_DELAY_INT_CFG 0x0210
+
+#define MT_WMM_AIFSN 0x0214
+#define MT_WMM_AIFSN_MASK GENMASK(3, 0)
+#define MT_WMM_AIFSN_SHIFT(_n) ((_n) * 4)
+
+#define MT_WMM_CWMIN 0x0218
+#define MT_WMM_CWMIN_MASK GENMASK(3, 0)
+#define MT_WMM_CWMIN_SHIFT(_n) ((_n) * 4)
+
+#define MT_WMM_CWMAX 0x021c
+#define MT_WMM_CWMAX_MASK GENMASK(3, 0)
+#define MT_WMM_CWMAX_SHIFT(_n) ((_n) * 4)
+
+#define MT_WMM_TXOP_BASE 0x0220
+#define MT_WMM_TXOP(_n) (MT_WMM_TXOP_BASE + (((_n) / 2) << 2))
+#define MT_WMM_TXOP_SHIFT(_n) ((_n & 1) * 16)
+#define MT_WMM_TXOP_MASK GENMASK(15, 0)
+
+#define MT_FCE_DMA_ADDR 0x0230
+#define MT_FCE_DMA_LEN 0x0234
+
+#define MT_USB_DMA_CFG 0x238
+#define MT_USB_DMA_CFG_RX_BULK_AGG_TOUT GENMASK(7, 0)
+#define MT_USB_DMA_CFG_RX_BULK_AGG_LMT GENMASK(15, 8)
+#define MT_USB_DMA_CFG_PHY_CLR BIT(16)
+#define MT_USB_DMA_CFG_TX_CLR BIT(19)
+#define MT_USB_DMA_CFG_TXOP_HALT BIT(20)
+#define MT_USB_DMA_CFG_RX_BULK_AGG_EN BIT(21)
+#define MT_USB_DMA_CFG_RX_BULK_EN BIT(22)
+#define MT_USB_DMA_CFG_TX_BULK_EN BIT(23)
+#define MT_USB_DMA_CFG_UDMA_RX_WL_DROP BIT(25)
+#define MT_USB_DMA_CFG_EP_OUT_VALID GENMASK(29, 27)
+#define MT_USB_DMA_CFG_RX_BUSY BIT(30)
+#define MT_USB_DMA_CFG_TX_BUSY BIT(31)
+
+#define MT_TSO_CTRL 0x0250
+#define MT_HEADER_TRANS_CTRL_REG 0x0260
+
+#define MT_US_CYC_CFG 0x02a4
+#define MT_US_CYC_CNT GENMASK(7, 0)
+
+#define MT_TX_RING_BASE 0x0300
+#define MT_RX_RING_BASE 0x03c0
+#define MT_RING_SIZE 0x10
+
+#define MT_TX_HW_QUEUE_MCU 8
+#define MT_TX_HW_QUEUE_MGMT 9
+
+#define MT_PBF_SYS_CTRL 0x0400
+#define MT_PBF_SYS_CTRL_MCU_RESET BIT(0)
+#define MT_PBF_SYS_CTRL_DMA_RESET BIT(1)
+#define MT_PBF_SYS_CTRL_MAC_RESET BIT(2)
+#define MT_PBF_SYS_CTRL_PBF_RESET BIT(3)
+#define MT_PBF_SYS_CTRL_ASY_RESET BIT(4)
+
+#define MT_PBF_CFG 0x0404
+#define MT_PBF_CFG_TX0Q_EN BIT(0)
+#define MT_PBF_CFG_TX1Q_EN BIT(1)
+#define MT_PBF_CFG_TX2Q_EN BIT(2)
+#define MT_PBF_CFG_TX3Q_EN BIT(3)
+#define MT_PBF_CFG_RX0Q_EN BIT(4)
+#define MT_PBF_CFG_RX_DROP_EN BIT(8)
+
+#define MT_PBF_TX_MAX_PCNT 0x0408
+#define MT_PBF_RX_MAX_PCNT 0x040c
+
+#define MT_BCN_OFFSET_BASE 0x041c
+#define MT_BCN_OFFSET(_n) (MT_BCN_OFFSET_BASE + ((_n) << 2))
+
+#define MT_RF_CSR_CFG 0x0500
+#define MT_RF_CSR_CFG_DATA GENMASK(7, 0)
+#define MT_RF_CSR_CFG_REG_ID GENMASK(13, 8)
+#define MT_RF_CSR_CFG_REG_BANK GENMASK(17, 14)
+#define MT_RF_CSR_CFG_WR BIT(30)
+#define MT_RF_CSR_CFG_KICK BIT(31)
+
+#define MT_RF_BYPASS_0 0x0504
+#define MT_RF_BYPASS_1 0x0508
+#define MT_RF_SETTING_0 0x050c
+
+#define MT_RF_DATA_WRITE 0x0524
+
+#define MT_RF_CTRL 0x0528
+#define MT_RF_CTRL_ADDR GENMASK(11, 0)
+#define MT_RF_CTRL_WRITE BIT(12)
+#define MT_RF_CTRL_BUSY BIT(13)
+#define MT_RF_CTRL_IDX BIT(16)
+
+#define MT_RF_DATA_READ 0x052c
+
+#define MT_FCE_PSE_CTRL 0x0800
+#define MT_FCE_PARAMETERS 0x0804
+#define MT_FCE_CSO 0x0808
+
+#define MT_FCE_L2_STUFF 0x080c
+#define MT_FCE_L2_STUFF_HT_L2_EN BIT(0)
+#define MT_FCE_L2_STUFF_QOS_L2_EN BIT(1)
+#define MT_FCE_L2_STUFF_RX_STUFF_EN BIT(2)
+#define MT_FCE_L2_STUFF_TX_STUFF_EN BIT(3)
+#define MT_FCE_L2_STUFF_WR_MPDU_LEN_EN BIT(4)
+#define MT_FCE_L2_STUFF_MVINV_BSWAP BIT(5)
+#define MT_FCE_L2_STUFF_TS_CMD_QSEL_EN GENMASK(15, 8)
+#define MT_FCE_L2_STUFF_TS_LEN_EN GENMASK(23, 16)
+#define MT_FCE_L2_STUFF_OTHER_PORT GENMASK(25, 24)
+
+#define MT_FCE_WLAN_FLOW_CONTROL1 0x0824
+
+#define MT_TX_CPU_FROM_FCE_BASE_PTR 0x09a0
+#define MT_TX_CPU_FROM_FCE_MAX_COUNT 0x09a4
+#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8
+
+#define MT_FCE_PDMA_GLOBAL_CONF 0x09c4
+
+#define MT_PAUSE_ENABLE_CONTROL1 0x0a38
+
+#define MT_FCE_SKIP_FS 0x0a6c
+
+#define MT_MAC_CSR0 0x1000
+
+#define MT_MAC_SYS_CTRL 0x1004
+#define MT_MAC_SYS_CTRL_RESET_CSR BIT(0)
+#define MT_MAC_SYS_CTRL_RESET_BBP BIT(1)
+#define MT_MAC_SYS_CTRL_ENABLE_TX BIT(2)
+#define MT_MAC_SYS_CTRL_ENABLE_RX BIT(3)
+
+#define MT_MAC_ADDR_DW0 0x1008
+#define MT_MAC_ADDR_DW1 0x100c
+#define MT_MAC_ADDR_DW1_U2ME_MASK GENMASK(23, 16)
+
+#define MT_MAC_BSSID_DW0 0x1010
+#define MT_MAC_BSSID_DW1 0x1014
+#define MT_MAC_BSSID_DW1_ADDR GENMASK(15, 0)
+#define MT_MAC_BSSID_DW1_MBSS_MODE GENMASK(17, 16)
+#define MT_MAC_BSSID_DW1_MBEACON_N GENMASK(20, 18)
+#define MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT BIT(21)
+#define MT_MAC_BSSID_DW1_MBSS_MODE_B2 BIT(22)
+#define MT_MAC_BSSID_DW1_MBEACON_N_B3 BIT(23)
+#define MT_MAC_BSSID_DW1_MBSS_IDX_BYTE GENMASK(26, 24)
+
+#define MT_MAX_LEN_CFG 0x1018
+#define MT_MAX_LEN_CFG_AMPDU GENMASK(13, 12)
+
+#define MT_BBP_CSR_CFG 0x101c
+#define MT_BBP_CSR_CFG_VAL GENMASK(7, 0)
+#define MT_BBP_CSR_CFG_REG_NUM GENMASK(15, 8)
+#define MT_BBP_CSR_CFG_READ BIT(16)
+#define MT_BBP_CSR_CFG_BUSY BIT(17)
+#define MT_BBP_CSR_CFG_PAR_DUR BIT(18)
+#define MT_BBP_CSR_CFG_RW_MODE BIT(19)
+
+#define MT_AMPDU_MAX_LEN_20M1S 0x1030
+#define MT_AMPDU_MAX_LEN_20M2S 0x1034
+#define MT_AMPDU_MAX_LEN_40M1S 0x1038
+#define MT_AMPDU_MAX_LEN_40M2S 0x103c
+#define MT_AMPDU_MAX_LEN 0x1040
+
+#define MT_WCID_DROP_BASE 0x106c
+#define MT_WCID_DROP(_n) (MT_WCID_DROP_BASE + ((_n) >> 5) * 4)
+#define MT_WCID_DROP_MASK(_n) BIT((_n) % 32)
+
+#define MT_BCN_BYPASS_MASK 0x108c
+
+#define MT_MAC_APC_BSSID_BASE 0x1090
+#define MT_MAC_APC_BSSID_L(_n) (MT_MAC_APC_BSSID_BASE + ((_n) * 8))
+#define MT_MAC_APC_BSSID_H(_n) (MT_MAC_APC_BSSID_BASE + ((_n) * 8 + 4))
+#define MT_MAC_APC_BSSID_H_ADDR GENMASK(15, 0)
+#define MT_MAC_APC_BSSID0_H_EN BIT(16)
+
+#define MT_XIFS_TIME_CFG 0x1100
+#define MT_XIFS_TIME_CFG_CCK_SIFS GENMASK(7, 0)
+#define MT_XIFS_TIME_CFG_OFDM_SIFS GENMASK(15, 8)
+#define MT_XIFS_TIME_CFG_OFDM_XIFS GENMASK(19, 16)
+#define MT_XIFS_TIME_CFG_EIFS GENMASK(28, 20)
+#define MT_XIFS_TIME_CFG_BB_RXEND_EN BIT(29)
+
+#define MT_BKOFF_SLOT_CFG 0x1104
+#define MT_BKOFF_SLOT_CFG_SLOTTIME GENMASK(7, 0)
+#define MT_BKOFF_SLOT_CFG_CC_DELAY GENMASK(11, 8)
+
+#define MT_BEACON_TIME_CFG 0x1114
+#define MT_BEACON_TIME_CFG_INTVAL GENMASK(15, 0)
+#define MT_BEACON_TIME_CFG_TIMER_EN BIT(16)
+#define MT_BEACON_TIME_CFG_SYNC_MODE GENMASK(18, 17)
+#define MT_BEACON_TIME_CFG_TBTT_EN BIT(19)
+#define MT_BEACON_TIME_CFG_BEACON_TX BIT(20)
+#define MT_BEACON_TIME_CFG_TSF_COMP GENMASK(31, 24)
+
+#define MT_TBTT_SYNC_CFG 0x1118
+#define MT_TBTT_TIMER_CFG 0x1124
+
+#define MT_INT_TIMER_CFG 0x1128
+#define MT_INT_TIMER_CFG_PRE_TBTT GENMASK(15, 0)
+#define MT_INT_TIMER_CFG_GP_TIMER GENMASK(31, 16)
+
+#define MT_INT_TIMER_EN 0x112c
+#define MT_INT_TIMER_EN_PRE_TBTT_EN BIT(0)
+#define MT_INT_TIMER_EN_GP_TIMER_EN BIT(1)
+
+#define MT_MAC_STATUS 0x1200
+#define MT_MAC_STATUS_TX BIT(0)
+#define MT_MAC_STATUS_RX BIT(1)
+
+#define MT_PWR_PIN_CFG 0x1204
+#define MT_AUX_CLK_CFG 0x120c
+
+#define MT_BB_PA_MODE_CFG0 0x1214
+#define MT_BB_PA_MODE_CFG1 0x1218
+#define MT_RF_PA_MODE_CFG0 0x121c
+#define MT_RF_PA_MODE_CFG1 0x1220
+
+#define MT_RF_PA_MODE_ADJ0 0x1228
+#define MT_RF_PA_MODE_ADJ1 0x122c
+
+#define MT_DACCLK_EN_DLY_CFG 0x1264
+
+#define MT_EDCA_CFG_BASE 0x1300
+#define MT_EDCA_CFG_AC(_n) (MT_EDCA_CFG_BASE + ((_n) << 2))
+#define MT_EDCA_CFG_TXOP GENMASK(7, 0)
+#define MT_EDCA_CFG_AIFSN GENMASK(11, 8)
+#define MT_EDCA_CFG_CWMIN GENMASK(15, 12)
+#define MT_EDCA_CFG_CWMAX GENMASK(19, 16)
+
+#define MT_TX_PWR_CFG_0 0x1314
+#define MT_TX_PWR_CFG_1 0x1318
+#define MT_TX_PWR_CFG_2 0x131c
+#define MT_TX_PWR_CFG_3 0x1320
+#define MT_TX_PWR_CFG_4 0x1324
+
+#define MT_TX_BAND_CFG 0x132c
+#define MT_TX_BAND_CFG_UPPER_40M BIT(0)
+#define MT_TX_BAND_CFG_5G BIT(1)
+#define MT_TX_BAND_CFG_2G BIT(2)
+
+#define MT_HT_FBK_TO_LEGACY 0x1384
+#define MT_TX_MPDU_ADJ_INT 0x1388
+
+#define MT_TX_PWR_CFG_7 0x13d4
+#define MT_TX_PWR_CFG_8 0x13d8
+#define MT_TX_PWR_CFG_9 0x13dc
+
+#define MT_TX_SW_CFG0 0x1330
+#define MT_TX_SW_CFG1 0x1334
+#define MT_TX_SW_CFG2 0x1338
+
+#define MT_TXOP_CTRL_CFG 0x1340
+#define MT_TXOP_TRUN_EN GENMASK(5, 0)
+#define MT_TXOP_EXT_CCA_DLY GENMASK(15, 8)
+#define MT_TXOP_CTRL
+
+#define MT_TX_RTS_CFG 0x1344
+#define MT_TX_RTS_CFG_RETRY_LIMIT GENMASK(7, 0)
+#define MT_TX_RTS_CFG_THRESH GENMASK(23, 8)
+#define MT_TX_RTS_FALLBACK BIT(24)
+
+#define MT_TX_TIMEOUT_CFG 0x1348
+#define MT_TX_RETRY_CFG 0x134c
+#define MT_TX_LINK_CFG 0x1350
+#define MT_HT_FBK_CFG0 0x1354
+#define MT_HT_FBK_CFG1 0x1358
+#define MT_LG_FBK_CFG0 0x135c
+#define MT_LG_FBK_CFG1 0x1360
+
+#define MT_CCK_PROT_CFG 0x1364
+#define MT_OFDM_PROT_CFG 0x1368
+#define MT_MM20_PROT_CFG 0x136c
+#define MT_MM40_PROT_CFG 0x1370
+#define MT_GF20_PROT_CFG 0x1374
+#define MT_GF40_PROT_CFG 0x1378
+
+#define MT_PROT_RATE GENMASK(15, 0)
+#define MT_PROT_CTRL_RTS_CTS BIT(16)
+#define MT_PROT_CTRL_CTS2SELF BIT(17)
+#define MT_PROT_NAV_SHORT BIT(18)
+#define MT_PROT_NAV_LONG BIT(19)
+#define MT_PROT_TXOP_ALLOW_CCK BIT(20)
+#define MT_PROT_TXOP_ALLOW_OFDM BIT(21)
+#define MT_PROT_TXOP_ALLOW_MM20 BIT(22)
+#define MT_PROT_TXOP_ALLOW_MM40 BIT(23)
+#define MT_PROT_TXOP_ALLOW_GF20 BIT(24)
+#define MT_PROT_TXOP_ALLOW_GF40 BIT(25)
+#define MT_PROT_RTS_THR_EN BIT(26)
+#define MT_PROT_RATE_CCK_11 0x0003
+#define MT_PROT_RATE_OFDM_6 0x4000
+#define MT_PROT_RATE_OFDM_24 0x4004
+#define MT_PROT_RATE_DUP_OFDM_24 0x4084
+#define MT_PROT_TXOP_ALLOW_ALL GENMASK(25, 20)
+#define MT_PROT_TXOP_ALLOW_BW20 (MT_PROT_TXOP_ALLOW_ALL & \
+ ~MT_PROT_TXOP_ALLOW_MM40 & \
+ ~MT_PROT_TXOP_ALLOW_GF40)
+
+#define MT_EXP_ACK_TIME 0x1380
+
+#define MT_TX_PWR_CFG_0_EXT 0x1390
+#define MT_TX_PWR_CFG_1_EXT 0x1394
+
+#define MT_TX_FBK_LIMIT 0x1398
+#define MT_TX_FBK_LIMIT_MPDU_FBK GENMASK(7, 0)
+#define MT_TX_FBK_LIMIT_AMPDU_FBK GENMASK(15, 8)
+#define MT_TX_FBK_LIMIT_MPDU_UP_CLEAR BIT(16)
+#define MT_TX_FBK_LIMIT_AMPDU_UP_CLEAR BIT(17)
+#define MT_TX_FBK_LIMIT_RATE_LUT BIT(18)
+
+#define MT_TX0_RF_GAIN_CORR 0x13a0
+#define MT_TX1_RF_GAIN_CORR 0x13a4
+#define MT_TX0_RF_GAIN_ATTEN 0x13a8
+
+#define MT_TX_ALC_CFG_0 0x13b0
+#define MT_TX_ALC_CFG_0_CH_INIT_0 GENMASK(5, 0)
+#define MT_TX_ALC_CFG_0_CH_INIT_1 GENMASK(13, 8)
+#define MT_TX_ALC_CFG_0_LIMIT_0 GENMASK(21, 16)
+#define MT_TX_ALC_CFG_0_LIMIT_1 GENMASK(29, 24)
+
+#define MT_TX_ALC_CFG_1 0x13b4
+#define MT_TX_ALC_CFG_1_TEMP_COMP GENMASK(5, 0)
+
+#define MT_TX_ALC_CFG_2 0x13a8
+#define MT_TX_ALC_CFG_2_TEMP_COMP GENMASK(5, 0)
+
+#define MT_TX0_BB_GAIN_ATTEN 0x13c0
+
+#define MT_TX_ALC_VGA3 0x13c8
+
+#define MT_TX_PROT_CFG6 0x13e0
+#define MT_TX_PROT_CFG7 0x13e4
+#define MT_TX_PROT_CFG8 0x13e8
+
+#define MT_PIFS_TX_CFG 0x13ec
+
+#define MT_RX_FILTR_CFG 0x1400
+
+#define MT_RX_FILTR_CFG_CRC_ERR BIT(0)
+#define MT_RX_FILTR_CFG_PHY_ERR BIT(1)
+#define MT_RX_FILTR_CFG_PROMISC BIT(2)
+#define MT_RX_FILTR_CFG_OTHER_BSS BIT(3)
+#define MT_RX_FILTR_CFG_VER_ERR BIT(4)
+#define MT_RX_FILTR_CFG_MCAST BIT(5)
+#define MT_RX_FILTR_CFG_BCAST BIT(6)
+#define MT_RX_FILTR_CFG_DUP BIT(7)
+#define MT_RX_FILTR_CFG_CFACK BIT(8)
+#define MT_RX_FILTR_CFG_CFEND BIT(9)
+#define MT_RX_FILTR_CFG_ACK BIT(10)
+#define MT_RX_FILTR_CFG_CTS BIT(11)
+#define MT_RX_FILTR_CFG_RTS BIT(12)
+#define MT_RX_FILTR_CFG_PSPOLL BIT(13)
+#define MT_RX_FILTR_CFG_BA BIT(14)
+#define MT_RX_FILTR_CFG_BAR BIT(15)
+#define MT_RX_FILTR_CFG_CTRL_RSV BIT(16)
+
+#define MT_AUTO_RSP_CFG 0x1404
+
+#define MT_AUTO_RSP_PREAMB_SHORT BIT(4)
+
+#define MT_LEGACY_BASIC_RATE 0x1408
+#define MT_HT_BASIC_RATE 0x140c
+
+#define MT_RX_PARSER_CFG 0x1418
+#define MT_RX_PARSER_RX_SET_NAV_ALL BIT(0)
+
+#define MT_EXT_CCA_CFG 0x141c
+#define MT_EXT_CCA_CFG_CCA0 GENMASK(1, 0)
+#define MT_EXT_CCA_CFG_CCA1 GENMASK(3, 2)
+#define MT_EXT_CCA_CFG_CCA2 GENMASK(5, 4)
+#define MT_EXT_CCA_CFG_CCA3 GENMASK(7, 6)
+#define MT_EXT_CCA_CFG_CCA_MASK GENMASK(11, 8)
+#define MT_EXT_CCA_CFG_ED_CCA_MASK GENMASK(15, 12)
+
+#define MT_TX_SW_CFG3 0x1478
+
+#define MT_PN_PAD_MODE 0x150c
+
+#define MT_TXOP_HLDR_ET 0x1608
+
+#define MT_PROT_AUTO_TX_CFG 0x1648
+
+#define MT_RX_STA_CNT0 0x1700
+#define MT_RX_STA_CNT1 0x1704
+#define MT_RX_STA_CNT2 0x1708
+#define MT_TX_STA_CNT0 0x170c
+#define MT_TX_STA_CNT1 0x1710
+#define MT_TX_STA_CNT2 0x1714
+
+/* Vendor driver defines content of the second word of STAT_FIFO as follows:
+ * MT_TX_STAT_FIFO_RATE GENMASK(26, 16)
+ * MT_TX_STAT_FIFO_ETXBF BIT(27)
+ * MT_TX_STAT_FIFO_SND BIT(28)
+ * MT_TX_STAT_FIFO_ITXBF BIT(29)
+ * However, tests show that b16-31 have the same layout as TXWI rate_ctl
+ * with rate set to rate at which frame was acked.
+ */
+#define MT_TX_STAT_FIFO 0x1718
+#define MT_TX_STAT_FIFO_VALID BIT(0)
+#define MT_TX_STAT_FIFO_PID_TYPE GENMASK(4, 1)
+#define MT_TX_STAT_FIFO_SUCCESS BIT(5)
+#define MT_TX_STAT_FIFO_AGGR BIT(6)
+#define MT_TX_STAT_FIFO_ACKREQ BIT(7)
+#define MT_TX_STAT_FIFO_WCID GENMASK(15, 8)
+#define MT_TX_STAT_FIFO_RATE GENMASK(31, 16)
+
+#define MT_TX_AGG_STAT 0x171c
+
+#define MT_TX_AGG_CNT_BASE0 0x1720
+
+#define MT_MPDU_DENSITY_CNT 0x1740
+
+#define MT_TX_AGG_CNT_BASE1 0x174c
+
+#define MT_TX_AGG_CNT(_id) ((_id) < 8 ? \
+ MT_TX_AGG_CNT_BASE0 + ((_id) << 2) : \
+ MT_TX_AGG_CNT_BASE1 + ((_id - 8) << 2))
+
+#define MT_TX_STAT_FIFO_EXT 0x1798
+#define MT_TX_STAT_FIFO_EXT_RETRY GENMASK(7, 0)
+
+#define MT_BBP_CORE_BASE 0x2000
+#define MT_BBP_IBI_BASE 0x2100
+#define MT_BBP_AGC_BASE 0x2300
+#define MT_BBP_TXC_BASE 0x2400
+#define MT_BBP_RXC_BASE 0x2500
+#define MT_BBP_TXO_BASE 0x2600
+#define MT_BBP_TXBE_BASE 0x2700
+#define MT_BBP_RXFE_BASE 0x2800
+#define MT_BBP_RXO_BASE 0x2900
+#define MT_BBP_DFS_BASE 0x2a00
+#define MT_BBP_TR_BASE 0x2b00
+#define MT_BBP_CAL_BASE 0x2c00
+#define MT_BBP_DSC_BASE 0x2e00
+#define MT_BBP_PFMU_BASE 0x2f00
+
+#define MT_BBP(_type, _n) (MT_BBP_##_type##_BASE + ((_n) << 2))
+
+#define MT_BBP_CORE_R1_BW GENMASK(4, 3)
+
+#define MT_BBP_AGC_R0_CTRL_CHAN GENMASK(9, 8)
+#define MT_BBP_AGC_R0_BW GENMASK(14, 12)
+
+/* AGC, R4/R5 */
+#define MT_BBP_AGC_LNA_GAIN GENMASK(21, 16)
+
+/* AGC, R8/R9 */
+#define MT_BBP_AGC_GAIN GENMASK(14, 8)
+
+#define MT_BBP_AGC20_RSSI0 GENMASK(7, 0)
+#define MT_BBP_AGC20_RSSI1 GENMASK(15, 8)
+
+#define MT_BBP_TXBE_R0_CTRL_CHAN GENMASK(1, 0)
+
+#define MT_WCID_ADDR_BASE 0x1800
+#define MT_WCID_ADDR(_n) (MT_WCID_ADDR_BASE + (_n) * 8)
+
+#define MT_SRAM_BASE 0x4000
+
+#define MT_WCID_KEY_BASE 0x8000
+#define MT_WCID_KEY(_n) (MT_WCID_KEY_BASE + (_n) * 32)
+
+#define MT_WCID_IV_BASE 0xa000
+#define MT_WCID_IV(_n) (MT_WCID_IV_BASE + (_n) * 8)
+
+#define MT_WCID_ATTR_BASE 0xa800
+#define MT_WCID_ATTR(_n) (MT_WCID_ATTR_BASE + (_n) * 4)
+
+#define MT_WCID_ATTR_PAIRWISE BIT(0)
+#define MT_WCID_ATTR_PKEY_MODE GENMASK(3, 1)
+#define MT_WCID_ATTR_BSS_IDX GENMASK(6, 4)
+#define MT_WCID_ATTR_RXWI_UDF GENMASK(9, 7)
+#define MT_WCID_ATTR_PKEY_MODE_EXT BIT(10)
+#define MT_WCID_ATTR_BSS_IDX_EXT BIT(11)
+#define MT_WCID_ATTR_WAPI_MCBC BIT(15)
+#define MT_WCID_ATTR_WAPI_KEYID GENMASK(31, 24)
+
+#define MT_SKEY_BASE_0 0xac00
+#define MT_SKEY_BASE_1 0xb400
+#define MT_SKEY_0(_bss, _idx) \
+ (MT_SKEY_BASE_0 + (4 * (_bss) + _idx) * 32)
+#define MT_SKEY_1(_bss, _idx) \
+ (MT_SKEY_BASE_1 + (4 * ((_bss) & 7) + _idx) * 32)
+#define MT_SKEY(_bss, _idx) \
+ ((_bss & 8) ? MT_SKEY_1(_bss, _idx) : MT_SKEY_0(_bss, _idx))
+
+#define MT_SKEY_MODE_BASE_0 0xb000
+#define MT_SKEY_MODE_BASE_1 0xb3f0
+#define MT_SKEY_MODE_0(_bss) \
+ (MT_SKEY_MODE_BASE_0 + ((_bss / 2) << 2))
+#define MT_SKEY_MODE_1(_bss) \
+ (MT_SKEY_MODE_BASE_1 + ((((_bss) & 7) / 2) << 2))
+#define MT_SKEY_MODE(_bss) \
+ ((_bss & 8) ? MT_SKEY_MODE_1(_bss) : MT_SKEY_MODE_0(_bss))
+#define MT_SKEY_MODE_MASK GENMASK(3, 0)
+#define MT_SKEY_MODE_SHIFT(_bss, _idx) (4 * ((_idx) + 4 * (_bss & 1)))
+
+#define MT_BEACON_BASE 0xc000
+
+#define MT_TEMP_SENSOR 0x1d000
+#define MT_TEMP_SENSOR_VAL GENMASK(6, 0)
+
+enum mt76_cipher_type {
+ MT_CIPHER_NONE,
+ MT_CIPHER_WEP40,
+ MT_CIPHER_WEP104,
+ MT_CIPHER_TKIP,
+ MT_CIPHER_AES_CCMP,
+ MT_CIPHER_CKIP40,
+ MT_CIPHER_CKIP104,
+ MT_CIPHER_CKIP128,
+ MT_CIPHER_WAPI,
+};
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/trace.c b/drivers/net/wireless/mediatek/mt7601u/trace.c
new file mode 100644
index 000000000000..8abdd3cd546d
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/trace.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+
+#ifndef __CHECKER__
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/trace.h b/drivers/net/wireless/mediatek/mt7601u/trace.h
new file mode 100644
index 000000000000..289897300ef0
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/trace.h
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#if !defined(__MT7601U_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __MT7601U_TRACE_H
+
+#include <linux/tracepoint.h>
+#include "mt7601u.h"
+#include "mac.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mt7601u
+
+#define MAXNAME 32
+#define DEV_ENTRY __array(char, wiphy_name, 32)
+#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \
+ wiphy_name(dev->hw->wiphy), MAXNAME)
+#define DEV_PR_FMT "%s "
+#define DEV_PR_ARG __entry->wiphy_name
+
+#define REG_ENTRY __field(u32, reg) __field(u32, val)
+#define REG_ASSIGN __entry->reg = reg; __entry->val = val
+#define REG_PR_FMT "%04x=%08x"
+#define REG_PR_ARG __entry->reg, __entry->val
+
+DECLARE_EVENT_CLASS(dev_reg_evt,
+ TP_PROTO(struct mt7601u_dev *dev, u32 reg, u32 val),
+ TP_ARGS(dev, reg, val),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ REG_ENTRY
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ REG_ASSIGN;
+ ),
+ TP_printk(
+ DEV_PR_FMT REG_PR_FMT,
+ DEV_PR_ARG, REG_PR_ARG
+ )
+);
+
+DEFINE_EVENT(dev_reg_evt, reg_read,
+ TP_PROTO(struct mt7601u_dev *dev, u32 reg, u32 val),
+ TP_ARGS(dev, reg, val)
+);
+
+DEFINE_EVENT(dev_reg_evt, reg_write,
+ TP_PROTO(struct mt7601u_dev *dev, u32 reg, u32 val),
+ TP_ARGS(dev, reg, val)
+);
+
+TRACE_EVENT(mt_submit_urb,
+ TP_PROTO(struct mt7601u_dev *dev, struct urb *u),
+ TP_ARGS(dev, u),
+ TP_STRUCT__entry(
+ DEV_ENTRY __field(unsigned, pipe) __field(u32, len)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->pipe = u->pipe;
+ __entry->len = u->transfer_buffer_length;
+ ),
+ TP_printk(DEV_PR_FMT "p:%08x len:%u",
+ DEV_PR_ARG, __entry->pipe, __entry->len)
+);
+
+#define trace_mt_submit_urb_sync(__dev, __pipe, __len) ({ \
+ struct urb u; \
+ u.pipe = __pipe; \
+ u.transfer_buffer_length = __len; \
+ trace_mt_submit_urb(__dev, &u); \
+})
+
+TRACE_EVENT(mt_mcu_msg_send,
+ TP_PROTO(struct mt7601u_dev *dev,
+ struct sk_buff *skb, u32 csum, bool resp),
+ TP_ARGS(dev, skb, csum, resp),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u32, info)
+ __field(u32, csum)
+ __field(bool, resp)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->info = *(u32 *)skb->data;
+ __entry->csum = csum;
+ __entry->resp = resp;
+ ),
+ TP_printk(DEV_PR_FMT "i:%08x c:%08x r:%d",
+ DEV_PR_ARG, __entry->info, __entry->csum, __entry->resp)
+);
+
+TRACE_EVENT(mt_vend_req,
+ TP_PROTO(struct mt7601u_dev *dev, unsigned pipe, u8 req, u8 req_type,
+ u16 val, u16 offset, void *buf, size_t buflen, int ret),
+ TP_ARGS(dev, pipe, req, req_type, val, offset, buf, buflen, ret),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(unsigned, pipe) __field(u8, req) __field(u8, req_type)
+ __field(u16, val) __field(u16, offset) __field(void*, buf)
+ __field(int, buflen) __field(int, ret)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->pipe = pipe;
+ __entry->req = req;
+ __entry->req_type = req_type;
+ __entry->val = val;
+ __entry->offset = offset;
+ __entry->buf = buf;
+ __entry->buflen = buflen;
+ __entry->ret = ret;
+ ),
+ TP_printk(DEV_PR_FMT
+ "%d p:%08x req:%02hhx %02hhx val:%04hx %04hx buf:%d %d",
+ DEV_PR_ARG, __entry->ret, __entry->pipe, __entry->req,
+ __entry->req_type, __entry->val, __entry->offset,
+ !!__entry->buf, __entry->buflen)
+);
+
+TRACE_EVENT(ee_read,
+ TP_PROTO(struct mt7601u_dev *dev, int offset, u16 val),
+ TP_ARGS(dev, offset, val),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(int, o) __field(u16, v)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->o = offset;
+ __entry->v = val;
+ ),
+ TP_printk(DEV_PR_FMT "%04x=%04x", DEV_PR_ARG, __entry->o, __entry->v)
+);
+
+DECLARE_EVENT_CLASS(dev_rf_reg_evt,
+ TP_PROTO(struct mt7601u_dev *dev, u8 bank, u8 reg, u8 val),
+ TP_ARGS(dev, bank, reg, val),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u8, bank)
+ __field(u8, reg)
+ __field(u8, val)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ REG_ASSIGN;
+ __entry->bank = bank;
+ ),
+ TP_printk(
+ DEV_PR_FMT "%02hhx:%02hhx=%02hhx",
+ DEV_PR_ARG, __entry->bank, __entry->reg, __entry->val
+ )
+);
+
+DEFINE_EVENT(dev_rf_reg_evt, rf_read,
+ TP_PROTO(struct mt7601u_dev *dev, u8 bank, u8 reg, u8 val),
+ TP_ARGS(dev, bank, reg, val)
+);
+
+DEFINE_EVENT(dev_rf_reg_evt, rf_write,
+ TP_PROTO(struct mt7601u_dev *dev, u8 bank, u8 reg, u8 val),
+ TP_ARGS(dev, bank, reg, val)
+);
+
+DECLARE_EVENT_CLASS(dev_bbp_reg_evt,
+ TP_PROTO(struct mt7601u_dev *dev, u8 reg, u8 val),
+ TP_ARGS(dev, reg, val),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u8, reg)
+ __field(u8, val)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ REG_ASSIGN;
+ ),
+ TP_printk(
+ DEV_PR_FMT "%02hhx=%02hhx",
+ DEV_PR_ARG, __entry->reg, __entry->val
+ )
+);
+
+DEFINE_EVENT(dev_bbp_reg_evt, bbp_read,
+ TP_PROTO(struct mt7601u_dev *dev, u8 reg, u8 val),
+ TP_ARGS(dev, reg, val)
+);
+
+DEFINE_EVENT(dev_bbp_reg_evt, bbp_write,
+ TP_PROTO(struct mt7601u_dev *dev, u8 reg, u8 val),
+ TP_ARGS(dev, reg, val)
+);
+
+DECLARE_EVENT_CLASS(dev_simple_evt,
+ TP_PROTO(struct mt7601u_dev *dev, u8 val),
+ TP_ARGS(dev, val),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u8, val)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->val = val;
+ ),
+ TP_printk(
+ DEV_PR_FMT "%02hhx", DEV_PR_ARG, __entry->val
+ )
+);
+
+DEFINE_EVENT(dev_simple_evt, temp_mode,
+ TP_PROTO(struct mt7601u_dev *dev, u8 val),
+ TP_ARGS(dev, val)
+);
+
+DEFINE_EVENT(dev_simple_evt, read_temp,
+ TP_PROTO(struct mt7601u_dev *dev, u8 val),
+ TP_ARGS(dev, val)
+);
+
+DEFINE_EVENT(dev_simple_evt, freq_cal_adjust,
+ TP_PROTO(struct mt7601u_dev *dev, u8 val),
+ TP_ARGS(dev, val)
+);
+
+TRACE_EVENT(freq_cal_offset,
+ TP_PROTO(struct mt7601u_dev *dev, u8 phy_mode, s8 freq_off),
+ TP_ARGS(dev, phy_mode, freq_off),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u8, phy_mode)
+ __field(s8, freq_off)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->phy_mode = phy_mode;
+ __entry->freq_off = freq_off;
+ ),
+ TP_printk(DEV_PR_FMT "phy:%02hhx off:%02hhx",
+ DEV_PR_ARG, __entry->phy_mode, __entry->freq_off)
+);
+
+TRACE_EVENT(mt_rx,
+ TP_PROTO(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, u32 f),
+ TP_ARGS(dev, rxwi, f),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field_struct(struct mt7601u_rxwi, rxwi)
+ __field(u32, fce_info)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->rxwi = *rxwi;
+ __entry->fce_info = f;
+ ),
+ TP_printk(DEV_PR_FMT "rxi:%08x ctl:%08x frag_sn:%04hx rate:%04hx "
+ "uknw:%02hhx z:%02hhx%02hhx%02hhx snr:%02hhx "
+ "ant:%02hhx gain:%02hhx freq_o:%02hhx "
+ "r:%08x ea:%08x fce:%08x", DEV_PR_ARG,
+ le32_to_cpu(__entry->rxwi.rxinfo),
+ le32_to_cpu(__entry->rxwi.ctl),
+ le16_to_cpu(__entry->rxwi.frag_sn),
+ le16_to_cpu(__entry->rxwi.rate),
+ __entry->rxwi.unknown,
+ __entry->rxwi.zero[0], __entry->rxwi.zero[1],
+ __entry->rxwi.zero[2],
+ __entry->rxwi.snr, __entry->rxwi.ant,
+ __entry->rxwi.gain, __entry->rxwi.freq_off,
+ __entry->rxwi.resv2, __entry->rxwi.expert_ant,
+ __entry->fce_info)
+);
+
+TRACE_EVENT(mt_tx,
+ TP_PROTO(struct mt7601u_dev *dev, struct sk_buff *skb,
+ struct mt76_sta *sta, struct mt76_txwi *h),
+ TP_ARGS(dev, skb, sta, h),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field_struct(struct mt76_txwi, h)
+ __field(struct sk_buff *, skb)
+ __field(struct mt76_sta *, sta)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->h = *h;
+ __entry->skb = skb;
+ __entry->sta = sta;
+ ),
+ TP_printk(DEV_PR_FMT "skb:%p sta:%p flg:%04hx rate_ctl:%04hx "
+ "ack:%02hhx wcid:%02hhx len_ctl:%05hx", DEV_PR_ARG,
+ __entry->skb, __entry->sta,
+ le16_to_cpu(__entry->h.flags),
+ le16_to_cpu(__entry->h.rate_ctl),
+ __entry->h.ack_ctl, __entry->h.wcid,
+ le16_to_cpu(__entry->h.len_ctl))
+);
+
+TRACE_EVENT(mt_tx_dma_done,
+ TP_PROTO(struct mt7601u_dev *dev, struct sk_buff *skb),
+ TP_ARGS(dev, skb),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(struct sk_buff *, skb)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->skb = skb;
+ ),
+ TP_printk(DEV_PR_FMT "%p", DEV_PR_ARG, __entry->skb)
+);
+
+TRACE_EVENT(mt_tx_status_cleaned,
+ TP_PROTO(struct mt7601u_dev *dev, int cleaned),
+ TP_ARGS(dev, cleaned),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(int, cleaned)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->cleaned = cleaned;
+ ),
+ TP_printk(DEV_PR_FMT "%d", DEV_PR_ARG, __entry->cleaned)
+);
+
+TRACE_EVENT(mt_tx_status,
+ TP_PROTO(struct mt7601u_dev *dev, u32 stat1, u32 stat2),
+ TP_ARGS(dev, stat1, stat2),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u32, stat1) __field(u32, stat2)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->stat1 = stat1;
+ __entry->stat2 = stat2;
+ ),
+ TP_printk(DEV_PR_FMT "%08x %08x",
+ DEV_PR_ARG, __entry->stat1, __entry->stat2)
+);
+
+TRACE_EVENT(mt_rx_dma_aggr,
+ TP_PROTO(struct mt7601u_dev *dev, int cnt, bool paged),
+ TP_ARGS(dev, cnt, paged),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u8, cnt)
+ __field(bool, paged)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->cnt = cnt;
+ __entry->paged = paged;
+ ),
+ TP_printk(DEV_PR_FMT "cnt:%d paged:%d",
+ DEV_PR_ARG, __entry->cnt, __entry->paged)
+);
+
+DEFINE_EVENT(dev_simple_evt, set_key,
+ TP_PROTO(struct mt7601u_dev *dev, u8 val),
+ TP_ARGS(dev, val)
+);
+
+TRACE_EVENT(set_shared_key,
+ TP_PROTO(struct mt7601u_dev *dev, u8 vid, u8 key),
+ TP_ARGS(dev, vid, key),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u8, vid)
+ __field(u8, key)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->vid = vid;
+ __entry->key = key;
+ ),
+ TP_printk(DEV_PR_FMT "phy:%02hhx off:%02hhx",
+ DEV_PR_ARG, __entry->vid, __entry->key)
+);
+
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>
diff --git a/drivers/net/wireless/mediatek/mt7601u/tx.c b/drivers/net/wireless/mediatek/mt7601u/tx.c
new file mode 100644
index 000000000000..0be2080ceab3
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/tx.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#include "mt7601u.h"
+#include "trace.h"
+
+enum mt76_txq_id {
+ MT_TXQ_VO = IEEE80211_AC_VO,
+ MT_TXQ_VI = IEEE80211_AC_VI,
+ MT_TXQ_BE = IEEE80211_AC_BE,
+ MT_TXQ_BK = IEEE80211_AC_BK,
+ MT_TXQ_PSD,
+ MT_TXQ_MCU,
+ __MT_TXQ_MAX
+};
+
+/* Hardware uses mirrored order of queues with Q0 having the highest priority */
+static u8 q2hwq(u8 q)
+{
+ return q ^ 0x3;
+}
+
+/* Take mac80211 Q id from the skb and translate it to hardware Q id */
+static u8 skb2q(struct sk_buff *skb)
+{
+ int qid = skb_get_queue_mapping(skb);
+
+ if (WARN_ON(qid >= MT_TXQ_PSD)) {
+ qid = MT_TXQ_BE;
+ skb_set_queue_mapping(skb, qid);
+ }
+
+ return q2hwq(qid);
+}
+
+/* Note: TX retry reporting is a bit broken.
+ * Retries are reported only once per AMPDU and often come a frame early
+ * i.e. they are reported in the last status preceding the AMPDU. Apart
+ * from the fact that it's hard to know the length of the AMPDU (which is
+ * required to know to how many consecutive frames retries should be
+ * applied), if status comes early on full FIFO it gets lost and retries
+ * of the whole AMPDU become invisible.
+ * As a work-around encode the desired rate in PKT_ID of TX descriptor
+ * and based on that guess the retries (every rate is tried once).
+ * Only downside here is that for MCS0 we have to rely solely on
+ * transmission failures as no retries can ever be reported.
+ * Not having to read EXT_FIFO has a nice effect of doubling the number
+ * of reports which can be fetched.
+ * Also the vendor driver never uses the EXT_FIFO register so it may be
+ * undertested.
+ */
+static u8 mt7601u_tx_pktid_enc(struct mt7601u_dev *dev, u8 rate, bool is_probe)
+{
+ u8 encoded = (rate + 1) + is_probe * 8;
+
+ /* Because PKT_ID 0 disables status reporting only 15 values are
+ * available but 16 are needed (8 MCS * 2 for encoding is_probe)
+ * - we need to cram together two rates. MCS0 and MCS7 with is_probe
+ * share PKT_ID 9.
+ */
+ if (is_probe && rate == 7)
+ return encoded - 7;
+
+ return encoded;
+}
+
+static void
+mt7601u_tx_pktid_dec(struct mt7601u_dev *dev, struct mt76_tx_status *stat)
+{
+ u8 req_rate = stat->pktid;
+ u8 eff_rate = stat->rate & 0x7;
+
+ req_rate -= 1;
+
+ if (req_rate > 7) {
+ stat->is_probe = true;
+ req_rate -= 8;
+
+ /* Decide between MCS0 and MCS7 which share pktid 9 */
+ if (!req_rate && eff_rate)
+ req_rate = 7;
+ }
+
+ stat->retry = req_rate - eff_rate;
+}
+
+static void mt7601u_tx_skb_remove_dma_overhead(struct sk_buff *skb,
+ struct ieee80211_tx_info *info)
+{
+ int pkt_len = (unsigned long)info->status.status_driver_data[0];
+
+ skb_pull(skb, sizeof(struct mt76_txwi) + 4);
+ if (ieee80211_get_hdrlen_from_skb(skb) % 4)
+ mt76_remove_hdr_pad(skb);
+
+ skb_trim(skb, pkt_len);
+}
+
+void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ mt7601u_tx_skb_remove_dma_overhead(skb, info);
+
+ ieee80211_tx_info_clear_status(info);
+ info->status.rates[0].idx = -1;
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ ieee80211_tx_status(dev->hw, skb);
+}
+
+static int mt7601u_skb_rooms(struct mt7601u_dev *dev, struct sk_buff *skb)
+{
+ int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
+ u32 need_head;
+
+ need_head = sizeof(struct mt76_txwi) + 4;
+ if (hdr_len % 4)
+ need_head += 2;
+
+ return skb_cow(skb, need_head);
+}
+
+static struct mt76_txwi *
+mt7601u_push_txwi(struct mt7601u_dev *dev, struct sk_buff *skb,
+ struct ieee80211_sta *sta, struct mt76_wcid *wcid,
+ int pkt_len)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_tx_rate *rate = &info->control.rates[0];
+ struct mt76_txwi *txwi;
+ unsigned long flags;
+ bool is_probe;
+ u32 pkt_id;
+ u16 rate_ctl;
+ u8 nss;
+
+ txwi = (struct mt76_txwi *)skb_push(skb, sizeof(struct mt76_txwi));
+ memset(txwi, 0, sizeof(*txwi));
+
+ if (!wcid->tx_rate_set)
+ ieee80211_get_tx_rates(info->control.vif, sta, skb,
+ info->control.rates, 1);
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (rate->idx < 0 || !rate->count)
+ rate_ctl = wcid->tx_rate;
+ else
+ rate_ctl = mt76_mac_tx_rate_val(dev, rate, &nss);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ txwi->rate_ctl = cpu_to_le16(rate_ctl);
+
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+ txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ;
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+ txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ;
+
+ if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) {
+ u8 ba_size = IEEE80211_MIN_AMPDU_BUF;
+
+ ba_size <<= sta->ht_cap.ampdu_factor;
+ ba_size = min_t(int, 63, ba_size);
+ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
+ ba_size = 0;
+ txwi->ack_ctl |= MT76_SET(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size);
+
+ txwi->flags = cpu_to_le16(MT_TXWI_FLAGS_AMPDU |
+ MT76_SET(MT_TXWI_FLAGS_MPDU_DENSITY,
+ sta->ht_cap.ampdu_density));
+ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
+ txwi->flags = 0;
+ }
+
+ txwi->wcid = wcid->idx;
+
+ is_probe = !!(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
+ pkt_id = mt7601u_tx_pktid_enc(dev, rate_ctl & 0x7, is_probe);
+ pkt_len |= MT76_SET(MT_TXWI_LEN_PKTID, pkt_id);
+ txwi->len_ctl = cpu_to_le16(pkt_len);
+
+ return txwi;
+}
+
+void mt7601u_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct mt7601u_dev *dev = hw->priv;
+ struct ieee80211_vif *vif = info->control.vif;
+ struct ieee80211_sta *sta = control->sta;
+ struct mt76_sta *msta = NULL;
+ struct mt76_wcid *wcid = dev->mon_wcid;
+ struct mt76_txwi *txwi;
+ int pkt_len = skb->len;
+ int hw_q = skb2q(skb);
+
+ BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1);
+ info->status.status_driver_data[0] = (void *)(unsigned long)pkt_len;
+
+ if (mt7601u_skb_rooms(dev, skb) || mt76_insert_hdr_pad(skb)) {
+ ieee80211_free_txskb(dev->hw, skb);
+ return;
+ }
+
+ if (sta) {
+ msta = (struct mt76_sta *) sta->drv_priv;
+ wcid = &msta->wcid;
+ } else if (vif) {
+ struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
+
+ wcid = &mvif->group_wcid;
+ }
+
+ txwi = mt7601u_push_txwi(dev, skb, sta, wcid, pkt_len);
+
+ if (mt7601u_dma_enqueue_tx(dev, skb, wcid, hw_q))
+ return;
+
+ trace_mt_tx(dev, skb, msta, txwi);
+}
+
+void mt7601u_tx_stat(struct work_struct *work)
+{
+ struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev,
+ stat_work.work);
+ struct mt76_tx_status stat;
+ unsigned long flags;
+ int cleaned = 0;
+
+ while (!test_bit(MT7601U_STATE_REMOVED, &dev->state)) {
+ stat = mt7601u_mac_fetch_tx_status(dev);
+ if (!stat.valid)
+ break;
+
+ mt7601u_tx_pktid_dec(dev, &stat);
+ mt76_send_tx_status(dev, &stat);
+
+ cleaned++;
+ }
+ trace_mt_tx_status_cleaned(dev, cleaned);
+
+ spin_lock_irqsave(&dev->tx_lock, flags);
+ if (cleaned)
+ queue_delayed_work(dev->stat_wq, &dev->stat_work,
+ msecs_to_jiffies(10));
+ else if (test_and_clear_bit(MT7601U_STATE_MORE_STATS, &dev->state))
+ queue_delayed_work(dev->stat_wq, &dev->stat_work,
+ msecs_to_jiffies(20));
+ else
+ clear_bit(MT7601U_STATE_READING_STATS, &dev->state);
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
+}
+
+int mt7601u_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u16 queue, const struct ieee80211_tx_queue_params *params)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ u8 cw_min = 5, cw_max = 10, hw_q = q2hwq(queue);
+ u32 val;
+
+ /* TODO: should we do funny things with the parameters?
+ * See what mt7601u_set_default_edca() used to do in init.c.
+ */
+
+ if (params->cw_min)
+ cw_min = fls(params->cw_min);
+ if (params->cw_max)
+ cw_max = fls(params->cw_max);
+
+ WARN_ON(params->txop > 0xff);
+ WARN_ON(params->aifs > 0xf);
+ WARN_ON(cw_min > 0xf);
+ WARN_ON(cw_max > 0xf);
+
+ val = MT76_SET(MT_EDCA_CFG_AIFSN, params->aifs) |
+ MT76_SET(MT_EDCA_CFG_CWMIN, cw_min) |
+ MT76_SET(MT_EDCA_CFG_CWMAX, cw_max);
+ /* TODO: based on user-controlled EnableTxBurst var vendor drv sets
+ * a really long txop on AC0 (see connect.c:2009) but only on
+ * connect? When not connected should be 0.
+ */
+ if (!hw_q)
+ val |= 0x60;
+ else
+ val |= MT76_SET(MT_EDCA_CFG_TXOP, params->txop);
+ mt76_wr(dev, MT_EDCA_CFG_AC(hw_q), val);
+
+ val = mt76_rr(dev, MT_WMM_TXOP(hw_q));
+ val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(hw_q));
+ val |= params->txop << MT_WMM_TXOP_SHIFT(hw_q);
+ mt76_wr(dev, MT_WMM_TXOP(hw_q), val);
+
+ val = mt76_rr(dev, MT_WMM_AIFSN);
+ val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(hw_q));
+ val |= params->aifs << MT_WMM_AIFSN_SHIFT(hw_q);
+ mt76_wr(dev, MT_WMM_AIFSN, val);
+
+ val = mt76_rr(dev, MT_WMM_CWMIN);
+ val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(hw_q));
+ val |= cw_min << MT_WMM_CWMIN_SHIFT(hw_q);
+ mt76_wr(dev, MT_WMM_CWMIN, val);
+
+ val = mt76_rr(dev, MT_WMM_CWMAX);
+ val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(hw_q));
+ val |= cw_max << MT_WMM_CWMAX_SHIFT(hw_q);
+ mt76_wr(dev, MT_WMM_CWMAX, val);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c
new file mode 100644
index 000000000000..54dba4001865
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/usb.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "mt7601u.h"
+#include "usb.h"
+#include "trace.h"
+
+static struct usb_device_id mt7601u_device_table[] = {
+ { USB_DEVICE(0x0b05, 0x17d3) },
+ { USB_DEVICE(0x0e8d, 0x760a) },
+ { USB_DEVICE(0x0e8d, 0x760b) },
+ { USB_DEVICE(0x13d3, 0x3431) },
+ { USB_DEVICE(0x13d3, 0x3434) },
+ { USB_DEVICE(0x148f, 0x7601) },
+ { USB_DEVICE(0x148f, 0x760a) },
+ { USB_DEVICE(0x148f, 0x760b) },
+ { USB_DEVICE(0x148f, 0x760c) },
+ { USB_DEVICE(0x148f, 0x760d) },
+ { USB_DEVICE(0x2001, 0x3d04) },
+ { USB_DEVICE(0x2717, 0x4106) },
+ { USB_DEVICE(0x2955, 0x0001) },
+ { USB_DEVICE(0x2955, 0x1001) },
+ { USB_DEVICE(0x2a5f, 0x1000) },
+ { USB_DEVICE(0x7392, 0x7710) },
+ { 0, }
+};
+
+bool mt7601u_usb_alloc_buf(struct mt7601u_dev *dev, size_t len,
+ struct mt7601u_dma_buf *buf)
+{
+ struct usb_device *usb_dev = mt7601u_to_usb_dev(dev);
+
+ buf->len = len;
+ buf->urb = usb_alloc_urb(0, GFP_KERNEL);
+ buf->buf = usb_alloc_coherent(usb_dev, buf->len, GFP_KERNEL, &buf->dma);
+
+ return !buf->urb || !buf->buf;
+}
+
+void mt7601u_usb_free_buf(struct mt7601u_dev *dev, struct mt7601u_dma_buf *buf)
+{
+ struct usb_device *usb_dev = mt7601u_to_usb_dev(dev);
+
+ usb_free_coherent(usb_dev, buf->len, buf->buf, buf->dma);
+ usb_free_urb(buf->urb);
+}
+
+int mt7601u_usb_submit_buf(struct mt7601u_dev *dev, int dir, int ep_idx,
+ struct mt7601u_dma_buf *buf, gfp_t gfp,
+ usb_complete_t complete_fn, void *context)
+{
+ struct usb_device *usb_dev = mt7601u_to_usb_dev(dev);
+ unsigned pipe;
+ int ret;
+
+ if (dir == USB_DIR_IN)
+ pipe = usb_rcvbulkpipe(usb_dev, dev->in_eps[ep_idx]);
+ else
+ pipe = usb_sndbulkpipe(usb_dev, dev->out_eps[ep_idx]);
+
+ usb_fill_bulk_urb(buf->urb, usb_dev, pipe, buf->buf, buf->len,
+ complete_fn, context);
+ buf->urb->transfer_dma = buf->dma;
+ buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ trace_mt_submit_urb(dev, buf->urb);
+ ret = usb_submit_urb(buf->urb, gfp);
+ if (ret)
+ dev_err(dev->dev, "Error: submit URB dir:%d ep:%d failed:%d\n",
+ dir, ep_idx, ret);
+ return ret;
+}
+
+void mt7601u_complete_urb(struct urb *urb)
+{
+ struct completion *cmpl = urb->context;
+
+ complete(cmpl);
+}
+
+static int
+__mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req,
+ const u8 direction, const u16 val, const u16 offset,
+ void *buf, const size_t buflen)
+{
+ int i, ret;
+ struct usb_device *usb_dev = mt7601u_to_usb_dev(dev);
+ const u8 req_type = direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ const unsigned int pipe = (direction == USB_DIR_IN) ?
+ usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0);
+
+ for (i = 0; i < MT_VEND_REQ_MAX_RETRY; i++) {
+ ret = usb_control_msg(usb_dev, pipe, req, req_type,
+ val, offset, buf, buflen,
+ MT_VEND_REQ_TOUT_MS);
+ trace_mt_vend_req(dev, pipe, req, req_type, val, offset,
+ buf, buflen, ret);
+
+ if (ret >= 0 || ret == -ENODEV)
+ return ret;
+
+ msleep(5);
+ }
+
+ dev_err(dev->dev, "Vendor request req:%02x off:%04x failed:%d\n",
+ req, offset, ret);
+
+ return ret;
+}
+
+int
+mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req,
+ const u8 direction, const u16 val, const u16 offset,
+ void *buf, const size_t buflen)
+{
+ int ret;
+
+ mutex_lock(&dev->vendor_req_mutex);
+
+ ret = __mt7601u_vendor_request(dev, req, direction, val, offset,
+ buf, buflen);
+ if (ret == -ENODEV)
+ set_bit(MT7601U_STATE_REMOVED, &dev->state);
+
+ mutex_unlock(&dev->vendor_req_mutex);
+
+ return ret;
+}
+
+void mt7601u_vendor_reset(struct mt7601u_dev *dev)
+{
+ mt7601u_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT,
+ MT_VEND_DEV_MODE_RESET, 0, NULL, 0);
+}
+
+u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset)
+{
+ int ret;
+ __le32 reg;
+ u32 val;
+
+ WARN_ONCE(offset > USHRT_MAX, "read high off:%08x", offset);
+
+ ret = mt7601u_vendor_request(dev, MT_VEND_MULTI_READ, USB_DIR_IN,
+ 0, offset, &reg, sizeof(reg));
+ val = le32_to_cpu(reg);
+ if (ret > 0 && ret != sizeof(reg)) {
+ dev_err(dev->dev, "Error: wrong size read:%d off:%08x\n",
+ ret, offset);
+ val = ~0;
+ }
+
+ trace_reg_read(dev, offset, val);
+ return val;
+}
+
+int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req,
+ const u16 offset, const u32 val)
+{
+ int ret;
+
+ ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT,
+ val & 0xffff, offset, NULL, 0);
+ if (ret)
+ return ret;
+ return mt7601u_vendor_request(dev, req, USB_DIR_OUT,
+ val >> 16, offset + 2, NULL, 0);
+}
+
+void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val)
+{
+ WARN_ONCE(offset > USHRT_MAX, "write high off:%08x", offset);
+
+ mt7601u_vendor_single_wr(dev, MT_VEND_WRITE, offset, val);
+ trace_reg_write(dev, offset, val);
+}
+
+u32 mt7601u_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val)
+{
+ val |= mt7601u_rr(dev, offset) & ~mask;
+ mt7601u_wr(dev, offset, val);
+ return val;
+}
+
+u32 mt7601u_rmc(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val)
+{
+ u32 reg = mt7601u_rr(dev, offset);
+
+ val |= reg & ~mask;
+ if (reg != val)
+ mt7601u_wr(dev, offset, val);
+ return val;
+}
+
+void mt7601u_wr_copy(struct mt7601u_dev *dev, u32 offset,
+ const void *data, int len)
+{
+ WARN_ONCE(offset & 3, "unaligned write copy off:%08x", offset);
+ WARN_ONCE(len & 3, "short write copy off:%08x", offset);
+
+ mt7601u_burst_write_regs(dev, offset, data, len / 4);
+}
+
+void mt7601u_addr_wr(struct mt7601u_dev *dev, const u32 offset, const u8 *addr)
+{
+ mt7601u_wr(dev, offset, get_unaligned_le32(addr));
+ mt7601u_wr(dev, offset + 4, addr[4] | addr[5] << 8);
+}
+
+static int mt7601u_assign_pipes(struct usb_interface *usb_intf,
+ struct mt7601u_dev *dev)
+{
+ struct usb_endpoint_descriptor *ep_desc;
+ struct usb_host_interface *intf_desc = usb_intf->cur_altsetting;
+ unsigned i, ep_i = 0, ep_o = 0;
+
+ BUILD_BUG_ON(sizeof(dev->in_eps) < __MT_EP_IN_MAX);
+ BUILD_BUG_ON(sizeof(dev->out_eps) < __MT_EP_OUT_MAX);
+
+ for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
+ ep_desc = &intf_desc->endpoint[i].desc;
+
+ if (usb_endpoint_is_bulk_in(ep_desc) &&
+ ep_i++ < __MT_EP_IN_MAX) {
+ dev->in_eps[ep_i - 1] = usb_endpoint_num(ep_desc);
+ dev->in_max_packet = usb_endpoint_maxp(ep_desc);
+ /* Note: this is ignored by usb sub-system but vendor
+ * code does it. We can drop this at some point.
+ */
+ dev->in_eps[ep_i - 1] |= USB_DIR_IN;
+ } else if (usb_endpoint_is_bulk_out(ep_desc) &&
+ ep_o++ < __MT_EP_OUT_MAX) {
+ dev->out_eps[ep_o - 1] = usb_endpoint_num(ep_desc);
+ dev->out_max_packet = usb_endpoint_maxp(ep_desc);
+ }
+ }
+
+ if (ep_i != __MT_EP_IN_MAX || ep_o != __MT_EP_OUT_MAX) {
+ dev_err(dev->dev, "Error: wrong pipe number in:%d out:%d\n",
+ ep_i, ep_o);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mt7601u_probe(struct usb_interface *usb_intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *usb_dev = interface_to_usbdev(usb_intf);
+ struct mt7601u_dev *dev;
+ u32 asic_rev, mac_rev;
+ int ret;
+
+ dev = mt7601u_alloc_device(&usb_intf->dev);
+ if (!dev)
+ return -ENOMEM;
+
+ usb_dev = usb_get_dev(usb_dev);
+ usb_reset_device(usb_dev);
+
+ usb_set_intfdata(usb_intf, dev);
+
+ ret = mt7601u_assign_pipes(usb_intf, dev);
+ if (ret)
+ goto err;
+ ret = mt7601u_wait_asic_ready(dev);
+ if (ret)
+ goto err;
+
+ asic_rev = mt7601u_rr(dev, MT_ASIC_VERSION);
+ mac_rev = mt7601u_rr(dev, MT_MAC_CSR0);
+ dev_info(dev->dev, "ASIC revision: %08x MAC revision: %08x\n",
+ asic_rev, mac_rev);
+
+ /* Note: vendor driver skips this check for MT7601U */
+ if (!(mt7601u_rr(dev, MT_EFUSE_CTRL) & MT_EFUSE_CTRL_SEL))
+ dev_warn(dev->dev, "Warning: eFUSE not present\n");
+
+ ret = mt7601u_init_hardware(dev);
+ if (ret)
+ goto err;
+ ret = mt7601u_register_device(dev);
+ if (ret)
+ goto err_hw;
+
+ set_bit(MT7601U_STATE_INITIALIZED, &dev->state);
+
+ return 0;
+err_hw:
+ mt7601u_cleanup(dev);
+err:
+ usb_set_intfdata(usb_intf, NULL);
+ usb_put_dev(interface_to_usbdev(usb_intf));
+
+ destroy_workqueue(dev->stat_wq);
+ ieee80211_free_hw(dev->hw);
+ return ret;
+}
+
+static void mt7601u_disconnect(struct usb_interface *usb_intf)
+{
+ struct mt7601u_dev *dev = usb_get_intfdata(usb_intf);
+
+ ieee80211_unregister_hw(dev->hw);
+ mt7601u_cleanup(dev);
+
+ usb_set_intfdata(usb_intf, NULL);
+ usb_put_dev(interface_to_usbdev(usb_intf));
+
+ destroy_workqueue(dev->stat_wq);
+ ieee80211_free_hw(dev->hw);
+}
+
+static int mt7601u_suspend(struct usb_interface *usb_intf, pm_message_t state)
+{
+ struct mt7601u_dev *dev = usb_get_intfdata(usb_intf);
+
+ mt7601u_cleanup(dev);
+
+ return 0;
+}
+
+static int mt7601u_resume(struct usb_interface *usb_intf)
+{
+ struct mt7601u_dev *dev = usb_get_intfdata(usb_intf);
+ int ret;
+
+ ret = mt7601u_init_hardware(dev);
+ if (ret)
+ return ret;
+
+ set_bit(MT7601U_STATE_INITIALIZED, &dev->state);
+
+ return 0;
+}
+
+MODULE_DEVICE_TABLE(usb, mt7601u_device_table);
+MODULE_FIRMWARE(MT7601U_FIRMWARE);
+MODULE_LICENSE("GPL");
+
+static struct usb_driver mt7601u_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = mt7601u_device_table,
+ .probe = mt7601u_probe,
+ .disconnect = mt7601u_disconnect,
+ .suspend = mt7601u_suspend,
+ .resume = mt7601u_resume,
+ .reset_resume = mt7601u_resume,
+ .soft_unbind = 1,
+ .disable_hub_initiated_lpm = 1,
+};
+module_usb_driver(mt7601u_driver);
diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.h b/drivers/net/wireless/mediatek/mt7601u/usb.h
new file mode 100644
index 000000000000..49e188fa3798
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/usb.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * 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.
+ */
+
+#ifndef __MT7601U_USB_H
+#define __MT7601U_USB_H
+
+#include "mt7601u.h"
+
+#define MT7601U_FIRMWARE "mt7601u.bin"
+
+#define MT_VEND_REQ_MAX_RETRY 10
+#define MT_VEND_REQ_TOUT_MS 300
+
+#define MT_VEND_DEV_MODE_RESET 1
+
+enum mt_vendor_req {
+ MT_VEND_DEV_MODE = 1,
+ MT_VEND_WRITE = 2,
+ MT_VEND_MULTI_READ = 7,
+ MT_VEND_WRITE_FCE = 0x42,
+};
+
+enum mt_usb_ep_in {
+ MT_EP_IN_PKT_RX,
+ MT_EP_IN_CMD_RESP,
+ __MT_EP_IN_MAX,
+};
+
+enum mt_usb_ep_out {
+ MT_EP_OUT_INBAND_CMD,
+ MT_EP_OUT_AC_BK,
+ MT_EP_OUT_AC_BE,
+ MT_EP_OUT_AC_VI,
+ MT_EP_OUT_AC_VO,
+ MT_EP_OUT_HCCA,
+ __MT_EP_OUT_MAX,
+};
+
+static inline struct usb_device *mt7601u_to_usb_dev(struct mt7601u_dev *mt7601u)
+{
+ return interface_to_usbdev(to_usb_interface(mt7601u->dev));
+}
+
+static inline bool mt7601u_urb_has_error(struct urb *urb)
+{
+ return urb->status &&
+ urb->status != -ENOENT &&
+ urb->status != -ECONNRESET &&
+ urb->status != -ESHUTDOWN;
+}
+
+bool mt7601u_usb_alloc_buf(struct mt7601u_dev *dev, size_t len,
+ struct mt7601u_dma_buf *buf);
+void mt7601u_usb_free_buf(struct mt7601u_dev *dev, struct mt7601u_dma_buf *buf);
+int mt7601u_usb_submit_buf(struct mt7601u_dev *dev, int dir, int ep_idx,
+ struct mt7601u_dma_buf *buf, gfp_t gfp,
+ usb_complete_t complete_fn, void *context);
+void mt7601u_complete_urb(struct urb *urb);
+
+int mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req,
+ const u8 direction, const u16 val, const u16 offset,
+ void *buf, const size_t buflen);
+void mt7601u_vendor_reset(struct mt7601u_dev *dev);
+int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req,
+ const u16 offset, const u32 val);
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/util.c b/drivers/net/wireless/mediatek/mt7601u/util.c
new file mode 100644
index 000000000000..7c1787c1ddcd
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/util.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ *
+ * 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.
+ */
+
+#include "mt7601u.h"
+
+void mt76_remove_hdr_pad(struct sk_buff *skb)
+{
+ int len = ieee80211_get_hdrlen_from_skb(skb);
+
+ memmove(skb->data + 2, skb->data, len);
+ skb_pull(skb, 2);
+}
+
+int mt76_insert_hdr_pad(struct sk_buff *skb)
+{
+ int len = ieee80211_get_hdrlen_from_skb(skb);
+ int ret;
+
+ if (len % 4 == 0)
+ return 0;
+
+ ret = skb_cow(skb, 2);
+ if (ret)
+ return ret;
+
+ skb_push(skb, 2);
+ memmove(skb->data, skb->data + 2, len);
+
+ skb->data[len] = 0;
+ skb->data[len + 1] = 0;
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/util.h b/drivers/net/wireless/mediatek/mt7601u/util.h
new file mode 100644
index 000000000000..b89140bf1210
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/util.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as 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.
+ */
+
+#ifndef __MT76_UTIL_H
+#define __MT76_UTIL_H
+
+/*
+ * Power of two check, this will check
+ * if the mask that has been given contains and contiguous set of bits.
+ * Note that we cannot use the is_power_of_2() function since this
+ * check must be done at compile-time.
+ */
+#define is_power_of_two(x) ( !((x) & ((x)-1)) )
+#define low_bit_mask(x) ( ((x)-1) & ~(x) )
+#define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x))
+
+/*
+ * 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.
+ */
+#define compile_ffs2(__x) \
+ __builtin_choose_expr(((__x) & 0x1), 0, 1)
+
+#define compile_ffs4(__x) \
+ __builtin_choose_expr(((__x) & 0x3), \
+ (compile_ffs2((__x))), \
+ (compile_ffs2((__x) >> 2) + 2))
+
+#define compile_ffs8(__x) \
+ __builtin_choose_expr(((__x) & 0xf), \
+ (compile_ffs4((__x))), \
+ (compile_ffs4((__x) >> 4) + 4))
+
+#define compile_ffs16(__x) \
+ __builtin_choose_expr(((__x) & 0xff), \
+ (compile_ffs8((__x))), \
+ (compile_ffs8((__x) >> 8) + 8))
+
+#define compile_ffs32(__x) \
+ __builtin_choose_expr(((__x) & 0xffff), \
+ (compile_ffs16((__x))), \
+ (compile_ffs16((__x) >> 16) + 16))
+
+/*
+ * This macro will check the requirements for the FIELD{8,16,32} macros
+ * The mask should be a constant non-zero contiguous set of bits which
+ * does not exceed the given typelimit.
+ */
+#define FIELD_CHECK(__mask) \
+ BUILD_BUG_ON(!(__mask) || !is_valid_mask(__mask))
+
+#define MT76_SET(_mask, _val) \
+ ({ \
+ FIELD_CHECK(_mask); \
+ (((u32) (_val)) << compile_ffs32(_mask)) & _mask; \
+ })
+
+#define MT76_GET(_mask, _val) \
+ ({ \
+ FIELD_CHECK(_mask); \
+ (u32) (((_val) & _mask) >> compile_ffs32(_mask)); \
+ })
+
+#endif
diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c
index 3ab87a855122..71a1b580796f 100644
--- a/drivers/net/wireless/mwifiex/11h.c
+++ b/drivers/net/wireless/mwifiex/11h.c
@@ -134,8 +134,8 @@ void mwifiex_dfs_cac_work_queue(struct work_struct *work)
chandef = priv->dfs_chandef;
if (priv->wdev.cac_started) {
- dev_dbg(priv->adapter->dev,
- "CAC timer finished; No radar detected\n");
+ mwifiex_dbg(priv->adapter, MSG,
+ "CAC timer finished; No radar detected\n");
cfg80211_cac_event(priv->netdev, &chandef,
NL80211_RADAR_CAC_FINISHED,
GFP_KERNEL);
@@ -161,21 +161,40 @@ int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv,
cr_req->chan_desc.chan_width = radar_params->chandef->width;
cr_req->msec_dwell_time = cpu_to_le32(radar_params->cac_time_ms);
- dev_dbg(priv->adapter->dev,
- "11h: issuing DFS Radar check for channel=%d\n",
- radar_params->chandef->chan->hw_value);
+ if (radar_params->cac_time_ms)
+ mwifiex_dbg(priv->adapter, MSG,
+ "11h: issuing DFS Radar check for channel=%d\n",
+ radar_params->chandef->chan->hw_value);
+ else
+ mwifiex_dbg(priv->adapter, MSG, "cancelling CAC\n");
return 0;
}
+int mwifiex_stop_radar_detection(struct mwifiex_private *priv,
+ struct cfg80211_chan_def *chandef)
+{
+ struct mwifiex_radar_params radar_params;
+
+ memset(&radar_params, 0, sizeof(struct mwifiex_radar_params));
+ radar_params.chandef = chandef;
+ radar_params.cac_time_ms = 0;
+
+ return mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST,
+ HostCmd_ACT_GEN_SET, 0, &radar_params, true);
+}
+
/* This function is to abort ongoing CAC upon stopping AP operations
* or during unload.
*/
void mwifiex_abort_cac(struct mwifiex_private *priv)
{
if (priv->wdev.cac_started) {
- dev_dbg(priv->adapter->dev,
- "Aborting delayed work for CAC.\n");
+ if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef))
+ mwifiex_dbg(priv->adapter, ERROR,
+ "failed to stop CAC in FW\n");
+ mwifiex_dbg(priv->adapter, MSG,
+ "Aborting delayed work for CAC.\n");
cancel_delayed_work_sync(&priv->dfs_cac_work);
cfg80211_cac_event(priv->netdev, &priv->dfs_chandef,
NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
@@ -199,7 +218,8 @@ int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv,
sizeof(u32));
if (le32_to_cpu(rpt_event->result) != HostCmd_RESULT_OK) {
- dev_err(priv->adapter->dev, "Error in channel report event\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Error in channel report event\n");
return -1;
}
@@ -212,8 +232,8 @@ int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv,
switch (le16_to_cpu(rpt->header.type)) {
case TLV_TYPE_CHANRPT_11H_BASIC:
if (rpt->map.radar) {
- dev_notice(priv->adapter->dev,
- "RADAR Detected on channel %d!\n",
+ mwifiex_dbg(priv->adapter, MSG,
+ "RADAR Detected on channel %d!\n",
priv->dfs_chandef.chan->hw_value);
cancel_delayed_work_sync(&priv->dfs_cac_work);
cfg80211_cac_event(priv->netdev,
@@ -242,16 +262,20 @@ int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
rdr_event = (void *)(skb->data + sizeof(u32));
if (le32_to_cpu(rdr_event->passed)) {
- dev_notice(priv->adapter->dev,
- "radar detected; indicating kernel\n");
+ mwifiex_dbg(priv->adapter, MSG,
+ "radar detected; indicating kernel\n");
+ if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef))
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to stop CAC in FW\n");
cfg80211_radar_event(priv->adapter->wiphy, &priv->dfs_chandef,
GFP_KERNEL);
- dev_dbg(priv->adapter->dev, "regdomain: %d\n",
- rdr_event->reg_domain);
- dev_dbg(priv->adapter->dev, "radar detection type: %d\n",
- rdr_event->det_type);
+ mwifiex_dbg(priv->adapter, MSG, "regdomain: %d\n",
+ rdr_event->reg_domain);
+ mwifiex_dbg(priv->adapter, MSG, "radar detection type: %d\n",
+ rdr_event->det_type);
} else {
- dev_dbg(priv->adapter->dev, "false radar detection event!\n");
+ mwifiex_dbg(priv->adapter, MSG,
+ "false radar detection event!\n");
}
return 0;
@@ -276,20 +300,20 @@ void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work)
bss_cfg = &priv->bss_cfg;
if (!bss_cfg->beacon_period) {
- dev_err(priv->adapter->dev,
- "channel switch: AP already stopped\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "channel switch: AP already stopped\n");
return;
}
- mwifiex_uap_set_channel(bss_cfg, priv->dfs_chandef);
+ mwifiex_uap_set_channel(priv, bss_cfg, priv->dfs_chandef);
if (mwifiex_config_start_uap(priv, bss_cfg)) {
- dev_dbg(priv->adapter->dev,
- "Failed to start AP after channel switch\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to start AP after channel switch\n");
return;
}
- dev_notice(priv->adapter->dev,
- "indicating channel switch completion to kernel\n");
+ mwifiex_dbg(priv->adapter, MSG,
+ "indicating channel switch completion to kernel\n");
cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef);
}
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
index 433bd6837c79..c174e79e6df2 100644
--- a/drivers/net/wireless/mwifiex/11n.c
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -42,7 +42,7 @@ int mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type,
priv->wdev.wiphy->bands[radio_type];
if (WARN_ON_ONCE(!sband)) {
- dev_err(priv->adapter->dev, "Invalid radio type!\n");
+ mwifiex_dbg(priv->adapter, ERROR, "Invalid radio type!\n");
return -EINVAL;
}
@@ -156,7 +156,7 @@ int mwifiex_ret_11n_delba(struct mwifiex_private *priv,
int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp)
{
- int tid;
+ int tid, tid_down;
struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp;
struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
struct mwifiex_ra_list_tbl *ra_list;
@@ -167,7 +167,9 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
>> BLOCKACKPARAM_TID_POS;
- ra_list = mwifiex_wmm_get_ralist_node(priv, tid, add_ba_rsp->
+
+ tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
+ ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, add_ba_rsp->
peer_mac_addr);
if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) {
if (ra_list) {
@@ -184,7 +186,7 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
tx_ba_tbl = mwifiex_get_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr);
if (tx_ba_tbl) {
- dev_dbg(priv->adapter->dev, "info: BA stream complete\n");
+ mwifiex_dbg(priv->adapter, EVENT, "info: BA stream complete\n");
tx_ba_tbl->ba_status = BA_SETUP_COMPLETE;
if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
priv->add_ba_param.tx_amsdu &&
@@ -197,7 +199,7 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
ra_list->ba_status = BA_SETUP_COMPLETE;
}
} else {
- dev_err(priv->adapter->dev, "BA stream not created\n");
+ mwifiex_dbg(priv->adapter, ERROR, "BA stream not created\n");
}
return 0;
@@ -224,7 +226,8 @@ int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
tx_buf->action = cpu_to_le16(action);
switch (action) {
case HostCmd_ACT_GEN_SET:
- dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", *buf_size);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: set tx_buf=%d\n", *buf_size);
tx_buf->buff_size = cpu_to_le16(*buf_size);
break;
case HostCmd_ACT_GEN_GET:
@@ -466,7 +469,8 @@ void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl))
return;
- dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl);
list_del(&tx_ba_tsr_tbl->list);
@@ -528,13 +532,16 @@ void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid,
struct mwifiex_tx_ba_stream_tbl *new_node;
struct mwifiex_ra_list_tbl *ra_list;
unsigned long flags;
+ int tid_down;
if (!mwifiex_get_ba_tbl(priv, tid, ra)) {
new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl),
GFP_ATOMIC);
if (!new_node)
return;
- ra_list = mwifiex_wmm_get_ralist_node(priv, tid, ra);
+
+ tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
+ ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, ra);
if (ra_list) {
ra_list->ba_status = ba_status;
ra_list->amsdu_in_ampdu = false;
@@ -563,7 +570,7 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
unsigned long flags;
u16 block_ack_param_set;
- dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid);
+ mwifiex_dbg(priv->adapter, CMD, "cmd: %s: tid %d\n", __func__, tid);
if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
@@ -575,9 +582,9 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
sta_ptr = mwifiex_get_sta_entry(priv, peer_mac);
if (!sta_ptr) {
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
- dev_warn(priv->adapter->dev,
- "BA setup with unknown TDLS peer %pM!\n",
- peer_mac);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "BA setup with unknown TDLS peer %pM!\n",
+ peer_mac);
return -1;
}
if (sta_ptr->is_11ac_enabled)
@@ -641,6 +648,30 @@ int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
}
/*
+ * This function sends delba to specific tid
+ */
+void mwifiex_11n_delba(struct mwifiex_private *priv, int tid)
+{
+ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
+
+ if (list_empty(&priv->rx_reorder_tbl_ptr)) {
+ dev_dbg(priv->adapter->dev,
+ "mwifiex_11n_delba: rx_reorder_tbl_ptr empty\n");
+ return;
+ }
+
+ list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) {
+ if (rx_reor_tbl_ptr->tid == tid) {
+ dev_dbg(priv->adapter->dev,
+ "Send delba to tid=%d, %pM\n",
+ tid, rx_reor_tbl_ptr->ta);
+ mwifiex_send_delba(priv, tid, rx_reor_tbl_ptr->ta, 0);
+ return;
+ }
+ }
+}
+
+/*
* This function handles the command response of a delete BA request.
*/
void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba)
@@ -706,8 +737,8 @@ int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid;
- dev_dbg(priv->adapter->dev, "data: %s tid=%d\n",
- __func__, rx_reo_tbl->tid);
+ mwifiex_dbg(priv->adapter, DATA, "data: %s tid=%d\n",
+ __func__, rx_reo_tbl->tid);
memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN);
rx_reo_tbl->amsdu = tx_ba_tsr_tbl->amsdu;
rx_reo_tbl++;
@@ -812,3 +843,72 @@ u8 mwifiex_get_sec_chan_offset(int chan)
return sec_offset;
}
+
+/* This function will send DELBA to entries in the priv's
+ * Tx BA stream table
+ */
+static void
+mwifiex_send_delba_txbastream_tbl(struct mwifiex_private *priv, u8 tid)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_tx_ba_stream_tbl *tx_ba_stream_tbl_ptr;
+
+ if (list_empty(&priv->tx_ba_stream_tbl_ptr))
+ return;
+
+ list_for_each_entry(tx_ba_stream_tbl_ptr,
+ &priv->tx_ba_stream_tbl_ptr, list) {
+ if (tx_ba_stream_tbl_ptr->ba_status == BA_SETUP_COMPLETE) {
+ if (tid == tx_ba_stream_tbl_ptr->tid) {
+ dev_dbg(adapter->dev,
+ "Tx:Send delba to tid=%d, %pM\n", tid,
+ tx_ba_stream_tbl_ptr->ra);
+ mwifiex_send_delba(priv,
+ tx_ba_stream_tbl_ptr->tid,
+ tx_ba_stream_tbl_ptr->ra, 1);
+ return;
+ }
+ }
+ }
+}
+
+/* This function updates all the tx_win_size
+ */
+void mwifiex_update_ampdu_txwinsize(struct mwifiex_adapter *adapter)
+{
+ u8 i;
+ u32 tx_win_size;
+ struct mwifiex_private *priv;
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (!adapter->priv[i])
+ continue;
+ priv = adapter->priv[i];
+ tx_win_size = priv->add_ba_param.tx_win_size;
+
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_TXWINSIZE;
+
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_TXWINSIZE;
+
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE;
+
+ if (adapter->coex_win_size) {
+ if (adapter->coex_tx_win_size)
+ priv->add_ba_param.tx_win_size =
+ adapter->coex_tx_win_size;
+ }
+
+ if (tx_win_size != priv->add_ba_param.tx_win_size) {
+ if (!priv->media_connected)
+ continue;
+ for (i = 0; i < MAX_NUM_TID; i++)
+ mwifiex_send_delba_txbastream_tbl(priv, i);
+ }
+ }
+}
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c
index 6183e255e62a..f7c717253a66 100644
--- a/drivers/net/wireless/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -187,7 +187,6 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
skb_aggr = mwifiex_alloc_dma_align_buf(adapter->tx_buf_size,
GFP_ATOMIC | GFP_DMA);
if (!skb_aggr) {
- dev_err(adapter->dev, "%s: alloc skb_aggr\n", __func__);
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
return -1;
@@ -297,13 +296,13 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
- dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
+ mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
break;
case -1:
if (adapter->iface_type != MWIFIEX_PCIE)
adapter->data_sent = false;
- dev_err(adapter->dev, "%s: host_to_card failed: %#x\n",
- __func__, ret);
+ mwifiex_dbg(adapter, ERROR, "%s: host_to_card failed: %#x\n",
+ __func__, ret);
adapter->dbg.num_tx_host_to_card_failure++;
mwifiex_write_data_complete(adapter, skb_aggr, 1, ret);
return 0;
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
index f75f8acfaca0..2906cd543532 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -51,8 +51,8 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
rx_skb = __skb_dequeue(&list);
ret = mwifiex_recv_packet(priv, rx_skb);
if (ret == -1)
- dev_err(priv->adapter->dev,
- "Rx of A-MSDU failed");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Rx of A-MSDU failed");
}
return 0;
}
@@ -304,7 +304,7 @@ mwifiex_flush_data(unsigned long context)
if (seq_num < 0)
return;
- dev_dbg(ctx->priv->adapter->dev, "info: flush data %d\n", seq_num);
+ mwifiex_dbg(ctx->priv->adapter, INFO, "info: flush data %d\n", seq_num);
start_win = (ctx->ptr->start_win + seq_num + 1) & (MAX_TID_VALUE - 1);
mwifiex_11n_dispatch_pkt_until_start_win(ctx->priv, ctx->ptr,
start_win);
@@ -367,8 +367,9 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
}
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
- dev_dbg(priv->adapter->dev, "info: last_seq=%d start_win=%d\n",
- last_seq, new_node->start_win);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: last_seq=%d start_win=%d\n",
+ last_seq, new_node->start_win);
if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
last_seq >= new_node->start_win) {
@@ -382,8 +383,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
GFP_KERNEL);
if (!new_node->rx_reorder_ptr) {
kfree((u8 *) new_node);
- dev_err(priv->adapter->dev,
- "%s: failed to alloc reorder_ptr\n", __func__);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: failed to alloc reorder_ptr\n", __func__);
return;
}
@@ -467,9 +468,9 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
cmd_addba_req->peer_mac_addr);
if (!sta_ptr) {
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
- dev_warn(priv->adapter->dev,
- "BA setup with unknown TDLS peer %pM!\n",
- cmd_addba_req->peer_mac_addr);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "BA setup with unknown TDLS peer %pM!\n",
+ cmd_addba_req->peer_mac_addr);
return -1;
}
if (sta_ptr->is_11ac_enabled)
@@ -573,14 +574,14 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
}
if (tbl->flags & RXREOR_FORCE_NO_DROP) {
- dev_dbg(priv->adapter->dev,
- "RXREOR_FORCE_NO_DROP when HS is activated\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "RXREOR_FORCE_NO_DROP when HS is activated\n");
tbl->flags &= ~RXREOR_FORCE_NO_DROP;
} else if (init_window_shift && seq_num < start_win &&
seq_num >= tbl->init_win) {
- dev_dbg(priv->adapter->dev,
- "Sender TID sequence number reset %d->%d for SSN %d\n",
- start_win, seq_num, tbl->init_win);
+ mwifiex_dbg(priv->adapter, INFO,
+ "Sender TID sequence number reset %d->%d for SSN %d\n",
+ start_win, seq_num, tbl->init_win);
tbl->start_win = start_win = seq_num;
end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
} else {
@@ -662,32 +663,35 @@ mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac,
struct mwifiex_ra_list_tbl *ra_list;
u8 cleanup_rx_reorder_tbl;
unsigned long flags;
+ int tid_down;
if (type == TYPE_DELBA_RECEIVE)
cleanup_rx_reorder_tbl = (initiator) ? true : false;
else
cleanup_rx_reorder_tbl = (initiator) ? false : true;
- dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d initiator=%d\n",
- peer_mac, tid, initiator);
+ mwifiex_dbg(priv->adapter, EVENT, "event: DELBA: %pM tid=%d initiator=%d\n",
+ peer_mac, tid, initiator);
if (cleanup_rx_reorder_tbl) {
tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
peer_mac);
if (!tbl) {
- dev_dbg(priv->adapter->dev,
- "event: TID, TA not found in table\n");
+ mwifiex_dbg(priv->adapter, EVENT,
+ "event: TID, TA not found in table\n");
return;
}
mwifiex_del_rx_reorder_entry(priv, tbl);
} else {
ptx_tbl = mwifiex_get_ba_tbl(priv, tid, peer_mac);
if (!ptx_tbl) {
- dev_dbg(priv->adapter->dev,
- "event: TID, RA not found in table\n");
+ mwifiex_dbg(priv->adapter, EVENT,
+ "event: TID, RA not found in table\n");
return;
}
- ra_list = mwifiex_wmm_get_ralist_node(priv, tid, peer_mac);
+
+ tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
+ ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, peer_mac);
if (ra_list) {
ra_list->amsdu_in_ampdu = false;
ra_list->ba_status = BA_SETUP_NONE;
@@ -721,8 +725,8 @@ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
* the stream
*/
if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) {
- dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n",
- add_ba_rsp->peer_mac_addr, tid);
+ mwifiex_dbg(priv->adapter, ERROR, "ADDBA RSP: failed %pM tid=%d)\n",
+ add_ba_rsp->peer_mac_addr, tid);
tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
add_ba_rsp->peer_mac_addr);
@@ -746,8 +750,8 @@ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
tbl->amsdu = false;
}
- dev_dbg(priv->adapter->dev,
- "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n",
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n",
add_ba_rsp->peer_mac_addr, tid, add_ba_rsp->ssn, win_size);
return 0;
@@ -824,3 +828,83 @@ void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags)
return;
}
+
+/* This function update all the rx_win_size based on coex flag
+ */
+static void mwifiex_update_ampdu_rxwinsize(struct mwifiex_adapter *adapter,
+ bool coex_flag)
+{
+ u8 i;
+ u32 rx_win_size;
+ struct mwifiex_private *priv;
+
+ dev_dbg(adapter->dev, "Update rxwinsize %d\n", coex_flag);
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (!adapter->priv[i])
+ continue;
+ priv = adapter->priv[i];
+ rx_win_size = priv->add_ba_param.rx_win_size;
+ if (coex_flag) {
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE;
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE;
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_UAP_COEX_AMPDU_DEF_RXWINSIZE;
+ } else {
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE;
+ }
+
+ if (adapter->coex_win_size && adapter->coex_rx_win_size)
+ priv->add_ba_param.rx_win_size =
+ adapter->coex_rx_win_size;
+
+ if (rx_win_size != priv->add_ba_param.rx_win_size) {
+ if (!priv->media_connected)
+ continue;
+ for (i = 0; i < MAX_NUM_TID; i++)
+ mwifiex_11n_delba(priv, i);
+ }
+ }
+}
+
+/* This function check coex for RX BA
+ */
+void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter)
+{
+ u8 i;
+ struct mwifiex_private *priv;
+ u8 count = 0;
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i]) {
+ priv = adapter->priv[i];
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
+ if (priv->media_connected)
+ count++;
+ }
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ if (priv->bss_started)
+ count++;
+ }
+ }
+ if (count >= MWIFIEX_BSS_COEX_COUNT)
+ break;
+ }
+ if (count >= MWIFIEX_BSS_COEX_COUNT)
+ mwifiex_update_ampdu_rxwinsize(adapter, true);
+ else
+ mwifiex_update_ampdu_rxwinsize(adapter, false);
+}
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig
index aa01c9bc77f9..48edf387683e 100644
--- a/drivers/net/wireless/mwifiex/Kconfig
+++ b/drivers/net/wireless/mwifiex/Kconfig
@@ -12,6 +12,7 @@ config MWIFIEX_SDIO
tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797/SD8887/SD8897"
depends on MWIFIEX && MMC
select FW_LOADER
+ select WANT_DEV_COREDUMP
---help---
This adds support for wireless adapters based on Marvell
8786/8787/8797/8887/8897 chipsets with SDIO interface.
@@ -23,6 +24,7 @@ config MWIFIEX_PCIE
tristate "Marvell WiFi-Ex Driver for PCIE 8766/8897"
depends on MWIFIEX && PCI
select FW_LOADER
+ select WANT_DEV_COREDUMP
---help---
This adds support for wireless adapters based on Marvell
8766/8897 chipsets with PCIe interface.
diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README
index 31928caeeed2..2f0f9b5609d0 100644
--- a/drivers/net/wireless/mwifiex/README
+++ b/drivers/net/wireless/mwifiex/README
@@ -230,9 +230,9 @@ getlog
cat getlog
-fw_dump
- This command is used to dump firmware memory into files.
- Separate file will be created for each memory segment.
+device_dump
+ This command is used to dump driver information and firmware memory
+ segments.
Usage:
cat fw_dump
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index bf9020ff2d33..b15e4c7acbec 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -67,6 +67,22 @@ u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type)
}
}
+/* This function maps IEEE HT secondary channel type to NL80211 channel type
+ */
+u8 mwifiex_sec_chan_offset_to_chan_type(u8 second_chan_offset)
+{
+ switch (second_chan_offset) {
+ case IEEE80211_HT_PARAM_CHA_SEC_NONE:
+ return NL80211_CHAN_HT20;
+ case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+ return NL80211_CHAN_HT40PLUS;
+ case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+ return NL80211_CHAN_HT40MINUS;
+ default:
+ return NL80211_CHAN_HT20;
+ }
+}
+
/*
* This function checks whether WEP is set.
*/
@@ -104,11 +120,11 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
if (mwifiex_set_encode(priv, NULL, NULL, 0, key_index, peer_mac, 1)) {
- wiphy_err(wiphy, "deleting the crypto keys\n");
+ mwifiex_dbg(priv->adapter, ERROR, "deleting the crypto keys\n");
return -EFAULT;
}
- wiphy_dbg(wiphy, "info: crypto keys deleted\n");
+ mwifiex_dbg(priv->adapter, INFO, "info: crypto keys deleted\n");
return 0;
}
@@ -163,7 +179,7 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
if (!buf || !len) {
- wiphy_err(wiphy, "invalid buffer and length\n");
+ mwifiex_dbg(priv->adapter, ERROR, "invalid buffer and length\n");
return -EFAULT;
}
@@ -172,8 +188,8 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
ieee80211_is_probe_resp(mgmt->frame_control)) {
/* Since we support offload probe resp, we need to skip probe
* resp in AP or GO mode */
- wiphy_dbg(wiphy,
- "info: skip to send probe resp in AP or GO mode\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: skip to send probe resp in AP or GO mode\n");
return 0;
}
@@ -183,7 +199,8 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
pkt_len + sizeof(pkt_len));
if (!skb) {
- wiphy_err(wiphy, "allocate skb failed for management frame\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "allocate skb failed for management frame\n");
return -ENOMEM;
}
@@ -206,7 +223,7 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
mwifiex_queue_tx_pkt(priv, skb);
- wiphy_dbg(wiphy, "info: management frame transmitted\n");
+ mwifiex_dbg(priv->adapter, INFO, "info: management frame transmitted\n");
return 0;
}
@@ -231,7 +248,7 @@ mwifiex_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG,
HostCmd_ACT_GEN_SET, 0,
&priv->mgmt_frame_mask, false);
- wiphy_dbg(wiphy, "info: mgmt frame registered\n");
+ mwifiex_dbg(priv->adapter, INFO, "info: mgmt frame registered\n");
}
}
@@ -248,13 +265,14 @@ mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy,
int ret;
if (!chan || !cookie) {
- wiphy_err(wiphy, "Invalid parameter for ROC\n");
+ mwifiex_dbg(priv->adapter, ERROR, "Invalid parameter for ROC\n");
return -EINVAL;
}
if (priv->roc_cfg.cookie) {
- wiphy_dbg(wiphy, "info: ongoing ROC, cookie = 0x%llx\n",
- priv->roc_cfg.cookie);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ongoing ROC, cookie = 0x%llx\n",
+ priv->roc_cfg.cookie);
return -EBUSY;
}
@@ -269,7 +287,8 @@ mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy,
cfg80211_ready_on_channel(wdev, *cookie, chan,
duration, GFP_ATOMIC);
- wiphy_dbg(wiphy, "info: ROC, cookie = 0x%llx\n", *cookie);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ROC, cookie = 0x%llx\n", *cookie);
}
return ret;
@@ -298,7 +317,8 @@ mwifiex_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
memset(&priv->roc_cfg, 0, sizeof(struct mwifiex_roc_cfg));
- wiphy_dbg(wiphy, "info: cancel ROC, cookie = 0x%llx\n", cookie);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: cancel ROC, cookie = 0x%llx\n", cookie);
}
return ret;
@@ -344,8 +364,8 @@ mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy,
u32 ps_mode;
if (timeout)
- wiphy_dbg(wiphy,
- "info: ignore timeout value for IEEE Power Save\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ignore timeout value for IEEE Power Save\n");
ps_mode = enabled;
@@ -370,7 +390,7 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
priv->wep_key_curr_index = key_index;
} else if (mwifiex_set_encode(priv, NULL, NULL, 0, key_index,
NULL, 0)) {
- wiphy_err(wiphy, "set default Tx key index\n");
+ mwifiex_dbg(priv->adapter, ERROR, "set default Tx key index\n");
return -EFAULT;
}
@@ -407,7 +427,7 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
if (mwifiex_set_encode(priv, params, params->key, params->key_len,
key_index, peer_mac, 0)) {
- wiphy_err(wiphy, "crypto keys added\n");
+ mwifiex_dbg(priv->adapter, ERROR, "crypto keys added\n");
return -EFAULT;
}
@@ -442,7 +462,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
band = mwifiex_band_to_radio_type(adapter->config_bands);
if (!wiphy->bands[band]) {
- wiphy_err(wiphy, "11D: setting domain info in FW\n");
+ mwifiex_dbg(adapter, ERROR,
+ "11D: setting domain info in FW\n");
return -1;
}
@@ -493,7 +514,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
HostCmd_ACT_GEN_SET, 0, NULL, false)) {
- wiphy_err(wiphy, "11D: setting domain info in FW\n");
+ mwifiex_dbg(adapter, INFO,
+ "11D: setting domain info in FW\n");
return -1;
}
@@ -516,9 +538,9 @@ static void mwifiex_reg_notifier(struct wiphy *wiphy,
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
struct mwifiex_private *priv = mwifiex_get_priv(adapter,
MWIFIEX_BSS_ROLE_ANY);
-
- wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for %c%c\n",
- request->alpha2[0], request->alpha2[1]);
+ mwifiex_dbg(adapter, INFO,
+ "info: cfg80211 regulatory domain callback for %c%c\n",
+ request->alpha2[0], request->alpha2[1]);
switch (request->initiator) {
case NL80211_REGDOM_SET_BY_DRIVER:
@@ -527,8 +549,9 @@ static void mwifiex_reg_notifier(struct wiphy *wiphy,
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
break;
default:
- wiphy_err(wiphy, "unknown regdom initiator: %d\n",
- request->initiator);
+ mwifiex_dbg(adapter, ERROR,
+ "unknown regdom initiator: %d\n",
+ request->initiator);
return;
}
@@ -597,8 +620,8 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
switch (priv->bss_role) {
case MWIFIEX_BSS_ROLE_UAP:
if (priv->bss_started) {
- dev_err(adapter->dev,
- "cannot change wiphy params when bss started");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot change wiphy params when bss started");
return -EINVAL;
}
@@ -622,15 +645,16 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
kfree(bss_cfg);
if (ret) {
- wiphy_err(wiphy, "Failed to set wiphy phy params\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to set wiphy phy params\n");
return ret;
}
break;
case MWIFIEX_BSS_ROLE_STA:
if (priv->media_connected) {
- dev_err(adapter->dev,
- "cannot change wiphy params when connected");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot change wiphy params when connected");
return -EINVAL;
}
if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
@@ -724,8 +748,8 @@ static int mwifiex_deinit_priv_params(struct mwifiex_private *priv)
if (mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG,
HostCmd_ACT_GEN_SET, 0,
&priv->mgmt_frame_mask, false)) {
- dev_warn(priv->adapter->dev,
- "could not unregister mgmt frame rx\n");
+ mwifiex_dbg(adapter, ERROR,
+ "could not unregister mgmt frame rx\n");
return -1;
}
@@ -789,9 +813,9 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv,
priv->bss_role = MWIFIEX_BSS_ROLE_UAP;
break;
default:
- dev_err(priv->adapter->dev,
- "%s: changing to %d not supported\n",
- dev->name, type);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
return -EOPNOTSUPP;
}
@@ -824,12 +848,13 @@ mwifiex_change_vif_to_p2p(struct net_device *dev,
if (adapter->curr_iface_comb.p2p_intf ==
adapter->iface_limit.p2p_intf) {
- dev_err(adapter->dev,
- "cannot create multiple P2P ifaces\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create multiple P2P ifaces\n");
return -1;
}
- dev_dbg(priv->adapter->dev, "%s: changing role to p2p\n", dev->name);
+ mwifiex_dbg(adapter, INFO,
+ "%s: changing role to p2p\n", dev->name);
if (mwifiex_deinit_priv_params(priv))
return -1;
@@ -846,9 +871,9 @@ mwifiex_change_vif_to_p2p(struct net_device *dev,
return -EFAULT;
break;
default:
- dev_err(priv->adapter->dev,
- "%s: changing to %d not supported\n",
- dev->name, type);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
return -EOPNOTSUPP;
}
@@ -897,17 +922,17 @@ mwifiex_change_vif_to_sta_adhoc(struct net_device *dev,
curr_iftype != NL80211_IFTYPE_P2P_GO) &&
(adapter->curr_iface_comb.sta_intf ==
adapter->iface_limit.sta_intf)) {
- dev_err(adapter->dev,
- "cannot create multiple station/adhoc ifaces\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create multiple station/adhoc ifaces\n");
return -1;
}
if (type == NL80211_IFTYPE_STATION)
- dev_notice(adapter->dev,
- "%s: changing role to station\n", dev->name);
+ mwifiex_dbg(adapter, INFO,
+ "%s: changing role to station\n", dev->name);
else
- dev_notice(adapter->dev,
- "%s: changing role to adhoc\n", dev->name);
+ mwifiex_dbg(adapter, INFO,
+ "%s: changing role to adhoc\n", dev->name);
if (mwifiex_deinit_priv_params(priv))
return -1;
@@ -954,12 +979,13 @@ mwifiex_change_vif_to_ap(struct net_device *dev,
if (adapter->curr_iface_comb.uap_intf ==
adapter->iface_limit.uap_intf) {
- dev_err(adapter->dev,
- "cannot create multiple AP ifaces\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create multiple AP ifaces\n");
return -1;
}
- dev_notice(adapter->dev, "%s: changing role to AP\n", dev->name);
+ mwifiex_dbg(adapter, INFO,
+ "%s: changing role to AP\n", dev->name);
if (mwifiex_deinit_priv_params(priv))
return -1;
@@ -1020,12 +1046,14 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
flags, params);
case NL80211_IFTYPE_UNSPECIFIED:
- wiphy_warn(wiphy, "%s: kept type as IBSS\n", dev->name);
+ mwifiex_dbg(priv->adapter, INFO,
+ "%s: kept type as IBSS\n", dev->name);
case NL80211_IFTYPE_ADHOC: /* This shouldn't happen */
return 0;
default:
- wiphy_err(wiphy, "%s: changing to %d not supported\n",
- dev->name, type);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
return -EOPNOTSUPP;
}
break;
@@ -1048,12 +1076,14 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
flags, params);
case NL80211_IFTYPE_UNSPECIFIED:
- wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name);
+ mwifiex_dbg(priv->adapter, INFO,
+ "%s: kept type as STA\n", dev->name);
case NL80211_IFTYPE_STATION: /* This shouldn't happen */
return 0;
default:
- wiphy_err(wiphy, "%s: changing to %d not supported\n",
- dev->name, type);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
return -EOPNOTSUPP;
}
break;
@@ -1070,12 +1100,14 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
return mwifiex_change_vif_to_p2p(dev, curr_iftype,
type, flags, params);
case NL80211_IFTYPE_UNSPECIFIED:
- wiphy_warn(wiphy, "%s: kept type as AP\n", dev->name);
+ mwifiex_dbg(priv->adapter, INFO,
+ "%s: kept type as AP\n", dev->name);
case NL80211_IFTYPE_AP: /* This shouldn't happen */
return 0;
default:
- wiphy_err(wiphy, "%s: changing to %d not supported\n",
- dev->name, type);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
return -EOPNOTSUPP;
}
break;
@@ -1100,19 +1132,22 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
flags, params);
case NL80211_IFTYPE_UNSPECIFIED:
- wiphy_warn(wiphy, "%s: kept type as P2P\n", dev->name);
+ mwifiex_dbg(priv->adapter, INFO,
+ "%s: kept type as P2P\n", dev->name);
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
return 0;
default:
- wiphy_err(wiphy, "%s: changing to %d not supported\n",
- dev->name, type);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
return -EOPNOTSUPP;
}
break;
default:
- wiphy_err(wiphy, "%s: unknown iftype: %d\n",
- dev->name, dev->ieee80211_ptr->iftype);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: unknown iftype: %d\n",
+ dev->name, dev->ieee80211_ptr->iftype);
return -EOPNOTSUPP;
}
@@ -1194,6 +1229,7 @@ mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo,
*/
static int
mwifiex_dump_station_info(struct mwifiex_private *priv,
+ struct mwifiex_sta_node *node,
struct station_info *sinfo)
{
u32 rate;
@@ -1203,15 +1239,41 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
BIT(NL80211_STA_INFO_TX_BITRATE) |
BIT(NL80211_STA_INFO_SIGNAL) | BIT(NL80211_STA_INFO_SIGNAL_AVG);
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ if (!node)
+ return -ENOENT;
+
+ sinfo->filled |= BIT(NL80211_STA_INFO_INACTIVE_TIME) |
+ BIT(NL80211_STA_INFO_TX_FAILED);
+ sinfo->inactive_time =
+ jiffies_to_msecs(jiffies - node->stats.last_rx);
+
+ sinfo->signal = node->stats.rssi;
+ sinfo->signal_avg = node->stats.rssi;
+ sinfo->rx_bytes = node->stats.rx_bytes;
+ sinfo->tx_bytes = node->stats.tx_bytes;
+ sinfo->rx_packets = node->stats.rx_packets;
+ sinfo->tx_packets = node->stats.tx_packets;
+ sinfo->tx_failed = node->stats.tx_failed;
+
+ mwifiex_parse_htinfo(priv, node->stats.last_tx_htinfo,
+ &sinfo->txrate);
+ sinfo->txrate.legacy = node->stats.last_tx_rate * 5;
+
+ return 0;
+ }
+
/* Get signal information from the firmware */
if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
HostCmd_ACT_GEN_GET, 0, NULL, true)) {
- dev_err(priv->adapter->dev, "failed to get signal information\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "failed to get signal information\n");
return -EFAULT;
}
if (mwifiex_drv_get_data_rate(priv, &rate)) {
- dev_err(priv->adapter->dev, "getting data rate\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "getting data rate error\n");
return -EFAULT;
}
@@ -1267,7 +1329,7 @@ mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
if (memcmp(mac, priv->cfg_bssid, ETH_ALEN))
return -ENOENT;
- return mwifiex_dump_station_info(priv, sinfo);
+ return mwifiex_dump_station_info(priv, NULL, sinfo);
}
/*
@@ -1278,13 +1340,29 @@ mwifiex_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
int idx, u8 *mac, struct station_info *sinfo)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ static struct mwifiex_sta_node *node;
- if (!priv->media_connected || idx)
- return -ENOENT;
+ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
+ priv->media_connected && idx == 0) {
+ ether_addr_copy(mac, priv->cfg_bssid);
+ return mwifiex_dump_station_info(priv, NULL, sinfo);
+ } else if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ mwifiex_send_cmd(priv, HOST_CMD_APCMD_STA_LIST,
+ HostCmd_ACT_GEN_GET, 0, NULL, true);
+
+ if (node && (&node->list == &priv->sta_list)) {
+ node = NULL;
+ return -ENOENT;
+ }
- memcpy(mac, priv->cfg_bssid, ETH_ALEN);
+ node = list_prepare_entry(node, &priv->sta_list, list);
+ list_for_each_entry_continue(node, &priv->sta_list, list) {
+ ether_addr_copy(mac, node->mac_addr);
+ return mwifiex_dump_station_info(priv, node, sinfo);
+ }
+ }
- return mwifiex_dump_station_info(priv, sinfo);
+ return -ENOENT;
}
static int
@@ -1295,7 +1373,7 @@ mwifiex_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
struct mwifiex_chan_stats *pchan_stats = priv->adapter->chan_stats;
enum ieee80211_band band;
- dev_dbg(priv->adapter->dev, "dump_survey idx=%d\n", idx);
+ mwifiex_dbg(priv->adapter, DUMP, "dump_survey idx=%d\n", idx);
memset(survey, 0, sizeof(struct survey_info));
@@ -1472,8 +1550,8 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
struct mwifiex_adapter *adapter = priv->adapter;
if (!priv->media_connected) {
- dev_err(adapter->dev,
- "Can not set Tx data rate in disconnected state\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Can not set Tx data rate in disconnected state\n");
return -EINVAL;
}
@@ -1556,17 +1634,20 @@ static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy,
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) {
- wiphy_err(wiphy, "%s: bss_type mismatched\n", __func__);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: bss_type mismatched\n", __func__);
return -EINVAL;
}
if (!priv->bss_started) {
- wiphy_err(wiphy, "%s: bss not started\n", __func__);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: bss not started\n", __func__);
return -EINVAL;
}
if (mwifiex_set_mgmt_ies(priv, data)) {
- wiphy_err(wiphy, "%s: setting mgmt ies failed\n", __func__);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: setting mgmt ies failed\n", __func__);
return -EFAULT;
}
@@ -1594,7 +1675,8 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
if (!params->mac || is_broadcast_ether_addr(params->mac))
return 0;
- wiphy_dbg(wiphy, "%s: mac address %pM\n", __func__, params->mac);
+ mwifiex_dbg(priv->adapter, INFO, "%s: mac address %pM\n",
+ __func__, params->mac);
eth_zero_addr(deauth_mac);
@@ -1687,14 +1769,23 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
mwifiex_abort_cac(priv);
if (mwifiex_del_mgmt_ies(priv))
- wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to delete mgmt IEs!\n");
priv->ap_11n_enabled = 0;
memset(&priv->bss_cfg, 0, sizeof(priv->bss_cfg));
if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0, NULL, true)) {
- wiphy_err(wiphy, "Failed to stop the BSS\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to stop the BSS\n");
+ return -1;
+ }
+
+ if (mwifiex_send_cmd(priv, HOST_CMD_APCMD_SYS_RESET,
+ HostCmd_ACT_GEN_SET, 0, NULL, true)) {
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to reset BSS\n");
return -1;
}
@@ -1751,12 +1842,13 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
return -EINVAL;
}
- mwifiex_uap_set_channel(bss_cfg, params->chandef);
+ mwifiex_uap_set_channel(priv, bss_cfg, params->chandef);
mwifiex_set_uap_rates(bss_cfg, params);
if (mwifiex_set_secure_params(priv, bss_cfg, params)) {
kfree(bss_cfg);
- wiphy_err(wiphy, "Failed to parse secuirty parameters!\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to parse secuirty parameters!\n");
return -1;
}
@@ -1775,20 +1867,25 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
mwifiex_set_wmm_params(priv, bss_cfg, params);
+ if (mwifiex_is_11h_active(priv))
+ mwifiex_set_tpc_params(priv, bss_cfg, params);
+
if (mwifiex_is_11h_active(priv) &&
!cfg80211_chandef_dfs_required(wiphy, &params->chandef,
priv->bss_mode)) {
- dev_dbg(priv->adapter->dev, "Disable 11h extensions in FW\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "Disable 11h extensions in FW\n");
if (mwifiex_11h_activate(priv, false)) {
- dev_err(priv->adapter->dev,
- "Failed to disable 11h extensions!!");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to disable 11h extensions!!");
return -1;
}
- priv->state_11h.is_11h_active = true;
+ priv->state_11h.is_11h_active = false;
}
if (mwifiex_config_start_uap(priv, bss_cfg)) {
- wiphy_err(wiphy, "Failed to start AP\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to start AP\n");
kfree(bss_cfg);
return -1;
}
@@ -1816,8 +1913,9 @@ mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
if (mwifiex_deauthenticate(priv, NULL))
return -EFAULT;
- wiphy_dbg(wiphy, "info: successfully disconnected from %pM:"
- " reason code %d\n", priv->cfg_bssid, reason_code);
+ mwifiex_dbg(priv->adapter, MSG,
+ "info: successfully disconnected from %pM:\t"
+ "reason code %d\n", priv->cfg_bssid, reason_code);
eth_zero_addr(priv->cfg_bssid);
priv->hs2_enabled = false;
@@ -1899,13 +1997,13 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len,
req_ssid.ssid_len = ssid_len;
if (ssid_len > IEEE80211_MAX_SSID_LEN) {
- dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
+ mwifiex_dbg(priv->adapter, ERROR, "invalid SSID - aborting\n");
return -EINVAL;
}
memcpy(req_ssid.ssid, ssid, ssid_len);
if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) {
- dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
+ mwifiex_dbg(priv->adapter, ERROR, "invalid SSID - aborting\n");
return -EINVAL;
}
@@ -1959,9 +2057,9 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len,
if (sme->key) {
if (mwifiex_is_alg_wep(priv->sec_info.encryption_mode)) {
- dev_dbg(priv->adapter->dev,
- "info: setting wep encryption"
- " with key len %d\n", sme->key_len);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: setting wep encryption\t"
+ "with key len %d\n", sme->key_len);
priv->wep_key_curr_index = sme->key_idx;
ret = mwifiex_set_encode(priv, NULL, sme->key,
sme->key_len, sme->key_idx,
@@ -1978,7 +2076,7 @@ done:
if (is_scanning_required) {
/* Do specific SSID scanning */
if (mwifiex_request_scan(priv, &req_ssid)) {
- dev_err(priv->adapter->dev, "scan error\n");
+ mwifiex_dbg(priv->adapter, ERROR, "scan error\n");
return -EFAULT;
}
}
@@ -1997,15 +2095,15 @@ done:
if (!bss) {
if (is_scanning_required) {
- dev_warn(priv->adapter->dev,
- "assoc: requested bss not found in scan results\n");
+ mwifiex_dbg(priv->adapter, WARN,
+ "assoc: requested bss not found in scan results\n");
break;
}
is_scanning_required = 1;
} else {
- dev_dbg(priv->adapter->dev,
- "info: trying to associate to '%s' bssid %pM\n",
- (char *) req_ssid.ssid, bss->bssid);
+ mwifiex_dbg(priv->adapter, MSG,
+ "info: trying to associate to '%s' bssid %pM\n",
+ (char *)req_ssid.ssid, bss->bssid);
memcpy(&priv->cfg_bssid, bss->bssid, ETH_ALEN);
break;
}
@@ -2041,26 +2139,29 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
int ret;
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) {
- wiphy_err(wiphy,
- "%s: reject infra assoc request in non-STA role\n",
- dev->name);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: reject infra assoc request in non-STA role\n",
+ dev->name);
return -EINVAL;
}
if (priv->wdev.current_bss) {
- wiphy_warn(wiphy, "%s: already connected\n", dev->name);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: already connected\n", dev->name);
return -EALREADY;
}
if (adapter->surprise_removed || adapter->is_cmd_timedout) {
- wiphy_err(wiphy,
- "%s: Ignore connection. Card removed or FW in bad state\n",
- dev->name);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: Ignore connection.\t"
+ "Card removed or FW in bad state\n",
+ dev->name);
return -EFAULT;
}
- wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n",
- (char *) sme->ssid, sme->bssid);
+ mwifiex_dbg(adapter, INFO,
+ "info: Trying to associate to %s and bssid %pM\n",
+ (char *)sme->ssid, sme->bssid);
ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid,
priv->bss_mode, sme->channel, sme, 0);
@@ -2068,17 +2169,17 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0,
NULL, 0, WLAN_STATUS_SUCCESS,
GFP_KERNEL);
- dev_dbg(priv->adapter->dev,
- "info: associated to bssid %pM successfully\n",
- priv->cfg_bssid);
+ mwifiex_dbg(priv->adapter, MSG,
+ "info: associated to bssid %pM successfully\n",
+ priv->cfg_bssid);
if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
priv->adapter->auto_tdls &&
priv->bss_type == MWIFIEX_BSS_TYPE_STA)
mwifiex_setup_auto_tdls_timer(priv);
} else {
- dev_dbg(priv->adapter->dev,
- "info: association to bssid %pM failed\n",
- priv->cfg_bssid);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "info: association to bssid %pM failed\n",
+ priv->cfg_bssid);
eth_zero_addr(priv->cfg_bssid);
if (ret > 0)
@@ -2105,7 +2206,6 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
static int mwifiex_set_ibss_params(struct mwifiex_private *priv,
struct cfg80211_ibss_params *params)
{
- struct wiphy *wiphy = priv->wdev.wiphy;
struct mwifiex_adapter *adapter = priv->adapter;
int index = 0, i;
u8 config_bands = 0;
@@ -2162,8 +2262,10 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv,
priv->adhoc_channel = ieee80211_frequency_to_channel(
params->chandef.chan->center_freq);
- wiphy_dbg(wiphy, "info: set ibss band %d, chan %d, chan offset %d\n",
- config_bands, priv->adhoc_channel, adapter->sec_chan_offset);
+ mwifiex_dbg(adapter, INFO,
+ "info: set ibss band %d, chan %d, chan offset %d\n",
+ config_bands, priv->adhoc_channel,
+ adapter->sec_chan_offset);
return 0;
}
@@ -2182,13 +2284,15 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
int ret = 0;
if (priv->bss_mode != NL80211_IFTYPE_ADHOC) {
- wiphy_err(wiphy, "request to join ibss received "
- "when station is not in ibss mode\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "request to join ibss received\t"
+ "when station is not in ibss mode\n");
goto done;
}
- wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n",
- (char *) params->ssid, params->bssid);
+ mwifiex_dbg(priv->adapter, MSG,
+ "info: trying to join to %s and bssid %pM\n",
+ (char *)params->ssid, params->bssid);
mwifiex_set_ibss_params(priv, params);
@@ -2200,12 +2304,12 @@ done:
if (!ret) {
cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid,
params->chandef.chan, GFP_KERNEL);
- dev_dbg(priv->adapter->dev,
- "info: joined/created adhoc network with bssid"
- " %pM successfully\n", priv->cfg_bssid);
+ mwifiex_dbg(priv->adapter, MSG,
+ "info: joined/created adhoc network with bssid\t"
+ "%pM successfully\n", priv->cfg_bssid);
} else {
- dev_dbg(priv->adapter->dev,
- "info: failed creating/joining adhoc network\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "info: failed creating/joining adhoc network\n");
}
return ret;
@@ -2222,8 +2326,8 @@ mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- wiphy_dbg(wiphy, "info: disconnecting from essid %pM\n",
- priv->cfg_bssid);
+ mwifiex_dbg(priv->adapter, MSG, "info: disconnecting from essid %pM\n",
+ priv->cfg_bssid);
if (mwifiex_deauthenticate(priv, NULL))
return -EFAULT;
@@ -2250,13 +2354,15 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
struct ieee_types_header *ie;
struct mwifiex_user_scan_cfg *user_scan_cfg;
- wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name);
+ mwifiex_dbg(priv->adapter, CMD,
+ "info: received scan request on %s\n", dev->name);
/* Block scan request if scan operation or scan cleanup when interface
* is disabled is in process
*/
if (priv->scan_request || priv->scan_aborting) {
- dev_err(priv->adapter->dev, "cmd: Scan already in process..\n");
+ mwifiex_dbg(priv->adapter, WARN,
+ "cmd: Scan already in process..\n");
return -EBUSY;
}
@@ -2308,7 +2414,8 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
ret = mwifiex_scan_networks(priv, user_scan_cfg);
kfree(user_scan_cfg);
if (ret) {
- dev_err(priv->adapter->dev, "scan failed: %d\n", ret);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "scan failed: %d\n", ret);
priv->scan_aborting = false;
priv->scan_request = NULL;
return ret;
@@ -2454,15 +2561,15 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
case NL80211_IFTYPE_ADHOC:
if (adapter->curr_iface_comb.sta_intf ==
adapter->iface_limit.sta_intf) {
- wiphy_err(wiphy,
- "cannot create multiple sta/adhoc ifaces\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create multiple sta/adhoc ifaces\n");
return ERR_PTR(-EINVAL);
}
priv = mwifiex_get_unused_priv(adapter);
if (!priv) {
- wiphy_err(wiphy,
- "could not get free private struct\n");
+ mwifiex_dbg(adapter, ERROR,
+ "could not get free private struct\n");
return ERR_PTR(-EFAULT);
}
@@ -2478,21 +2585,21 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II;
priv->bss_priority = 0;
priv->bss_role = MWIFIEX_BSS_ROLE_STA;
- priv->bss_num = 0;
+ priv->bss_num = adapter->curr_iface_comb.sta_intf;
break;
case NL80211_IFTYPE_AP:
if (adapter->curr_iface_comb.uap_intf ==
adapter->iface_limit.uap_intf) {
- wiphy_err(wiphy,
- "cannot create multiple AP ifaces\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create multiple AP ifaces\n");
return ERR_PTR(-EINVAL);
}
priv = mwifiex_get_unused_priv(adapter);
if (!priv) {
- wiphy_err(wiphy,
- "could not get free private struct\n");
+ mwifiex_dbg(adapter, ERROR,
+ "could not get free private struct\n");
return ERR_PTR(-EFAULT);
}
@@ -2504,22 +2611,22 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
priv->bss_priority = 0;
priv->bss_role = MWIFIEX_BSS_ROLE_UAP;
priv->bss_started = 0;
- priv->bss_num = 0;
+ priv->bss_num = adapter->curr_iface_comb.uap_intf;
priv->bss_mode = type;
break;
case NL80211_IFTYPE_P2P_CLIENT:
if (adapter->curr_iface_comb.p2p_intf ==
adapter->iface_limit.p2p_intf) {
- wiphy_err(wiphy,
- "cannot create multiple P2P ifaces\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create multiple P2P ifaces\n");
return ERR_PTR(-EINVAL);
}
priv = mwifiex_get_unused_priv(adapter);
if (!priv) {
- wiphy_err(wiphy,
- "could not get free private struct\n");
+ mwifiex_dbg(adapter, ERROR,
+ "could not get free private struct\n");
return ERR_PTR(-EFAULT);
}
@@ -2540,7 +2647,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
priv->bss_priority = MWIFIEX_BSS_ROLE_STA;
priv->bss_role = MWIFIEX_BSS_ROLE_STA;
priv->bss_started = 0;
- priv->bss_num = 0;
+ priv->bss_num = adapter->curr_iface_comb.p2p_intf;
if (mwifiex_cfg80211_init_p2p_client(priv)) {
memset(&priv->wdev, 0, sizeof(priv->wdev));
@@ -2550,7 +2657,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
break;
default:
- wiphy_err(wiphy, "type not supported\n");
+ mwifiex_dbg(adapter, ERROR, "type not supported\n");
return ERR_PTR(-EINVAL);
}
@@ -2558,7 +2665,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
name_assign_type, ether_setup,
IEEE80211_NUM_ACS, 1);
if (!dev) {
- wiphy_err(wiphy, "no memory available for netdevice\n");
+ mwifiex_dbg(adapter, ERROR,
+ "no memory available for netdevice\n");
memset(&priv->wdev, 0, sizeof(priv->wdev));
priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
@@ -2599,7 +2707,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
/* Register network device */
if (register_netdevice(dev)) {
- wiphy_err(wiphy, "cannot register virtual network device\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot register virtual network device\n");
free_netdev(dev);
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
priv->netdev = NULL;
@@ -2613,7 +2722,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
WQ_MEM_RECLAIM |
WQ_UNBOUND, 1, name);
if (!priv->dfs_cac_workqueue) {
- wiphy_err(wiphy, "cannot register virtual network device\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot register virtual network device\n");
free_netdev(dev);
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
priv->netdev = NULL;
@@ -2628,7 +2738,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
WQ_HIGHPRI | WQ_UNBOUND |
WQ_MEM_RECLAIM, 1, name);
if (!priv->dfs_chan_sw_workqueue) {
- wiphy_err(wiphy, "cannot register virtual network device\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot register virtual network device\n");
free_netdev(dev);
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
priv->netdev = NULL;
@@ -2642,7 +2753,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
sema_init(&priv->async_sem, 1);
- dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: Marvell 802.11 Adapter\n", dev->name);
#ifdef CONFIG_DEBUG_FS
mwifiex_dev_debugfs_init(priv);
@@ -2661,7 +2773,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
adapter->curr_iface_comb.p2p_intf++;
break;
default:
- wiphy_err(wiphy, "type not supported\n");
+ mwifiex_dbg(adapter, ERROR, "type not supported\n");
return ERR_PTR(-EINVAL);
}
@@ -2721,7 +2833,8 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
adapter->curr_iface_comb.p2p_intf++;
break;
default:
- dev_err(adapter->dev, "del_virtual_intf: type not supported\n");
+ mwifiex_dbg(adapter, ERROR,
+ "del_virtual_intf: type not supported\n");
break;
}
@@ -2839,7 +2952,8 @@ static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv,
if (!mwifiex_is_pattern_supported(&wowlan->patterns[i],
byte_seq,
MWIFIEX_MEF_MAX_BYTESEQ)) {
- dev_err(priv->adapter->dev, "Pattern not supported\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Pattern not supported\n");
kfree(mef_entry);
return -EOPNOTSUPP;
}
@@ -2954,21 +3068,22 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
mwifiex_cancel_all_pending_cmd(adapter);
if (!wowlan) {
- dev_warn(adapter->dev, "None of the WOWLAN triggers enabled\n");
+ mwifiex_dbg(adapter, ERROR,
+ "None of the WOWLAN triggers enabled\n");
return 0;
}
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
if (!priv->media_connected) {
- dev_warn(adapter->dev,
- "Can not configure WOWLAN in disconnected state\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Can not configure WOWLAN in disconnected state\n");
return 0;
}
ret = mwifiex_set_mef_filter(priv, wowlan);
if (ret) {
- dev_err(adapter->dev, "Failed to set MEF filter\n");
+ mwifiex_dbg(adapter, ERROR, "Failed to set MEF filter\n");
return ret;
}
@@ -2981,7 +3096,8 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
MWIFIEX_SYNC_CMD, &hs_cfg);
if (ret) {
- dev_err(adapter->dev, "Failed to set HS params\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to set HS params\n");
return ret;
}
}
@@ -3041,7 +3157,8 @@ mwifiex_fill_coalesce_rule_info(struct mwifiex_private *priv,
if (!mwifiex_is_pattern_supported(&crule->patterns[i],
byte_seq,
MWIFIEX_COALESCE_MAX_BYTESEQ)) {
- dev_err(priv->adapter->dev, "Pattern not supported\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Pattern not supported\n");
return -EOPNOTSUPP;
}
@@ -3050,8 +3167,8 @@ mwifiex_fill_coalesce_rule_info(struct mwifiex_private *priv,
pkt_type = mwifiex_get_coalesce_pkt_type(byte_seq);
if (pkt_type && mrule->pkt_type) {
- dev_err(priv->adapter->dev,
- "Multiple packet types not allowed\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Multiple packet types not allowed\n");
return -EOPNOTSUPP;
} else if (pkt_type) {
mrule->pkt_type = pkt_type;
@@ -3074,8 +3191,8 @@ mwifiex_fill_coalesce_rule_info(struct mwifiex_private *priv,
}
if (!mrule->pkt_type) {
- dev_err(priv->adapter->dev,
- "Packet type can not be determined\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Packet type can not be determined\n");
return -EOPNOTSUPP;
}
@@ -3093,8 +3210,8 @@ static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy,
memset(&coalesce_cfg, 0, sizeof(coalesce_cfg));
if (!coalesce) {
- dev_dbg(adapter->dev,
- "Disable coalesce and reset all previous rules\n");
+ mwifiex_dbg(adapter, WARN,
+ "Disable coalesce and reset all previous rules\n");
return mwifiex_send_cmd(priv, HostCmd_CMD_COALESCE_CFG,
HostCmd_ACT_GEN_SET, 0,
&coalesce_cfg, true);
@@ -3105,8 +3222,8 @@ static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy,
ret = mwifiex_fill_coalesce_rule_info(priv, &coalesce->rules[i],
&coalesce_cfg.rule[i]);
if (ret) {
- dev_err(priv->adapter->dev,
- "Recheck the patterns provided for rule %d\n",
+ mwifiex_dbg(adapter, ERROR,
+ "Recheck the patterns provided for rule %d\n",
i + 1);
return ret;
}
@@ -3138,9 +3255,9 @@ mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
switch (action_code) {
case WLAN_TDLS_SETUP_REQUEST:
- dev_dbg(priv->adapter->dev,
- "Send TDLS Setup Request to %pM status_code=%d\n", peer,
- status_code);
+ mwifiex_dbg(priv->adapter, MSG,
+ "Send TDLS Setup Request to %pM status_code=%d\n",
+ peer, status_code);
mwifiex_add_auto_tdls_peer(priv, peer);
ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
dialog_token, status_code,
@@ -3148,45 +3265,45 @@ mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
break;
case WLAN_TDLS_SETUP_RESPONSE:
mwifiex_add_auto_tdls_peer(priv, peer);
- dev_dbg(priv->adapter->dev,
- "Send TDLS Setup Response to %pM status_code=%d\n",
- peer, status_code);
+ mwifiex_dbg(priv->adapter, MSG,
+ "Send TDLS Setup Response to %pM status_code=%d\n",
+ peer, status_code);
ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
dialog_token, status_code,
extra_ies, extra_ies_len);
break;
case WLAN_TDLS_SETUP_CONFIRM:
- dev_dbg(priv->adapter->dev,
- "Send TDLS Confirm to %pM status_code=%d\n", peer,
- status_code);
+ mwifiex_dbg(priv->adapter, MSG,
+ "Send TDLS Confirm to %pM status_code=%d\n", peer,
+ status_code);
ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
dialog_token, status_code,
extra_ies, extra_ies_len);
break;
case WLAN_TDLS_TEARDOWN:
- dev_dbg(priv->adapter->dev, "Send TDLS Tear down to %pM\n",
- peer);
+ mwifiex_dbg(priv->adapter, MSG,
+ "Send TDLS Tear down to %pM\n", peer);
ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
dialog_token, status_code,
extra_ies, extra_ies_len);
break;
case WLAN_TDLS_DISCOVERY_REQUEST:
- dev_dbg(priv->adapter->dev,
- "Send TDLS Discovery Request to %pM\n", peer);
+ mwifiex_dbg(priv->adapter, MSG,
+ "Send TDLS Discovery Request to %pM\n", peer);
ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
dialog_token, status_code,
extra_ies, extra_ies_len);
break;
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
- dev_dbg(priv->adapter->dev,
- "Send TDLS Discovery Response to %pM\n", peer);
+ mwifiex_dbg(priv->adapter, MSG,
+ "Send TDLS Discovery Response to %pM\n", peer);
ret = mwifiex_send_tdls_action_frame(priv, peer, action_code,
dialog_token, status_code,
extra_ies, extra_ies_len);
break;
default:
- dev_warn(priv->adapter->dev,
- "Unknown TDLS mgmt/action frame %pM\n", peer);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Unknown TDLS mgmt/action frame %pM\n", peer);
ret = -EINVAL;
break;
}
@@ -3208,8 +3325,8 @@ mwifiex_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected))
return -ENOTSUPP;
- dev_dbg(priv->adapter->dev,
- "TDLS peer=%pM, oper=%d\n", peer, action);
+ mwifiex_dbg(priv->adapter, MSG,
+ "TDLS peer=%pM, oper=%d\n", peer, action);
switch (action) {
case NL80211_TDLS_ENABLE_LINK:
@@ -3220,22 +3337,22 @@ mwifiex_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
break;
case NL80211_TDLS_TEARDOWN:
/* shouldn't happen!*/
- dev_warn(priv->adapter->dev,
- "tdls_oper: teardown from driver not supported\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "tdls_oper: teardown from driver not supported\n");
return -EINVAL;
case NL80211_TDLS_SETUP:
/* shouldn't happen!*/
- dev_warn(priv->adapter->dev,
- "tdls_oper: setup from driver not supported\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "tdls_oper: setup from driver not supported\n");
return -EINVAL;
case NL80211_TDLS_DISCOVERY_REQ:
/* shouldn't happen!*/
- dev_warn(priv->adapter->dev,
- "tdls_oper: discovery from driver not supported\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "tdls_oper: discovery from driver not supported\n");
return -EINVAL;
default:
- dev_err(priv->adapter->dev,
- "tdls_oper: operation not supported\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "tdls_oper: operation not supported\n");
return -ENOTSUPP;
}
@@ -3268,8 +3385,8 @@ mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (priv->adapter->scan_processing) {
- dev_err(priv->adapter->dev,
- "radar detection: scan in process...\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "radar detection: scan in process...\n");
return -EBUSY;
}
@@ -3284,8 +3401,8 @@ mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
params->beacon_csa.tail,
params->beacon_csa.tail_len);
if (!chsw_ie) {
- dev_err(priv->adapter->dev,
- "Could not parse channel switch announcement IE\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Could not parse channel switch announcement IE\n");
return -EINVAL;
}
@@ -3297,10 +3414,12 @@ mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
}
if (mwifiex_del_mgmt_ies(priv))
- wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to delete mgmt IEs!\n");
if (mwifiex_set_mgmt_ies(priv, &params->beacon_csa)) {
- wiphy_err(wiphy, "%s: setting mgmt ies failed\n", __func__);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: setting mgmt ies failed\n", __func__);
return -EFAULT;
}
@@ -3314,6 +3433,45 @@ mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
+static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct cfg80211_chan_def *chandef)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
+ struct mwifiex_bssdescriptor *curr_bss;
+ struct ieee80211_channel *chan;
+ u8 second_chan_offset;
+ enum nl80211_channel_type chan_type;
+ enum ieee80211_band band;
+ int freq;
+ int ret = -ENODATA;
+
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP &&
+ cfg80211_chandef_valid(&priv->bss_chandef)) {
+ *chandef = priv->bss_chandef;
+ ret = 0;
+ } else if (priv->media_connected) {
+ curr_bss = &priv->curr_bss_params.bss_descriptor;
+ band = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
+ freq = ieee80211_channel_to_frequency(curr_bss->channel, band);
+ chan = ieee80211_get_channel(wiphy, freq);
+
+ if (curr_bss->bcn_ht_oper) {
+ second_chan_offset = curr_bss->bcn_ht_oper->ht_param &
+ IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
+ chan_type = mwifiex_sec_chan_offset_to_chan_type
+ (second_chan_offset);
+ cfg80211_chandef_create(chandef, chan, chan_type);
+ } else {
+ cfg80211_chandef_create(chandef, chan,
+ NL80211_CHAN_NO_HT);
+ }
+ ret = 0;
+ }
+
+ return ret;
+}
+
static int
mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy,
struct net_device *dev,
@@ -3324,16 +3482,17 @@ mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy,
struct mwifiex_radar_params radar_params;
if (priv->adapter->scan_processing) {
- dev_err(priv->adapter->dev,
- "radar detection: scan already in process...\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "radar detection: scan already in process...\n");
return -EBUSY;
}
if (!mwifiex_is_11h_active(priv)) {
- dev_dbg(priv->adapter->dev, "Enable 11h extensions in FW\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "Enable 11h extensions in FW\n");
if (mwifiex_11h_activate(priv, true)) {
- dev_err(priv->adapter->dev,
- "Failed to activate 11h extensions!!");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to activate 11h extensions!!");
return -1;
}
priv->state_11h.is_11h_active = true;
@@ -3418,6 +3577,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.tdls_oper = mwifiex_cfg80211_tdls_oper,
.add_station = mwifiex_cfg80211_add_station,
.change_station = mwifiex_cfg80211_change_station,
+ .get_channel = mwifiex_cfg80211_get_channel,
.start_radar_detection = mwifiex_cfg80211_start_radar_detection,
.channel_switch = mwifiex_cfg80211_channel_switch,
};
@@ -3492,7 +3652,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy = wiphy_new(&mwifiex_cfg80211_ops,
sizeof(struct mwifiex_adapter *));
if (!wiphy) {
- dev_err(adapter->dev, "%s: creating new wiphy\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: creating new wiphy\n", __func__);
return -ENOMEM;
}
wiphy->max_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH;
@@ -3524,7 +3685,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
- WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+ WIPHY_FLAG_HAS_CHANNEL_SWITCH |
+ WIPHY_FLAG_PS_ON_BY_DEFAULT;
if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info))
wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
@@ -3563,20 +3725,22 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
ret = wiphy_register(wiphy);
if (ret < 0) {
- dev_err(adapter->dev,
- "%s: wiphy_register failed: %d\n", __func__, ret);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: wiphy_register failed: %d\n", __func__, ret);
wiphy_free(wiphy);
return ret;
}
if (reg_alpha2 && mwifiex_is_valid_alpha2(reg_alpha2)) {
- wiphy_info(wiphy, "driver hint alpha2: %2.2s\n", reg_alpha2);
+ mwifiex_dbg(adapter, INFO,
+ "driver hint alpha2: %2.2s\n", reg_alpha2);
regulatory_hint(wiphy, reg_alpha2);
} else {
country_code = mwifiex_11d_code_2_region(adapter->region_code);
if (country_code)
- wiphy_info(wiphy, "ignoring F/W country code %2.2s\n",
- country_code);
+ mwifiex_dbg(adapter, WARN,
+ "ignoring F/W country code %2.2s\n",
+ country_code);
}
mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c
index e9df8826f124..3ddb8ec676ed 100644
--- a/drivers/net/wireless/mwifiex/cfp.c
+++ b/drivers/net/wireless/mwifiex/cfp.c
@@ -327,8 +327,9 @@ mwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq)
sband = priv->wdev.wiphy->bands[IEEE80211_BAND_5GHZ];
if (!sband) {
- dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d\n",
- __func__, band);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: cannot find cfp by band %d\n",
+ __func__, band);
return cfp;
}
@@ -349,9 +350,10 @@ mwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq)
}
}
if (i == sband->n_channels) {
- dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
- " & channel=%d freq=%d\n", __func__, band, channel,
- freq);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: cannot find cfp by band %d\t"
+ "& channel=%d freq=%d\n",
+ __func__, band, channel, freq);
} else {
if (!ch)
return cfp;
@@ -431,15 +433,17 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
switch (adapter->config_bands) {
case BAND_B:
- dev_dbg(adapter->dev, "info: infra band=%d "
- "supported_rates_b\n", adapter->config_bands);
+ mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
+ "supported_rates_b\n",
+ adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_b,
sizeof(supported_rates_b));
break;
case BAND_G:
case BAND_G | BAND_GN:
- dev_dbg(adapter->dev, "info: infra band=%d "
- "supported_rates_g\n", adapter->config_bands);
+ mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
+ "supported_rates_g\n",
+ adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_g,
sizeof(supported_rates_g));
break;
@@ -449,15 +453,17 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN | BAND_AAC:
case BAND_B | BAND_G | BAND_GN:
- dev_dbg(adapter->dev, "info: infra band=%d "
- "supported_rates_bg\n", adapter->config_bands);
+ mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
+ "supported_rates_bg\n",
+ adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_bg,
sizeof(supported_rates_bg));
break;
case BAND_A:
case BAND_A | BAND_G:
- dev_dbg(adapter->dev, "info: infra band=%d "
- "supported_rates_a\n", adapter->config_bands);
+ mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
+ "supported_rates_a\n",
+ adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_a,
sizeof(supported_rates_a));
break;
@@ -466,14 +472,16 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
case BAND_A | BAND_AN | BAND_AAC:
case BAND_A | BAND_G | BAND_AN | BAND_GN:
case BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC:
- dev_dbg(adapter->dev, "info: infra band=%d "
- "supported_rates_a\n", adapter->config_bands);
+ mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
+ "supported_rates_a\n",
+ adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_a,
sizeof(supported_rates_a));
break;
case BAND_GN:
- dev_dbg(adapter->dev, "info: infra band=%d "
- "supported_rates_n\n", adapter->config_bands);
+ mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
+ "supported_rates_n\n",
+ adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_n,
sizeof(supported_rates_n));
break;
@@ -482,25 +490,25 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
/* Ad-hoc mode */
switch (adapter->adhoc_start_band) {
case BAND_B:
- dev_dbg(adapter->dev, "info: adhoc B\n");
+ mwifiex_dbg(adapter, INFO, "info: adhoc B\n");
k = mwifiex_copy_rates(rates, k, adhoc_rates_b,
sizeof(adhoc_rates_b));
break;
case BAND_G:
case BAND_G | BAND_GN:
- dev_dbg(adapter->dev, "info: adhoc G only\n");
+ mwifiex_dbg(adapter, INFO, "info: adhoc G only\n");
k = mwifiex_copy_rates(rates, k, adhoc_rates_g,
sizeof(adhoc_rates_g));
break;
case BAND_B | BAND_G:
case BAND_B | BAND_G | BAND_GN:
- dev_dbg(adapter->dev, "info: adhoc BG\n");
+ mwifiex_dbg(adapter, INFO, "info: adhoc BG\n");
k = mwifiex_copy_rates(rates, k, adhoc_rates_bg,
sizeof(adhoc_rates_bg));
break;
case BAND_A:
case BAND_A | BAND_AN:
- dev_dbg(adapter->dev, "info: adhoc A\n");
+ mwifiex_dbg(adapter, INFO, "info: adhoc A\n");
k = mwifiex_copy_rates(rates, k, adhoc_rates_a,
sizeof(adhoc_rates_a));
break;
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index c5a14ff7eb82..207da40500f4 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -62,7 +62,8 @@ mwifiex_get_cmd_node(struct mwifiex_adapter *adapter)
spin_lock_irqsave(&adapter->cmd_free_q_lock, flags);
if (list_empty(&adapter->cmd_free_q)) {
- dev_err(adapter->dev, "GET_CMD_NODE: cmd node not available\n");
+ mwifiex_dbg(adapter, ERROR,
+ "GET_CMD_NODE: cmd node not available\n");
spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
return NULL;
}
@@ -116,7 +117,8 @@ static int mwifiex_cmd_host_cmd(struct mwifiex_private *priv,
{
/* Copy the HOST command to command buffer */
memcpy(cmd, pcmd_ptr->cmd, pcmd_ptr->len);
- dev_dbg(priv->adapter->dev, "cmd: host cmd size = %d\n", pcmd_ptr->len);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: host cmd size = %d\n", pcmd_ptr->len);
return 0;
}
@@ -147,8 +149,9 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
/* Sanity test */
if (host_cmd == NULL || host_cmd->size == 0) {
- dev_err(adapter->dev, "DNLD_CMD: host_cmd is null"
- " or cmd size is 0, not sending\n");
+ mwifiex_dbg(adapter, ERROR,
+ "DNLD_CMD: host_cmd is null\t"
+ "or cmd size is 0, not sending\n");
if (cmd_node->wait_q_enabled)
adapter->cmd_wait_q.status = -1;
mwifiex_recycle_cmd_node(adapter, cmd_node);
@@ -161,8 +164,8 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET &&
cmd_code != HostCmd_CMD_FUNC_SHUTDOWN &&
cmd_code != HostCmd_CMD_FUNC_INIT) {
- dev_err(adapter->dev,
- "DNLD_CMD: FW in reset state, ignore cmd %#x\n",
+ mwifiex_dbg(adapter, ERROR,
+ "DNLD_CMD: FW in reset state, ignore cmd %#x\n",
cmd_code);
if (cmd_node->wait_q_enabled)
mwifiex_complete_cmd(adapter, cmd_node);
@@ -197,10 +200,12 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
*/
skb_put(cmd_node->cmd_skb, cmd_size - cmd_node->cmd_skb->len);
- dev_dbg(adapter->dev,
- "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n", cmd_code,
- le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)), cmd_size,
- le16_to_cpu(host_cmd->seq_num));
+ mwifiex_dbg(adapter, CMD,
+ "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n",
+ cmd_code,
+ le16_to_cpu(*(__le16 *)((u8 *)host_cmd + S_DS_GEN)),
+ cmd_size, le16_to_cpu(host_cmd->seq_num));
+ mwifiex_dbg_dump(adapter, CMD_D, "cmd buffer:", host_cmd, cmd_size);
if (adapter->iface_type == MWIFIEX_USB) {
tmp = cpu_to_le32(MWIFIEX_USB_TYPE_CMD);
@@ -221,7 +226,8 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
}
if (ret == -1) {
- dev_err(adapter->dev, "DNLD_CMD: host to card failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "DNLD_CMD: host to card failed\n");
if (adapter->iface_type == MWIFIEX_USB)
adapter->cmd_sent = false;
if (cmd_node->wait_q_enabled)
@@ -280,12 +286,14 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
(adapter->seq_num, priv->bss_num,
priv->bss_type)));
- dev_dbg(adapter->dev,
- "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n",
+ mwifiex_dbg(adapter, CMD,
+ "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n",
le16_to_cpu(sleep_cfm_buf->command),
le16_to_cpu(sleep_cfm_buf->action),
le16_to_cpu(sleep_cfm_buf->size),
le16_to_cpu(sleep_cfm_buf->seq_num));
+ mwifiex_dbg_dump(adapter, CMD_D, "SLEEP_CFM buffer: ", sleep_cfm_buf,
+ le16_to_cpu(sleep_cfm_buf->size));
if (adapter->iface_type == MWIFIEX_USB) {
sleep_cfm_tmp =
@@ -311,7 +319,7 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
}
if (ret == -1) {
- dev_err(adapter->dev, "SLEEP_CFM: failed\n");
+ mwifiex_dbg(adapter, ERROR, "SLEEP_CFM: failed\n");
adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
return -1;
}
@@ -362,8 +370,9 @@ int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter)
for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) {
cmd_array[i].skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER);
if (!cmd_array[i].skb) {
- dev_err(adapter->dev, "ALLOC_CMD_BUF: out of memory\n");
- return -1;
+ mwifiex_dbg(adapter, ERROR,
+ "unable to allocate command buffer\n");
+ return -ENOMEM;
}
}
@@ -386,7 +395,8 @@ int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter)
/* Need to check if cmd pool is allocated or not */
if (!adapter->cmd_pool) {
- dev_dbg(adapter->dev, "info: FREE_CMD_BUF: cmd_pool is null\n");
+ mwifiex_dbg(adapter, FATAL,
+ "info: FREE_CMD_BUF: cmd_pool is null\n");
return 0;
}
@@ -395,7 +405,8 @@ int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter)
/* Release shared memory buffers */
for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) {
if (cmd_array[i].skb) {
- dev_dbg(adapter->dev, "cmd: free cmd buffer %d\n", i);
+ mwifiex_dbg(adapter, CMD,
+ "cmd: free cmd buffer %d\n", i);
dev_kfree_skb_any(cmd_array[i].skb);
}
if (!cmd_array[i].resp_skb)
@@ -409,7 +420,8 @@ int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter)
}
/* Release struct cmd_ctrl_node */
if (adapter->cmd_pool) {
- dev_dbg(adapter->dev, "cmd: free cmd pool\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: free cmd pool\n");
kfree(adapter->cmd_pool);
adapter->cmd_pool = NULL;
}
@@ -457,9 +469,11 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
memset(rx_info, 0, sizeof(*rx_info));
rx_info->bss_num = priv->bss_num;
rx_info->bss_type = priv->bss_type;
+ mwifiex_dbg_dump(adapter, EVT_D, "Event Buf:",
+ skb->data, skb->len);
}
- dev_dbg(adapter->dev, "EVENT: cause: %#x\n", eventcause);
+ mwifiex_dbg(adapter, EVENT, "EVENT: cause: %#x\n", eventcause);
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
ret = mwifiex_process_uap_event(priv);
@@ -498,28 +512,33 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
}
if (adapter->is_suspended) {
- dev_err(adapter->dev, "PREP_CMD: device in suspended state\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: device in suspended state\n");
return -1;
}
if (adapter->hs_enabling && cmd_no != HostCmd_CMD_802_11_HS_CFG_ENH) {
- dev_err(adapter->dev, "PREP_CMD: host entering sleep state\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: host entering sleep state\n");
return -1;
}
if (adapter->surprise_removed) {
- dev_err(adapter->dev, "PREP_CMD: card is removed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: card is removed\n");
return -1;
}
if (adapter->is_cmd_timedout) {
- dev_err(adapter->dev, "PREP_CMD: FW is in bad state\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: FW is in bad state\n");
return -1;
}
if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) {
if (cmd_no != HostCmd_CMD_FUNC_INIT) {
- dev_err(adapter->dev, "PREP_CMD: FW in reset state\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: FW in reset state\n");
return -1;
}
}
@@ -528,7 +547,8 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
cmd_node = mwifiex_get_cmd_node(adapter);
if (!cmd_node) {
- dev_err(adapter->dev, "PREP_CMD: no free cmd node\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: no free cmd node\n");
return -1;
}
@@ -536,7 +556,8 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf, sync);
if (!cmd_node->cmd_skb) {
- dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: no free cmd buf\n");
return -1;
}
@@ -554,6 +575,8 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
case HostCmd_CMD_UAP_BSS_START:
case HostCmd_CMD_UAP_BSS_STOP:
case HostCmd_CMD_UAP_STA_DEAUTH:
+ case HOST_CMD_APCMD_SYS_RESET:
+ case HOST_CMD_APCMD_STA_LIST:
ret = mwifiex_uap_prepare_cmd(priv, cmd_no, cmd_action,
cmd_oid, data_buf,
cmd_ptr);
@@ -571,7 +594,8 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
/* Return error, since the command preparation failed */
if (ret) {
- dev_err(adapter->dev, "PREP_CMD: cmd %#x preparation failed\n",
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: cmd %#x preparation failed\n",
cmd_no);
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
return -1;
@@ -626,7 +650,8 @@ void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter,
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
atomic_dec(&adapter->cmd_pending);
- dev_dbg(adapter->dev, "cmd: FREE_CMD: cmd=%#x, cmd_pending=%d\n",
+ mwifiex_dbg(adapter, CMD,
+ "cmd: FREE_CMD: cmd=%#x, cmd_pending=%d\n",
le16_to_cpu(host_cmd->command),
atomic_read(&adapter->cmd_pending));
}
@@ -648,7 +673,7 @@ mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
if (!host_cmd) {
- dev_err(adapter->dev, "QUEUE_CMD: host_cmd is NULL\n");
+ mwifiex_dbg(adapter, ERROR, "QUEUE_CMD: host_cmd is NULL\n");
return;
}
@@ -673,7 +698,8 @@ mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
atomic_inc(&adapter->cmd_pending);
- dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x, cmd_pending=%d\n",
+ mwifiex_dbg(adapter, CMD,
+ "cmd: QUEUE_CMD: cmd=%#x, cmd_pending=%d\n",
command, atomic_read(&adapter->cmd_pending));
}
@@ -699,7 +725,8 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
/* Check if already in processing */
if (adapter->curr_cmd) {
- dev_err(adapter->dev, "EXEC_NEXT_CMD: cmd in processing\n");
+ mwifiex_dbg(adapter, FATAL,
+ "EXEC_NEXT_CMD: cmd in processing\n");
return -1;
}
@@ -721,8 +748,9 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
priv = cmd_node->priv;
if (adapter->ps_state != PS_STATE_AWAKE) {
- dev_err(adapter->dev, "%s: cannot send cmd in sleep state,"
- " this should not happen\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: cannot send cmd in sleep state,\t"
+ "this should not happen\n", __func__);
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
return ret;
}
@@ -772,8 +800,9 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) {
resp = (struct host_cmd_ds_command *) adapter->upld_buf;
- dev_err(adapter->dev, "CMD_RESP: NULL curr_cmd, %#x\n",
- le16_to_cpu(resp->command));
+ mwifiex_dbg(adapter, ERROR,
+ "CMD_RESP: NULL curr_cmd, %#x\n",
+ le16_to_cpu(resp->command));
return -1;
}
@@ -781,8 +810,9 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data;
if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
- dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n",
- le16_to_cpu(resp->command));
+ mwifiex_dbg(adapter, ERROR,
+ "CMD_RESP: %#x been canceled\n",
+ le16_to_cpu(resp->command));
mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL;
@@ -794,7 +824,8 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
/* Copy original response back to response buffer */
struct mwifiex_ds_misc_cmd *hostcmd;
uint16_t size = le16_to_cpu(resp->size);
- dev_dbg(adapter->dev, "info: host cmd resp size = %d\n", size);
+ mwifiex_dbg(adapter, INFO,
+ "info: host cmd resp size = %d\n", size);
size = min_t(u16, size, MWIFIEX_SIZE_OF_CMD_BUFFER);
if (adapter->curr_cmd->data_buf) {
hostcmd = adapter->curr_cmd->data_buf;
@@ -822,13 +853,15 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
adapter->dbg.last_cmd_resp_id[adapter->dbg.last_cmd_resp_index] =
orig_cmdresp_no;
- dev_dbg(adapter->dev,
- "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n",
- orig_cmdresp_no, cmdresp_result,
- le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num));
+ mwifiex_dbg(adapter, CMD,
+ "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n",
+ orig_cmdresp_no, cmdresp_result,
+ le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num));
+ mwifiex_dbg_dump(adapter, CMD_D, "CMD_RESP buffer:", resp,
+ le16_to_cpu(resp->size));
if (!(orig_cmdresp_no & HostCmd_RET_BIT)) {
- dev_err(adapter->dev, "CMD_RESP: invalid cmd resp\n");
+ mwifiex_dbg(adapter, ERROR, "CMD_RESP: invalid cmd resp\n");
if (adapter->curr_cmd->wait_q_enabled)
adapter->cmd_wait_q.status = -1;
@@ -852,8 +885,9 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
/* Check init command response */
if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) {
if (ret) {
- dev_err(adapter->dev, "%s: cmd %#x failed during "
- "initialization\n", __func__, cmdresp_no);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: cmd %#x failed during\t"
+ "initialization\n", __func__, cmdresp_no);
mwifiex_init_fw_complete(adapter);
return -1;
} else if (adapter->last_init_cmd == cmdresp_no)
@@ -888,7 +922,8 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
adapter->is_cmd_timedout = 1;
if (!adapter->curr_cmd) {
- dev_dbg(adapter->dev, "cmd: empty curr_cmd\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cmd: empty curr_cmd\n");
return;
}
cmd_node = adapter->curr_cmd;
@@ -897,47 +932,60 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index];
adapter->dbg.timeout_cmd_act =
adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index];
- dev_err(adapter->dev,
- "%s: Timeout cmd id = %#x, act = %#x\n", __func__,
- adapter->dbg.timeout_cmd_id,
- adapter->dbg.timeout_cmd_act);
-
- dev_err(adapter->dev, "num_data_h2c_failure = %d\n",
- adapter->dbg.num_tx_host_to_card_failure);
- dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n",
- adapter->dbg.num_cmd_host_to_card_failure);
-
- dev_err(adapter->dev, "is_cmd_timedout = %d\n",
- adapter->is_cmd_timedout);
- dev_err(adapter->dev, "num_tx_timeout = %d\n",
- adapter->dbg.num_tx_timeout);
-
- dev_err(adapter->dev, "last_cmd_index = %d\n",
- adapter->dbg.last_cmd_index);
- dev_err(adapter->dev, "last_cmd_id: %*ph\n",
- (int)sizeof(adapter->dbg.last_cmd_id),
- adapter->dbg.last_cmd_id);
- dev_err(adapter->dev, "last_cmd_act: %*ph\n",
- (int)sizeof(adapter->dbg.last_cmd_act),
- adapter->dbg.last_cmd_act);
-
- dev_err(adapter->dev, "last_cmd_resp_index = %d\n",
- adapter->dbg.last_cmd_resp_index);
- dev_err(adapter->dev, "last_cmd_resp_id: %*ph\n",
- (int)sizeof(adapter->dbg.last_cmd_resp_id),
- adapter->dbg.last_cmd_resp_id);
-
- dev_err(adapter->dev, "last_event_index = %d\n",
- adapter->dbg.last_event_index);
- dev_err(adapter->dev, "last_event: %*ph\n",
- (int)sizeof(adapter->dbg.last_event),
- adapter->dbg.last_event);
-
- dev_err(adapter->dev, "data_sent=%d cmd_sent=%d\n",
- adapter->data_sent, adapter->cmd_sent);
-
- dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n",
- adapter->ps_mode, adapter->ps_state);
+ mwifiex_dbg(adapter, MSG,
+ "%s: Timeout cmd id = %#x, act = %#x\n", __func__,
+ adapter->dbg.timeout_cmd_id,
+ adapter->dbg.timeout_cmd_act);
+
+ mwifiex_dbg(adapter, MSG,
+ "num_data_h2c_failure = %d\n",
+ adapter->dbg.num_tx_host_to_card_failure);
+ mwifiex_dbg(adapter, MSG,
+ "num_cmd_h2c_failure = %d\n",
+ adapter->dbg.num_cmd_host_to_card_failure);
+
+ mwifiex_dbg(adapter, MSG,
+ "is_cmd_timedout = %d\n",
+ adapter->is_cmd_timedout);
+ mwifiex_dbg(adapter, MSG,
+ "num_tx_timeout = %d\n",
+ adapter->dbg.num_tx_timeout);
+
+ mwifiex_dbg(adapter, MSG,
+ "last_cmd_index = %d\n",
+ adapter->dbg.last_cmd_index);
+ mwifiex_dbg(adapter, MSG,
+ "last_cmd_id: %*ph\n",
+ (int)sizeof(adapter->dbg.last_cmd_id),
+ adapter->dbg.last_cmd_id);
+ mwifiex_dbg(adapter, MSG,
+ "last_cmd_act: %*ph\n",
+ (int)sizeof(adapter->dbg.last_cmd_act),
+ adapter->dbg.last_cmd_act);
+
+ mwifiex_dbg(adapter, MSG,
+ "last_cmd_resp_index = %d\n",
+ adapter->dbg.last_cmd_resp_index);
+ mwifiex_dbg(adapter, MSG,
+ "last_cmd_resp_id: %*ph\n",
+ (int)sizeof(adapter->dbg.last_cmd_resp_id),
+ adapter->dbg.last_cmd_resp_id);
+
+ mwifiex_dbg(adapter, MSG,
+ "last_event_index = %d\n",
+ adapter->dbg.last_event_index);
+ mwifiex_dbg(adapter, MSG,
+ "last_event: %*ph\n",
+ (int)sizeof(adapter->dbg.last_event),
+ adapter->dbg.last_event);
+
+ mwifiex_dbg(adapter, MSG,
+ "data_sent=%d cmd_sent=%d\n",
+ adapter->data_sent, adapter->cmd_sent);
+
+ mwifiex_dbg(adapter, MSG,
+ "ps_mode=%d ps_state=%d\n",
+ adapter->ps_mode, adapter->ps_state);
if (cmd_node->wait_q_enabled) {
adapter->cmd_wait_q.status = -ETIMEDOUT;
@@ -948,8 +996,8 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
mwifiex_init_fw_complete(adapter);
- if (adapter->if_ops.fw_dump)
- adapter->if_ops.fw_dump(adapter);
+ if (adapter->if_ops.device_dump)
+ adapter->if_ops.device_dump(adapter);
if (adapter->if_ops.card_reset)
adapter->if_ops.card_reset(adapter);
@@ -1015,7 +1063,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
if (!priv)
continue;
if (priv->scan_request) {
- dev_dbg(adapter->dev, "info: aborting scan\n");
+ mwifiex_dbg(adapter, WARN, "info: aborting scan\n");
cfg80211_scan_done(priv->scan_request, 1);
priv->scan_request = NULL;
}
@@ -1075,7 +1123,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
if (!priv)
continue;
if (priv->scan_request) {
- dev_dbg(adapter->dev, "info: aborting scan\n");
+ mwifiex_dbg(adapter, WARN, "info: aborting scan\n");
cfg80211_scan_done(priv->scan_request, 1);
priv->scan_request = NULL;
}
@@ -1100,11 +1148,11 @@ mwifiex_check_ps_cond(struct mwifiex_adapter *adapter)
!adapter->curr_cmd && !IS_CARD_RX_RCVD(adapter))
mwifiex_dnld_sleep_confirm_cmd(adapter);
else
- dev_dbg(adapter->dev,
- "cmd: Delay Sleep Confirm (%s%s%s)\n",
- (adapter->cmd_sent) ? "D" : "",
- (adapter->curr_cmd) ? "C" : "",
- (IS_CARD_RX_RCVD(adapter)) ? "R" : "");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: Delay Sleep Confirm (%s%s%s)\n",
+ (adapter->cmd_sent) ? "D" : "",
+ (adapter->curr_cmd) ? "C" : "",
+ (IS_CARD_RX_RCVD(adapter)) ? "R" : "");
}
/*
@@ -1120,15 +1168,18 @@ mwifiex_hs_activated_event(struct mwifiex_private *priv, u8 activated)
priv->adapter->hs_activated = true;
mwifiex_update_rxreor_flags(priv->adapter,
RXREOR_FORCE_NO_DROP);
- dev_dbg(priv->adapter->dev, "event: hs_activated\n");
+ mwifiex_dbg(priv->adapter, EVENT,
+ "event: hs_activated\n");
priv->adapter->hs_activate_wait_q_woken = true;
wake_up_interruptible(
&priv->adapter->hs_activate_wait_q);
} else {
- dev_dbg(priv->adapter->dev, "event: HS not configured\n");
+ mwifiex_dbg(priv->adapter, EVENT,
+ "event: HS not configured\n");
}
} else {
- dev_dbg(priv->adapter->dev, "event: hs_deactivated\n");
+ mwifiex_dbg(priv->adapter, EVENT,
+ "event: hs_deactivated\n");
priv->adapter->hs_activated = false;
}
}
@@ -1156,11 +1207,12 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
mwifiex_hs_activated_event(priv, true);
return 0;
} else {
- dev_dbg(adapter->dev, "cmd: CMD_RESP: HS_CFG cmd reply"
- " result=%#x, conditions=0x%x gpio=0x%x gap=0x%x\n",
- resp->result, conditions,
- phs_cfg->params.hs_config.gpio,
- phs_cfg->params.hs_config.gap);
+ mwifiex_dbg(adapter, CMD,
+ "cmd: CMD_RESP: HS_CFG cmd reply\t"
+ " result=%#x, conditions=0x%x gpio=0x%x gap=0x%x\n",
+ resp->result, conditions,
+ phs_cfg->params.hs_config.gpio,
+ phs_cfg->params.hs_config.gap);
}
if (conditions != HS_CFG_CANCEL) {
adapter->is_hs_configured = true;
@@ -1182,8 +1234,10 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
void
mwifiex_process_hs_config(struct mwifiex_adapter *adapter)
{
- dev_dbg(adapter->dev, "info: %s: auto cancelling host sleep"
- " since there is interrupt from the firmware\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: auto cancelling host sleep\t"
+ "since there is interrupt from the firmware\n",
+ __func__);
adapter->if_ops.wakeup(adapter);
adapter->hs_activated = false;
@@ -1212,13 +1266,14 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter,
uint16_t seq_num = le16_to_cpu(cmd->seq_num);
if (!upld_len) {
- dev_err(adapter->dev, "%s: cmd size is 0\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: cmd size is 0\n", __func__);
return;
}
- dev_dbg(adapter->dev,
- "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n",
- command, result, le16_to_cpu(cmd->size), seq_num);
+ mwifiex_dbg(adapter, CMD,
+ "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n",
+ command, result, le16_to_cpu(cmd->size), seq_num);
/* Get BSS number and corresponding priv */
priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num),
@@ -1232,15 +1287,16 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter,
command &= HostCmd_CMD_ID_MASK;
if (command != HostCmd_CMD_802_11_PS_MODE_ENH) {
- dev_err(adapter->dev,
- "%s: rcvd unexpected resp for cmd %#x, result = %x\n",
- __func__, command, result);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: rcvd unexpected resp for cmd %#x, result = %x\n",
+ __func__, command, result);
return;
}
if (result) {
- dev_err(adapter->dev, "%s: sleep confirm cmd failed\n",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: sleep confirm cmd failed\n",
+ __func__);
adapter->pm_wakeup_card_req = false;
adapter->ps_state = PS_STATE_AWAKE;
return;
@@ -1305,7 +1361,8 @@ int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv,
sizeof(struct mwifiex_ie_types_header));
cmd_size += sizeof(*ps_tlv);
tlv += sizeof(*ps_tlv);
- dev_dbg(adapter->dev, "cmd: PS Command: Enter PS\n");
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: PS Command: Enter PS\n");
ps_mode->null_pkt_interval =
cpu_to_le16(adapter->null_pkt_interval);
ps_mode->multiple_dtims =
@@ -1335,8 +1392,8 @@ int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv,
tlv += sizeof(*auto_ds_tlv);
if (auto_ds)
idletime = auto_ds->idle_time;
- dev_dbg(priv->adapter->dev,
- "cmd: PS Command: Enter Auto Deep Sleep\n");
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: PS Command: Enter Auto Deep Sleep\n");
auto_ds_tlv->deep_sleep_timeout = cpu_to_le16(idletime);
}
cmd->size = cpu_to_le16(cmd_size);
@@ -1363,27 +1420,31 @@ int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv,
uint16_t auto_ps_bitmap =
le16_to_cpu(ps_mode->params.ps_bitmap);
- dev_dbg(adapter->dev,
- "info: %s: PS_MODE cmd reply result=%#x action=%#X\n",
- __func__, resp->result, action);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: PS_MODE cmd reply result=%#x action=%#X\n",
+ __func__, resp->result, action);
if (action == EN_AUTO_PS) {
if (auto_ps_bitmap & BITMAP_AUTO_DS) {
- dev_dbg(adapter->dev, "cmd: Enabled auto deep sleep\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: Enabled auto deep sleep\n");
priv->adapter->is_deep_sleep = true;
}
if (auto_ps_bitmap & BITMAP_STA_PS) {
- dev_dbg(adapter->dev, "cmd: Enabled STA power save\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: Enabled STA power save\n");
if (adapter->sleep_period.period)
- dev_dbg(adapter->dev,
- "cmd: set to uapsd/pps mode\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: set to uapsd/pps mode\n");
}
} else if (action == DIS_AUTO_PS) {
if (ps_bitmap & BITMAP_AUTO_DS) {
priv->adapter->is_deep_sleep = false;
- dev_dbg(adapter->dev, "cmd: Disabled auto deep sleep\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: Disabled auto deep sleep\n");
}
if (ps_bitmap & BITMAP_STA_PS) {
- dev_dbg(adapter->dev, "cmd: Disabled STA power save\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: Disabled STA power save\n");
if (adapter->sleep_period.period) {
adapter->delay_null_pkt = false;
adapter->tx_lock_flag = false;
@@ -1396,7 +1457,8 @@ int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv,
else
adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
- dev_dbg(adapter->dev, "cmd: ps_bitmap=%#x\n", ps_bitmap);
+ mwifiex_dbg(adapter, CMD,
+ "cmd: ps_bitmap=%#x\n", ps_bitmap);
if (pm_cfg) {
/* This section is for get power save mode */
@@ -1533,29 +1595,29 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
api_rev->major_ver;
adapter->key_api_minor_ver =
api_rev->minor_ver;
- dev_dbg(adapter->dev,
- "key_api v%d.%d\n",
- adapter->key_api_major_ver,
- adapter->key_api_minor_ver);
+ mwifiex_dbg(adapter, INFO,
+ "key_api v%d.%d\n",
+ adapter->key_api_major_ver,
+ adapter->key_api_minor_ver);
break;
case FW_API_VER_ID:
adapter->fw_api_ver =
api_rev->major_ver;
- dev_dbg(adapter->dev,
- "Firmware api version %d\n",
- adapter->fw_api_ver);
+ mwifiex_dbg(adapter, INFO,
+ "Firmware api version %d\n",
+ adapter->fw_api_ver);
break;
default:
- dev_warn(adapter->dev,
- "Unknown api_id: %d\n",
- api_id);
+ mwifiex_dbg(adapter, FATAL,
+ "Unknown api_id: %d\n",
+ api_id);
break;
}
break;
default:
- dev_warn(adapter->dev,
- "Unknown GET_HW_SPEC TLV type: %#x\n",
- le16_to_cpu(tlv->type));
+ mwifiex_dbg(adapter, FATAL,
+ "Unknown GET_HW_SPEC TLV type: %#x\n",
+ le16_to_cpu(tlv->type));
break;
}
parsed_len += le16_to_cpu(tlv->len) +
@@ -1565,14 +1627,16 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
}
}
- dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n",
- adapter->fw_release_number);
- dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n",
- hw_spec->permanent_addr);
- dev_dbg(adapter->dev,
- "info: GET_HW_SPEC: hw_if_version=%#x version=%#x\n",
- le16_to_cpu(hw_spec->hw_if_version),
- le16_to_cpu(hw_spec->version));
+ mwifiex_dbg(adapter, INFO,
+ "info: GET_HW_SPEC: fw_release_number- %#x\n",
+ adapter->fw_release_number);
+ mwifiex_dbg(adapter, INFO,
+ "info: GET_HW_SPEC: permanent addr: %pM\n",
+ hw_spec->permanent_addr);
+ mwifiex_dbg(adapter, INFO,
+ "info: GET_HW_SPEC: hw_if_version=%#x version=%#x\n",
+ le16_to_cpu(hw_spec->hw_if_version),
+ le16_to_cpu(hw_spec->version));
ether_addr_copy(priv->adapter->perm_addr, hw_spec->permanent_addr);
adapter->region_code = le16_to_cpu(hw_spec->region_code);
@@ -1585,8 +1649,8 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
/* If it's unidentified region code, use the default (USA) */
if (i >= MWIFIEX_MAX_REGION_CODE) {
adapter->region_code = 0x10;
- dev_dbg(adapter->dev,
- "cmd: unknown region code, use default (USA)\n");
+ mwifiex_dbg(adapter, WARN,
+ "cmd: unknown region code, use default (USA)\n");
}
adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap);
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
index 1fb329dc6744..5a0636d43a1b 100644
--- a/drivers/net/wireless/mwifiex/debugfs.c
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -152,24 +152,24 @@ free_and_exit:
}
/*
- * Proc firmware dump read handler.
+ * Proc device dump read handler.
*
- * This function is called when the 'fw_dump' file is opened for
+ * This function is called when the 'device_dump' file is opened for
* reading.
- * This function dumps firmware memory in different files
- * (ex. DTCM, ITCM, SQRAM etc.) based on the the segments for
+ * This function dumps driver information and firmware memory segments
+ * (ex. DTCM, ITCM, SQRAM etc.) for
* debugging.
*/
static ssize_t
-mwifiex_fw_dump_read(struct file *file, char __user *ubuf,
- size_t count, loff_t *ppos)
+mwifiex_device_dump_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
{
struct mwifiex_private *priv = file->private_data;
- if (!priv->adapter->if_ops.fw_dump)
+ if (!priv->adapter->if_ops.device_dump)
return -EIO;
- priv->adapter->if_ops.fw_dump(priv->adapter);
+ priv->adapter->if_ops.device_dump(priv->adapter);
return 0;
}
@@ -535,6 +535,144 @@ done:
return ret;
}
+/* Proc debug_mask file read handler.
+ * This function is called when the 'debug_mask' file is opened for reading
+ * This function can be used read driver debugging mask value.
+ */
+static ssize_t
+mwifiex_debug_mask_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwifiex_private *priv =
+ (struct mwifiex_private *)file->private_data;
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)page;
+ size_t ret = 0;
+ int pos = 0;
+
+ if (!buf)
+ return -ENOMEM;
+
+ pos += snprintf(buf, PAGE_SIZE, "debug mask=0x%08x\n",
+ priv->adapter->debug_mask);
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
+
+ free_page(page);
+ return ret;
+}
+
+/* Proc debug_mask file read handler.
+ * This function is called when the 'debug_mask' file is opened for reading
+ * This function can be used read driver debugging mask value.
+ */
+static ssize_t
+mwifiex_debug_mask_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ int ret;
+ unsigned long debug_mask;
+ struct mwifiex_private *priv = (void *)file->private_data;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (void *)addr;
+ size_t buf_size = min(count, (size_t)(PAGE_SIZE - 1));
+
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, ubuf, buf_size)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (kstrtoul(buf, 0, &debug_mask)) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ priv->adapter->debug_mask = debug_mask;
+ ret = count;
+done:
+ free_page(addr);
+ return ret;
+}
+
+/* Proc memrw file write handler.
+ * This function is called when the 'memrw' file is opened for writing
+ * This function can be used to write to a memory location.
+ */
+static ssize_t
+mwifiex_memrw_write(struct file *file, const char __user *ubuf, size_t count,
+ loff_t *ppos)
+{
+ int ret;
+ char cmd;
+ struct mwifiex_ds_mem_rw mem_rw;
+ u16 cmd_action;
+ struct mwifiex_private *priv = (void *)file->private_data;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (void *)addr;
+ size_t buf_size = min(count, (size_t)(PAGE_SIZE - 1));
+
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, ubuf, buf_size)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = sscanf(buf, "%c %x %x", &cmd, &mem_rw.addr, &mem_rw.value);
+ if (ret != 3) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((cmd == 'r') || (cmd == 'R')) {
+ cmd_action = HostCmd_ACT_GEN_GET;
+ mem_rw.value = 0;
+ } else if ((cmd == 'w') || (cmd == 'W')) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memcpy(&priv->mem_rw, &mem_rw, sizeof(mem_rw));
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_MEM_ACCESS, cmd_action, 0,
+ &mem_rw, true))
+ ret = -1;
+ else
+ ret = count;
+
+done:
+ free_page(addr);
+ return ret;
+}
+
+/* Proc memrw file read handler.
+ * This function is called when the 'memrw' file is opened for reading
+ * This function can be used to read from a memory location.
+ */
+static ssize_t
+mwifiex_memrw_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwifiex_private *priv = (void *)file->private_data;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+ int ret, pos = 0;
+
+ if (!buf)
+ return -ENOMEM;
+
+ pos += snprintf(buf, PAGE_SIZE, "0x%x 0x%x\n", priv->mem_rw.addr,
+ priv->mem_rw.value);
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
+
+ free_page(addr);
+ return ret;
+}
+
static u32 saved_offset = -1, saved_bytes = -1;
/*
@@ -654,7 +792,8 @@ mwifiex_hscfg_write(struct file *file, const char __user *ubuf,
memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg));
if (arg_num > 3) {
- dev_err(priv->adapter->dev, "Too many arguments\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Too many arguments\n");
ret = -EINVAL;
goto done;
}
@@ -746,11 +885,13 @@ static const struct file_operations mwifiex_dfs_##name##_fops = { \
MWIFIEX_DFS_FILE_READ_OPS(info);
MWIFIEX_DFS_FILE_READ_OPS(debug);
MWIFIEX_DFS_FILE_READ_OPS(getlog);
-MWIFIEX_DFS_FILE_READ_OPS(fw_dump);
+MWIFIEX_DFS_FILE_READ_OPS(device_dump);
MWIFIEX_DFS_FILE_OPS(regrdwr);
MWIFIEX_DFS_FILE_OPS(rdeeprom);
+MWIFIEX_DFS_FILE_OPS(memrw);
MWIFIEX_DFS_FILE_OPS(hscfg);
MWIFIEX_DFS_FILE_OPS(histogram);
+MWIFIEX_DFS_FILE_OPS(debug_mask);
/*
* This function creates the debug FS directory structure and the files.
@@ -772,9 +913,11 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
MWIFIEX_DFS_ADD_FILE(getlog);
MWIFIEX_DFS_ADD_FILE(regrdwr);
MWIFIEX_DFS_ADD_FILE(rdeeprom);
- MWIFIEX_DFS_ADD_FILE(fw_dump);
+ MWIFIEX_DFS_ADD_FILE(device_dump);
+ MWIFIEX_DFS_ADD_FILE(memrw);
MWIFIEX_DFS_ADD_FILE(hscfg);
MWIFIEX_DFS_ADD_FILE(histogram);
+ MWIFIEX_DFS_ADD_FILE(debug_mask);
}
/*
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index 38f24e0427d2..51e344789ba2 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -29,7 +29,7 @@
#include <uapi/linux/if_arp.h>
#include <net/mac80211.h>
-
+#define MWIFIEX_BSS_COEX_COUNT 2
#define MWIFIEX_MAX_BSS_NUM (3)
#define MWIFIEX_DMA_ALIGN_SZ 64
@@ -49,7 +49,12 @@
#define MWIFIEX_STA_AMPDU_DEF_TXWINSIZE 64
#define MWIFIEX_STA_AMPDU_DEF_RXWINSIZE 64
+#define MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE 16
+
#define MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE 32
+
+#define MWIFIEX_UAP_COEX_AMPDU_DEF_RXWINSIZE 16
+
#define MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE 16
#define MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE 64
#define MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE 64
diff --git a/drivers/net/wireless/mwifiex/ethtool.c b/drivers/net/wireless/mwifiex/ethtool.c
index 65d8d6d4b6ba..58400c69ab26 100644
--- a/drivers/net/wireless/mwifiex/ethtool.c
+++ b/drivers/net/wireless/mwifiex/ethtool.c
@@ -64,104 +64,7 @@ static int mwifiex_ethtool_set_wol(struct net_device *dev,
return 0;
}
-static int
-mwifiex_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump)
-{
- struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- struct mwifiex_adapter *adapter = priv->adapter;
- struct memory_type_mapping *entry;
-
- if (!adapter->if_ops.fw_dump)
- return -ENOTSUPP;
-
- dump->flag = adapter->curr_mem_idx;
- dump->version = 1;
- if (adapter->curr_mem_idx == MWIFIEX_DRV_INFO_IDX) {
- dump->len = adapter->drv_info_size;
- } else if (adapter->curr_mem_idx != MWIFIEX_FW_DUMP_IDX) {
- entry = &adapter->mem_type_mapping_tbl[adapter->curr_mem_idx];
- dump->len = entry->mem_size;
- } else {
- dump->len = 0;
- }
-
- return 0;
-}
-
-static int
-mwifiex_get_dump_data(struct net_device *dev, struct ethtool_dump *dump,
- void *buffer)
-{
- u8 *p = buffer;
- struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- struct mwifiex_adapter *adapter = priv->adapter;
- struct memory_type_mapping *entry;
-
- if (!adapter->if_ops.fw_dump)
- return -ENOTSUPP;
-
- if (adapter->curr_mem_idx == MWIFIEX_DRV_INFO_IDX) {
- if (!adapter->drv_info_dump)
- return -EFAULT;
- memcpy(p, adapter->drv_info_dump, adapter->drv_info_size);
- return 0;
- }
-
- if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) {
- dev_err(adapter->dev, "firmware dump in progress!!\n");
- return -EBUSY;
- }
-
- entry = &adapter->mem_type_mapping_tbl[adapter->curr_mem_idx];
-
- if (!entry->mem_ptr)
- return -EFAULT;
-
- memcpy(p, entry->mem_ptr, entry->mem_size);
-
- entry->mem_size = 0;
- vfree(entry->mem_ptr);
- entry->mem_ptr = NULL;
-
- return 0;
-}
-
-static int mwifiex_set_dump(struct net_device *dev, struct ethtool_dump *val)
-{
- struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- struct mwifiex_adapter *adapter = priv->adapter;
-
- if (!adapter->if_ops.fw_dump)
- return -ENOTSUPP;
-
- if (val->flag == MWIFIEX_DRV_INFO_IDX) {
- adapter->curr_mem_idx = MWIFIEX_DRV_INFO_IDX;
- return 0;
- }
-
- if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) {
- dev_err(adapter->dev, "firmware dump in progress!!\n");
- return -EBUSY;
- }
-
- if (val->flag == MWIFIEX_FW_DUMP_IDX) {
- adapter->curr_mem_idx = val->flag;
- adapter->if_ops.fw_dump(adapter);
- return 0;
- }
-
- if (val->flag < 0 || val->flag >= adapter->num_mem_types)
- return -EINVAL;
-
- adapter->curr_mem_idx = val->flag;
-
- return 0;
-}
-
const struct ethtool_ops mwifiex_ethtool_ops = {
.get_wol = mwifiex_ethtool_get_wol,
.set_wol = mwifiex_ethtool_set_wol,
- .get_dump_flag = mwifiex_get_dump_flag,
- .get_dump_data = mwifiex_get_dump_data,
- .set_dump = mwifiex_set_dump,
};
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 59d8964dd0dc..cd09051710e6 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -128,6 +128,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_UAP_SSID 0x0000
#define TLV_TYPE_UAP_RATES 0x0001
+#define TLV_TYPE_PWR_CONSTRAINT 0x0020
#define PROPRIETARY_TLV_BASE_ID 0x0100
#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
@@ -174,6 +175,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_SCAN_CHANNEL_GAP (PROPRIETARY_TLV_BASE_ID + 197)
#define TLV_TYPE_API_REV (PROPRIETARY_TLV_BASE_ID + 199)
#define TLV_TYPE_CHANNEL_STATS (PROPRIETARY_TLV_BASE_ID + 198)
+#define TLV_BTCOEX_WL_AGGR_WINSIZE (PROPRIETARY_TLV_BASE_ID + 202)
+#define TLV_BTCOEX_WL_SCANTIME (PROPRIETARY_TLV_BASE_ID + 203)
#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048
@@ -323,15 +326,18 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075
#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f
#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083
+#define HostCmd_CMD_MEM_ACCESS 0x0086
#define HostCmd_CMD_CFG_DATA 0x008f
#define HostCmd_CMD_VERSION_EXT 0x0097
#define HostCmd_CMD_MEF_CFG 0x009a
#define HostCmd_CMD_RSSI_INFO 0x00a4
#define HostCmd_CMD_FUNC_INIT 0x00a9
#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
+#define HOST_CMD_APCMD_SYS_RESET 0x00af
#define HostCmd_CMD_UAP_SYS_CONFIG 0x00b0
#define HostCmd_CMD_UAP_BSS_START 0x00b1
#define HostCmd_CMD_UAP_BSS_STOP 0x00b2
+#define HOST_CMD_APCMD_STA_LIST 0x00b3
#define HostCmd_CMD_UAP_STA_DEAUTH 0x00b5
#define HostCmd_CMD_11N_CFG 0x00cd
#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce
@@ -418,8 +424,12 @@ enum P2P_MODES {
#define HS_CFG_COND_MAC_EVENT 0x00000004
#define HS_CFG_COND_MULTICAST_DATA 0x00000008
-#define MWIFIEX_TIMEOUT_FOR_AP_RESP 0xfffc
-#define MWIFIEX_STATUS_CODE_AUTH_TIMEOUT 2
+#define CONNECT_ERR_AUTH_ERR_STA_FAILURE 0xFFFB
+#define CONNECT_ERR_ASSOC_ERR_TIMEOUT 0xFFFC
+#define CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED 0xFFFD
+#define CONNECT_ERR_AUTH_MSG_UNHANDLED 0xFFFE
+#define CONNECT_ERR_STA_FAILURE 0xFFFF
+
#define CMD_F_HOSTCMD (1 << 0)
#define CMD_F_CANCELED (1 << 1)
@@ -502,6 +512,7 @@ enum P2P_MODES {
#define EVENT_EXT_SCAN_REPORT 0x00000058
#define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f
#define EVENT_TX_STATUS_REPORT 0x00000074
+#define EVENT_BT_COEX_WLAN_PARA_CHANGE 0X00000076
#define EVENT_ID_MASK 0xffff
#define BSS_NUM_MASK 0xf
@@ -626,7 +637,12 @@ struct uap_rxpd {
__le16 rx_pkt_type;
__le16 seq_num;
u8 priority;
- u8 reserved1;
+ u8 rx_rate;
+ s8 snr;
+ s8 nf;
+ u8 ht_info;
+ u8 reserved[3];
+ u8 flags;
};
struct mwifiex_fw_chan_stats {
@@ -1150,6 +1166,13 @@ enum SNMP_MIB_INDEX {
DOT11H_I = 10,
};
+enum mwifiex_assocmd_failurepoint {
+ MWIFIEX_ASSOC_CMD_SUCCESS = 0,
+ MWIFIEX_ASSOC_CMD_FAILURE_ASSOC,
+ MWIFIEX_ASSOC_CMD_FAILURE_AUTH,
+ MWIFIEX_ASSOC_CMD_FAILURE_JOIN
+};
+
#define MAX_SNMP_BUF_SIZE 128
struct host_cmd_ds_802_11_snmp_mib {
@@ -1447,6 +1470,18 @@ struct host_cmd_ds_sta_deauth {
__le16 reason;
} __packed;
+struct mwifiex_ie_types_sta_info {
+ struct mwifiex_ie_types_header header;
+ u8 mac[ETH_ALEN];
+ u8 power_mfg_status;
+ s8 rssi;
+};
+
+struct host_cmd_ds_sta_list {
+ u16 sta_count;
+ u8 tlv[0];
+} __packed;
+
struct mwifiex_ie_types_pwr_capability {
struct mwifiex_ie_types_header header;
s8 min_pwr;
@@ -1576,6 +1611,13 @@ struct mwifiex_ie_types_extcap {
u8 ext_capab[0];
} __packed;
+struct host_cmd_ds_mem_access {
+ __le16 action;
+ __le16 reserved;
+ __le32 addr;
+ __le32 value;
+};
+
struct mwifiex_ie_types_qos_info {
struct mwifiex_ie_types_header header;
u8 qos_info;
@@ -1742,6 +1784,27 @@ struct host_cmd_tlv_ageout_timer {
__le32 sta_ao_timer;
} __packed;
+struct host_cmd_tlv_power_constraint {
+ struct mwifiex_ie_types_header header;
+ u8 constraint;
+} __packed;
+
+struct mwifiex_ie_types_btcoex_scan_time {
+ struct mwifiex_ie_types_header header;
+ u8 coex_scan;
+ u8 reserved;
+ u16 min_scan_time;
+ u16 max_scan_time;
+} __packed;
+
+struct mwifiex_ie_types_btcoex_aggr_win_size {
+ struct mwifiex_ie_types_header header;
+ u8 coex_win_size;
+ u8 tx_win_size;
+ u8 rx_win_size;
+ u8 reserved;
+} __packed;
+
struct host_cmd_ds_version_ext {
u8 version_str_sel;
char version_str[128];
@@ -1958,6 +2021,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_p2p_mode_cfg mode_cfg;
struct host_cmd_ds_802_11_ibss_status ibss_coalescing;
struct host_cmd_ds_mef_cfg mef_cfg;
+ struct host_cmd_ds_mem_access mem;
struct host_cmd_ds_mac_reg_access mac_reg;
struct host_cmd_ds_bbp_reg_access bbp_reg;
struct host_cmd_ds_rf_reg_access rf_reg;
@@ -1968,6 +2032,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_802_11_subsc_evt subsc_evt;
struct host_cmd_ds_sys_config uap_sys_config;
struct host_cmd_ds_sta_deauth sta_deauth;
+ struct host_cmd_ds_sta_list sta_list;
struct host_cmd_11ac_vht_cfg vht_cfg;
struct host_cmd_ds_coalesce_cfg coalesce_cfg;
struct host_cmd_ds_tdls_oper tdls_oper;
diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c
index f3b6ed249403..0ba894509413 100644
--- a/drivers/net/wireless/mwifiex/ie.c
+++ b/drivers/net/wireless/mwifiex/ie.c
@@ -320,63 +320,81 @@ done:
/* This function parses head and tail IEs, from cfg80211_beacon_data and sets
* these IE to FW.
*/
-static int mwifiex_uap_set_head_tail_ies(struct mwifiex_private *priv,
- struct cfg80211_beacon_data *info)
+static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv,
+ struct cfg80211_beacon_data *info)
{
struct mwifiex_ie *gen_ie;
- struct ieee_types_header *rsn_ie = NULL, *wpa_ie = NULL;
- struct ieee_types_header *chsw_ie = NULL;
+ struct ieee_types_header *hdr;
+ struct ieee80211_vendor_ie *vendorhdr;
u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
- const u8 *vendor_ie;
+ int left_len, parsed_len = 0;
+
+ if (!info->tail || !info->tail_len)
+ return 0;
gen_ie = kzalloc(sizeof(*gen_ie), GFP_KERNEL);
if (!gen_ie)
return -ENOMEM;
- gen_ie->ie_index = cpu_to_le16(gen_idx);
- gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON |
- MGMT_MASK_PROBE_RESP |
- MGMT_MASK_ASSOC_RESP);
- if (info->tail && info->tail_len) {
- rsn_ie = (void *)cfg80211_find_ie(WLAN_EID_RSN,
- info->tail, info->tail_len);
- if (rsn_ie) {
- memcpy(gen_ie->ie_buffer, rsn_ie, rsn_ie->len + 2);
- ie_len = rsn_ie->len + 2;
- gen_ie->ie_length = cpu_to_le16(ie_len);
+ left_len = info->tail_len;
+
+ /* Many IEs are generated in FW by parsing bss configuration.
+ * Let's not add them here; else we may end up duplicating these IEs
+ */
+ while (left_len > sizeof(struct ieee_types_header)) {
+ hdr = (void *)(info->tail + parsed_len);
+ switch (hdr->element_id) {
+ case WLAN_EID_SSID:
+ case WLAN_EID_SUPP_RATES:
+ case WLAN_EID_COUNTRY:
+ case WLAN_EID_PWR_CONSTRAINT:
+ case WLAN_EID_EXT_SUPP_RATES:
+ case WLAN_EID_HT_CAPABILITY:
+ case WLAN_EID_HT_OPERATION:
+ case WLAN_EID_VHT_CAPABILITY:
+ case WLAN_EID_VHT_OPERATION:
+ case WLAN_EID_VENDOR_SPECIFIC:
+ break;
+ default:
+ memcpy(gen_ie->ie_buffer + ie_len, hdr,
+ hdr->len + sizeof(struct ieee_types_header));
+ ie_len += hdr->len + sizeof(struct ieee_types_header);
+ break;
}
+ left_len -= hdr->len + sizeof(struct ieee_types_header);
+ parsed_len += hdr->len + sizeof(struct ieee_types_header);
+ }
- vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+ /* parse only WPA vendor IE from tail, WMM IE is configured by
+ * bss_config command
+ */
+ vendorhdr = (void *)cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
WLAN_OUI_TYPE_MICROSOFT_WPA,
- info->tail,
- info->tail_len);
- if (vendor_ie) {
- wpa_ie = (struct ieee_types_header *)vendor_ie;
- memcpy(gen_ie->ie_buffer + ie_len,
- wpa_ie, wpa_ie->len + 2);
- ie_len += wpa_ie->len + 2;
- gen_ie->ie_length = cpu_to_le16(ie_len);
- }
+ info->tail, info->tail_len);
+ if (vendorhdr) {
+ memcpy(gen_ie->ie_buffer + ie_len, vendorhdr,
+ vendorhdr->len + sizeof(struct ieee_types_header));
+ ie_len += vendorhdr->len + sizeof(struct ieee_types_header);
+ }
- chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH,
- info->tail, info->tail_len);
- if (chsw_ie) {
- memcpy(gen_ie->ie_buffer + ie_len,
- chsw_ie, chsw_ie->len + 2);
- ie_len += chsw_ie->len + 2;
- gen_ie->ie_length = cpu_to_le16(ie_len);
- }
+ if (!ie_len) {
+ kfree(gen_ie);
+ return 0;
}
- if (rsn_ie || wpa_ie || chsw_ie) {
- if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL,
- NULL, NULL, NULL)) {
- kfree(gen_ie);
- return -1;
- }
- priv->gen_idx = gen_idx;
+ gen_ie->ie_index = cpu_to_le16(gen_idx);
+ gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON |
+ MGMT_MASK_PROBE_RESP |
+ MGMT_MASK_ASSOC_RESP);
+ gen_ie->ie_length = cpu_to_le16(ie_len);
+
+ if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, NULL,
+ NULL, NULL)) {
+ kfree(gen_ie);
+ return -1;
}
+ priv->gen_idx = gen_idx;
kfree(gen_ie);
return 0;
}
@@ -390,7 +408,7 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
{
int ret;
- ret = mwifiex_uap_set_head_tail_ies(priv, info);
+ ret = mwifiex_uap_parse_tail_ies(priv, info);
return ret;
return mwifiex_set_mgmt_beacon_data_ies(priv, info);
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index e12192f5cfad..df7fdc09d38c 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -56,7 +56,7 @@ static void wakeup_timer_fn(unsigned long data)
{
struct mwifiex_adapter *adapter = (struct mwifiex_adapter *)data;
- dev_err(adapter->dev, "Firmware wakeup failed\n");
+ mwifiex_dbg(adapter, ERROR, "Firmware wakeup failed\n");
adapter->hw_status = MWIFIEX_HW_STATUS_RESET;
mwifiex_cancel_all_pending_cmd(adapter);
@@ -172,8 +172,9 @@ static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter)
/* Allocate command buffer */
ret = mwifiex_alloc_cmd_buffer(adapter);
if (ret) {
- dev_err(adapter->dev, "%s: failed to alloc cmd buffer\n",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: failed to alloc cmd buffer\n",
+ __func__);
return -1;
}
@@ -182,8 +183,9 @@ static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter)
+ INTF_HEADER_LEN);
if (!adapter->sleep_cfm) {
- dev_err(adapter->dev, "%s: failed to alloc sleep cfm"
- " cmd buffer\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: failed to alloc sleep cfm\t"
+ " cmd buffer\n", __func__);
return -1;
}
skb_reserve(adapter->sleep_cfm, INTF_HEADER_LEN);
@@ -417,7 +419,7 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
mwifiex_free_lock_list(adapter);
/* Free command buffer */
- dev_dbg(adapter->dev, "info: free cmd buffer\n");
+ mwifiex_dbg(adapter, INFO, "info: free cmd buffer\n");
mwifiex_free_cmd_buffer(adapter);
for (idx = 0; idx < adapter->num_mem_types; idx++) {
@@ -433,6 +435,7 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
if (adapter->drv_info_dump) {
vfree(adapter->drv_info_dump);
+ adapter->drv_info_dump = NULL;
adapter->drv_info_size = 0;
}
@@ -595,10 +598,11 @@ static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv)
for (i = 0; i < adapter->priv_num; ++i) {
head = &adapter->bss_prio_tbl[i].bss_prio_head;
lock = &adapter->bss_prio_tbl[i].bss_prio_lock;
- dev_dbg(adapter->dev, "info: delete BSS priority table,"
- " bss_type = %d, bss_num = %d, i = %d,"
- " head = %p\n",
- priv->bss_type, priv->bss_num, i, head);
+ mwifiex_dbg(adapter, INFO,
+ "info: delete BSS priority table,\t"
+ "bss_type = %d, bss_num = %d, i = %d,\t"
+ "head = %p\n",
+ priv->bss_type, priv->bss_num, i, head);
{
spin_lock_irqsave(lock, flags);
@@ -609,9 +613,10 @@ static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv)
list_for_each_entry_safe(bssprio_node, tmp_node, head,
list) {
if (bssprio_node->priv == priv) {
- dev_dbg(adapter->dev, "info: Delete "
- "node %p, next = %p\n",
- bssprio_node, tmp_node);
+ mwifiex_dbg(adapter, INFO,
+ "info: Delete\t"
+ "node %p, next = %p\n",
+ bssprio_node, tmp_node);
list_del(&bssprio_node->list);
kfree(bssprio_node);
}
@@ -659,20 +664,23 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
adapter->hw_status = MWIFIEX_HW_STATUS_CLOSING;
/* wait for mwifiex_process to complete */
if (adapter->mwifiex_processing) {
- dev_warn(adapter->dev, "main process is still running\n");
+ mwifiex_dbg(adapter, WARN,
+ "main process is still running\n");
return ret;
}
/* cancel current command */
if (adapter->curr_cmd) {
- dev_warn(adapter->dev, "curr_cmd is still in processing\n");
+ mwifiex_dbg(adapter, WARN,
+ "curr_cmd is still in processing\n");
del_timer_sync(&adapter->cmd_timer);
mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
adapter->curr_cmd = NULL;
}
/* shut down mwifiex */
- dev_dbg(adapter->dev, "info: shutdown mwifiex...\n");
+ mwifiex_dbg(adapter, MSG,
+ "info: shutdown mwifiex...\n");
/* Clean up Tx/Rx queues and delete BSS priority table */
for (i = 0; i < adapter->priv_num; i++) {
@@ -741,8 +749,8 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
/* check if firmware is already running */
ret = adapter->if_ops.check_fw_status(adapter, poll_num);
if (!ret) {
- dev_notice(adapter->dev,
- "WLAN FW already running! Skip FW dnld\n");
+ mwifiex_dbg(adapter, MSG,
+ "WLAN FW already running! Skip FW dnld\n");
return 0;
}
@@ -750,8 +758,8 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
/* check if we are the winner for downloading FW */
if (!adapter->winner) {
- dev_notice(adapter->dev,
- "FW already running! Skip FW dnld\n");
+ mwifiex_dbg(adapter, MSG,
+ "FW already running! Skip FW dnld\n");
goto poll_fw;
}
}
@@ -760,7 +768,8 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
/* Download firmware with helper */
ret = adapter->if_ops.prog_fw(adapter, pmfw);
if (ret) {
- dev_err(adapter->dev, "prog_fw failed ret=%#x\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "prog_fw failed ret=%#x\n", ret);
return ret;
}
}
@@ -769,7 +778,8 @@ poll_fw:
/* Check if the firmware is downloaded successfully or not */
ret = adapter->if_ops.check_fw_status(adapter, poll_num);
if (ret)
- dev_err(adapter->dev, "FW failed to be active in time\n");
+ mwifiex_dbg(adapter, ERROR,
+ "FW failed to be active in time\n");
return ret;
}
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index d2b05c3a96da..4f0174c64946 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -113,6 +113,7 @@ struct mwifiex_uap_bss_param {
u32 sta_ao_timer;
u32 ps_sta_ao_timer;
u8 qos_info;
+ u8 power_constraint;
struct mwifiex_types_wmm_info wmm_info;
};
@@ -189,6 +190,7 @@ struct tdls_peer_info {
};
struct mwifiex_debug_info {
+ unsigned int debug_mask;
u32 int_counter;
u32 packets_out[MAX_NUM_TID];
u32 tx_buf_size;
@@ -342,6 +344,11 @@ struct mwifiex_ds_read_eeprom {
u8 value[MAX_EEPROM_DATA];
};
+struct mwifiex_ds_mem_rw {
+ u32 addr;
+ u32 value;
+};
+
#define IEEE_MAX_IE_SIZE 256
#define MWIFIEX_IE_HDR_SIZE (sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE)
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 411a6c2f4aca..56b024a6aaa5 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -53,9 +53,9 @@ mwifiex_cmd_append_generic_ie(struct mwifiex_private *priv, u8 **buffer)
* parameter buffer pointer.
*/
if (priv->gen_ie_buf_len) {
- dev_dbg(priv->adapter->dev,
- "info: %s: append generic ie len %d to %p\n",
- __func__, priv->gen_ie_buf_len, *buffer);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: %s: append generic ie len %d to %p\n",
+ __func__, priv->gen_ie_buf_len, *buffer);
/* Wrap the generic IE buffer with a pass through TLV type */
ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
@@ -125,9 +125,9 @@ mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer,
tsf_val = cpu_to_le64(bss_desc->timestamp);
- dev_dbg(priv->adapter->dev,
- "info: %s: TSF offset calc: %016llx - %016llx\n",
- __func__, bss_desc->timestamp, bss_desc->fw_tsf);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: %s: TSF offset calc: %016llx - %016llx\n",
+ __func__, bss_desc->timestamp, bss_desc->fw_tsf);
memcpy(*buffer, &tsf_val, sizeof(tsf_val));
*buffer += sizeof(tsf_val);
@@ -152,7 +152,7 @@ static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1,
tmp = kmemdup(rate1, rate1_size, GFP_KERNEL);
if (!tmp) {
- dev_err(priv->adapter->dev, "failed to alloc tmp buf\n");
+ mwifiex_dbg(priv->adapter, ERROR, "failed to alloc tmp buf\n");
return -ENOMEM;
}
@@ -169,8 +169,8 @@ static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1,
}
}
- dev_dbg(priv->adapter->dev, "info: Tx data rate set to %#x\n",
- priv->data_rate);
+ mwifiex_dbg(priv->adapter, INFO, "info: Tx data rate set to %#x\n",
+ priv->data_rate);
if (!priv->is_data_rate_auto) {
while (*ptr) {
@@ -180,9 +180,10 @@ static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1,
}
ptr++;
}
- dev_err(priv->adapter->dev, "previously set fixed data rate %#x"
- " is not compatible with the network\n",
- priv->data_rate);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "previously set fixed data rate %#x\t"
+ "is not compatible with the network\n",
+ priv->data_rate);
ret = -1;
goto done;
@@ -214,8 +215,9 @@ mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv,
if (mwifiex_get_common_rates(priv, out_rates, MWIFIEX_SUPPORTED_RATES,
card_rates, card_rates_size)) {
*out_rates_size = 0;
- dev_err(priv->adapter->dev, "%s: cannot get common rates\n",
- __func__);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: cannot get common rates\n",
+ __func__);
return -1;
}
@@ -246,8 +248,9 @@ mwifiex_cmd_append_wps_ie(struct mwifiex_private *priv, u8 **buffer)
* parameter buffer pointer.
*/
if (priv->wps_ie_len) {
- dev_dbg(priv->adapter->dev, "cmd: append wps ie %d to %p\n",
- priv->wps_ie_len, *buffer);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: append wps ie %d to %p\n",
+ priv->wps_ie_len, *buffer);
/* Wrap the generic IE buffer with a pass through TLV type */
ie_header.type = cpu_to_le16(TLV_TYPE_MGMT_IE);
@@ -292,8 +295,9 @@ mwifiex_cmd_append_wapi_ie(struct mwifiex_private *priv, u8 **buffer)
* parameter buffer pointer.
*/
if (priv->wapi_ie_len) {
- dev_dbg(priv->adapter->dev, "cmd: append wapi ie %d to %p\n",
- priv->wapi_ie_len, *buffer);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: append wapi ie %d to %p\n",
+ priv->wapi_ie_len, *buffer);
/* Wrap the generic IE buffer with a pass through TLV type */
ie_header.type = cpu_to_le16(TLV_TYPE_WAPI_IE);
@@ -453,8 +457,8 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
rates_tlv->header.len = cpu_to_le16((u16) rates_size);
memcpy(rates_tlv->rates, rates, rates_size);
pos += sizeof(rates_tlv->header) + rates_size;
- dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: rates size = %d\n",
- rates_size);
+ mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_CMD: rates size = %d\n",
+ rates_size);
/* Add the Authentication type to be used for Auth frames */
auth_tlv = (struct mwifiex_ie_types_auth_type *) pos;
@@ -487,14 +491,14 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
sizeof(struct mwifiex_chan_scan_param_set));
chan_tlv->chan_scan_param[0].chan_number =
(bss_desc->phy_param_set.ds_param_set.current_chan);
- dev_dbg(priv->adapter->dev, "info: Assoc: TLV Chan = %d\n",
- chan_tlv->chan_scan_param[0].chan_number);
+ mwifiex_dbg(priv->adapter, INFO, "info: Assoc: TLV Chan = %d\n",
+ chan_tlv->chan_scan_param[0].chan_number);
chan_tlv->chan_scan_param[0].radio_type =
mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
- dev_dbg(priv->adapter->dev, "info: Assoc: TLV Band = %d\n",
- chan_tlv->chan_scan_param[0].radio_type);
+ mwifiex_dbg(priv->adapter, INFO, "info: Assoc: TLV Band = %d\n",
+ chan_tlv->chan_scan_param[0].radio_type);
pos += sizeof(chan_tlv->header) +
sizeof(struct mwifiex_chan_scan_param_set);
}
@@ -544,13 +548,31 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
tmp_cap &= CAPINFO_MASK;
- dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
- tmp_cap, CAPINFO_MASK);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
+ tmp_cap, CAPINFO_MASK);
assoc->cap_info_bitmap = cpu_to_le16(tmp_cap);
return 0;
}
+static const char *assoc_failure_reason_to_str(u16 cap_info)
+{
+ switch (cap_info) {
+ case CONNECT_ERR_AUTH_ERR_STA_FAILURE:
+ return "CONNECT_ERR_AUTH_ERR_STA_FAILURE";
+ case CONNECT_ERR_AUTH_MSG_UNHANDLED:
+ return "CONNECT_ERR_AUTH_MSG_UNHANDLED";
+ case CONNECT_ERR_ASSOC_ERR_TIMEOUT:
+ return "CONNECT_ERR_ASSOC_ERR_TIMEOUT";
+ case CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED:
+ return "CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED";
+ case CONNECT_ERR_STA_FAILURE:
+ return "CONNECT_ERR_STA_FAILURE";
+ }
+
+ return "Unknown connect failure";
+}
/*
* Association firmware command response handler
*
@@ -621,29 +643,48 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
struct ieee_types_assoc_rsp *assoc_rsp;
struct mwifiex_bssdescriptor *bss_desc;
bool enable_data = true;
- u16 cap_info, status_code;
+ u16 cap_info, status_code, aid;
assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params;
cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap);
status_code = le16_to_cpu(assoc_rsp->status_code);
+ aid = le16_to_cpu(assoc_rsp->a_id);
+
+ if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
+ dev_err(priv->adapter->dev,
+ "invalid AID value 0x%x; bits 15:14 not set\n",
+ aid);
+
+ aid &= ~(BIT(15) | BIT(14));
priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN,
sizeof(priv->assoc_rsp_buf));
memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
+ assoc_rsp->a_id = cpu_to_le16(aid);
+
if (status_code) {
priv->adapter->dbg.num_cmd_assoc_failure++;
- dev_err(priv->adapter->dev,
- "ASSOC_RESP: failed, status code=%d err=%#x a_id=%#x\n",
- status_code, cap_info, le16_to_cpu(assoc_rsp->a_id));
-
- if (cap_info == MWIFIEX_TIMEOUT_FOR_AP_RESP) {
- if (status_code == MWIFIEX_STATUS_CODE_AUTH_TIMEOUT)
+ mwifiex_dbg(priv->adapter, ERROR,
+ "ASSOC_RESP: failed,\t"
+ "status code=%d err=%#x a_id=%#x\n",
+ status_code, cap_info,
+ le16_to_cpu(assoc_rsp->a_id));
+
+ mwifiex_dbg(priv->adapter, ERROR, "assoc failure: reason %s\n",
+ assoc_failure_reason_to_str(cap_info));
+ if (cap_info == CONNECT_ERR_ASSOC_ERR_TIMEOUT) {
+ if (status_code == MWIFIEX_ASSOC_CMD_FAILURE_AUTH) {
ret = WLAN_STATUS_AUTH_TIMEOUT;
- else
+ mwifiex_dbg(priv->adapter, ERROR,
+ "ASSOC_RESP: AUTH timeout\n");
+ } else {
ret = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ mwifiex_dbg(priv->adapter, ERROR,
+ "ASSOC_RESP: UNSPECIFIED failure\n");
+ }
} else {
ret = status_code;
}
@@ -661,8 +702,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
/* Set the attempted BSSID Index to current */
bss_desc = priv->attempted_bss_desc;
- dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: %s\n",
- bss_desc->ssid.ssid);
+ mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: %s\n",
+ bss_desc->ssid.ssid);
/* Make a copy of current BSSID descriptor */
memcpy(&priv->curr_bss_params.bss_descriptor,
@@ -692,8 +733,9 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
= ((bss_desc->wmm_ie.qos_info_bitmap &
IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0);
- dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: curr_pkt_filter is %#x\n",
- priv->curr_pkt_filter);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ASSOC_RESP: curr_pkt_filter is %#x\n",
+ priv->curr_pkt_filter);
if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
priv->wpa_is_gtk_set = false;
@@ -709,8 +751,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
}
if (enable_data)
- dev_dbg(priv->adapter->dev,
- "info: post association, re-enabling data flow\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: post association, re-enabling data flow\n");
/* Reset SNR/NF/RSSI values */
priv->data_rssi_last = 0;
@@ -728,7 +770,7 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
priv->adapter->dbg.num_cmd_assoc_success++;
- dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: associated\n");
+ mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: associated\n");
/* Add the ra_list here for infra mode as there will be only 1 ra
always */
@@ -815,8 +857,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
memcpy(adhoc_start->ssid, req_ssid->ssid, req_ssid->ssid_len);
- dev_dbg(adapter->dev, "info: ADHOC_S_CMD: SSID = %s\n",
- adhoc_start->ssid);
+ mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: SSID = %s\n",
+ adhoc_start->ssid);
memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN);
memcpy(bss_desc->ssid.ssid, req_ssid->ssid, req_ssid->ssid_len);
@@ -848,12 +890,14 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
}
if (!priv->adhoc_channel) {
- dev_err(adapter->dev, "ADHOC_S_CMD: adhoc_channel cannot be 0\n");
+ mwifiex_dbg(adapter, ERROR,
+ "ADHOC_S_CMD: adhoc_channel cannot be 0\n");
return -1;
}
- dev_dbg(adapter->dev, "info: ADHOC_S_CMD: creating ADHOC on channel %d\n",
- priv->adhoc_channel);
+ mwifiex_dbg(adapter, INFO,
+ "info: ADHOC_S_CMD: creating ADHOC on channel %d\n",
+ priv->adhoc_channel);
priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel;
priv->curr_bss_params.band = adapter->adhoc_start_band;
@@ -885,13 +929,14 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
/* Set up privacy in bss_desc */
if (priv->sec_info.encryption_mode) {
/* Ad-Hoc capability privacy on */
- dev_dbg(adapter->dev,
- "info: ADHOC_S_CMD: wep_status set privacy to WEP\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: ADHOC_S_CMD: wep_status set privacy to WEP\n");
bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
tmp_cap |= WLAN_CAPABILITY_PRIVACY;
} else {
- dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status NOT set,"
- " setting privacy to ACCEPT ALL\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: ADHOC_S_CMD: wep_status NOT set,\t"
+ "setting privacy to ACCEPT ALL\n");
bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
}
@@ -902,8 +947,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
HostCmd_ACT_GEN_SET, 0,
&priv->curr_pkt_filter, false)) {
- dev_err(adapter->dev,
- "ADHOC_S_CMD: G Protection config failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "ADHOC_S_CMD: G Protection config failed\n");
return -1;
}
}
@@ -918,10 +963,10 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
memcpy(&priv->curr_bss_params.data_rates,
&adhoc_start->data_rate, priv->curr_bss_params.num_of_rates);
- dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%4ph\n",
- adhoc_start->data_rate);
+ mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: rates=%4ph\n",
+ adhoc_start->data_rate);
- dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n");
+ mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n");
if (IS_SUPPORT_MULTI_BANDS(adapter)) {
/* Append a channel TLV */
@@ -935,8 +980,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
chan_tlv->chan_scan_param[0].chan_number =
(u8) priv->curr_bss_params.bss_descriptor.channel;
- dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Chan = %d\n",
- chan_tlv->chan_scan_param[0].chan_number);
+ mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: TLV Chan = %d\n",
+ chan_tlv->chan_scan_param[0].chan_number);
chan_tlv->chan_scan_param[0].radio_type
= mwifiex_band_to_radio_type(priv->curr_bss_params.band);
@@ -951,8 +996,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
chan_tlv->chan_scan_param[0].radio_type |=
(IEEE80211_HT_PARAM_CHA_SEC_BELOW << 4);
}
- dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Band = %d\n",
- chan_tlv->chan_scan_param[0].radio_type);
+ mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: TLV Band = %d\n",
+ chan_tlv->chan_scan_param[0].radio_type);
pos += sizeof(chan_tlv->header) +
sizeof(struct mwifiex_chan_scan_param_set);
cmd_append_size +=
@@ -1074,8 +1119,8 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
HostCmd_ACT_GEN_SET, 0,
&curr_pkt_filter, false)) {
- dev_err(priv->adapter->dev,
- "ADHOC_J_CMD: G Protection config failed\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "ADHOC_J_CMD: G Protection config failed\n");
return -1;
}
}
@@ -1106,14 +1151,15 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
tmp_cap &= CAPINFO_MASK;
- dev_dbg(priv->adapter->dev,
- "info: ADHOC_J_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
- tmp_cap, CAPINFO_MASK);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ADHOC_J_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
+ tmp_cap, CAPINFO_MASK);
/* Information on BSSID descriptor passed to FW */
- dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: BSSID=%pM, SSID='%s'\n",
- adhoc_join->bss_descriptor.bssid,
- adhoc_join->bss_descriptor.ssid);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ADHOC_J_CMD: BSSID=%pM, SSID='%s'\n",
+ adhoc_join->bss_descriptor.bssid,
+ adhoc_join->bss_descriptor.ssid);
for (i = 0; i < MWIFIEX_SUPPORTED_RATES &&
bss_desc->supported_rates[i]; i++)
@@ -1149,14 +1195,14 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
sizeof(struct mwifiex_chan_scan_param_set));
chan_tlv->chan_scan_param[0].chan_number =
(bss_desc->phy_param_set.ds_param_set.current_chan);
- dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Chan=%d\n",
- chan_tlv->chan_scan_param[0].chan_number);
+ mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_J_CMD: TLV Chan=%d\n",
+ chan_tlv->chan_scan_param[0].chan_number);
chan_tlv->chan_scan_param[0].radio_type =
mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
- dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Band=%d\n",
- chan_tlv->chan_scan_param[0].radio_type);
+ mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_J_CMD: TLV Band=%d\n",
+ chan_tlv->chan_scan_param[0].radio_type);
pos += sizeof(chan_tlv->header) +
sizeof(struct mwifiex_chan_scan_param_set);
cmd_append_size += sizeof(chan_tlv->header) +
@@ -1210,7 +1256,7 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
/* Join result code 0 --> SUCCESS */
reason_code = le16_to_cpu(resp->result);
if (reason_code) {
- dev_err(priv->adapter->dev, "ADHOC_RESP: failed\n");
+ mwifiex_dbg(priv->adapter, ERROR, "ADHOC_RESP: failed\n");
if (priv->media_connected)
mwifiex_reset_connect_state(priv, reason_code);
@@ -1225,8 +1271,8 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
priv->media_connected = true;
if (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_AD_HOC_START) {
- dev_dbg(priv->adapter->dev, "info: ADHOC_S_RESP %s\n",
- bss_desc->ssid.ssid);
+ mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_S_RESP %s\n",
+ bss_desc->ssid.ssid);
/* Update the created network descriptor with the new BSSID */
memcpy(bss_desc->mac_address,
@@ -1238,8 +1284,9 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
* Now the join cmd should be successful.
* If BSSID has changed use SSID to compare instead of BSSID
*/
- dev_dbg(priv->adapter->dev, "info: ADHOC_J_RESP %s\n",
- bss_desc->ssid.ssid);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ADHOC_J_RESP %s\n",
+ bss_desc->ssid.ssid);
/*
* Make a copy of current BSSID descriptor, only needed for
@@ -1252,10 +1299,10 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
priv->adhoc_state = ADHOC_JOINED;
}
- dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: channel = %d\n",
- priv->adhoc_channel);
- dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: BSSID = %pM\n",
- priv->curr_bss_params.bss_descriptor.mac_address);
+ mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_RESP: channel = %d\n",
+ priv->adhoc_channel);
+ mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_RESP: BSSID = %pM\n",
+ priv->curr_bss_params.bss_descriptor.mac_address);
if (!netif_carrier_ok(priv->netdev))
netif_carrier_on(priv->netdev);
@@ -1317,12 +1364,12 @@ int
mwifiex_adhoc_start(struct mwifiex_private *priv,
struct cfg80211_ssid *adhoc_ssid)
{
- dev_dbg(priv->adapter->dev, "info: Adhoc Channel = %d\n",
- priv->adhoc_channel);
- dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n",
- priv->curr_bss_params.bss_descriptor.channel);
- dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %d\n",
- priv->curr_bss_params.band);
+ mwifiex_dbg(priv->adapter, INFO, "info: Adhoc Channel = %d\n",
+ priv->adhoc_channel);
+ mwifiex_dbg(priv->adapter, INFO, "info: curr_bss_params.channel = %d\n",
+ priv->curr_bss_params.bss_descriptor.channel);
+ mwifiex_dbg(priv->adapter, INFO, "info: curr_bss_params.band = %d\n",
+ priv->curr_bss_params.band);
if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
priv->adapter->config_bands & BAND_AAC)
@@ -1343,14 +1390,16 @@ mwifiex_adhoc_start(struct mwifiex_private *priv,
int mwifiex_adhoc_join(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc)
{
- dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid =%s\n",
- priv->curr_bss_params.bss_descriptor.ssid.ssid);
- dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid_len =%u\n",
- priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
- dev_dbg(priv->adapter->dev, "info: adhoc join: ssid =%s\n",
- bss_desc->ssid.ssid);
- dev_dbg(priv->adapter->dev, "info: adhoc join: ssid_len =%u\n",
- bss_desc->ssid.ssid_len);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: adhoc join: curr_bss ssid =%s\n",
+ priv->curr_bss_params.bss_descriptor.ssid.ssid);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: adhoc join: curr_bss ssid_len =%u\n",
+ priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
+ mwifiex_dbg(priv->adapter, INFO, "info: adhoc join: ssid =%s\n",
+ bss_desc->ssid.ssid);
+ mwifiex_dbg(priv->adapter, INFO, "info: adhoc join: ssid_len =%u\n",
+ bss_desc->ssid.ssid_len);
/* Check if the requested SSID is already joined */
if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len &&
@@ -1358,8 +1407,9 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv,
&priv->curr_bss_params.bss_descriptor.ssid) &&
(priv->curr_bss_params.bss_descriptor.bss_mode ==
NL80211_IFTYPE_ADHOC)) {
- dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: new ad-hoc SSID"
- " is the same as current; not attempting to re-join\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ADHOC_J_CMD: new ad-hoc SSID\t"
+ "is the same as current; not attempting to re-join\n");
return -1;
}
@@ -1370,10 +1420,12 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv,
else
mwifiex_set_ba_params(priv);
- dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n",
- priv->curr_bss_params.bss_descriptor.channel);
- dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n",
- priv->curr_bss_params.band);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: curr_bss_params.channel = %d\n",
+ priv->curr_bss_params.bss_descriptor.channel);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: curr_bss_params.band = %c\n",
+ priv->curr_bss_params.band);
return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
HostCmd_ACT_GEN_SET, 0, bss_desc, true);
@@ -1421,7 +1473,7 @@ int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
ret = mwifiex_deauthenticate_infra(priv, mac);
if (ret)
cfg80211_disconnected(priv->netdev, 0, NULL, 0,
- GFP_KERNEL);
+ true, GFP_KERNEL);
break;
case NL80211_IFTYPE_ADHOC:
return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP,
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 03a95c7d34bf..3ba4e0e04223 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -24,6 +24,10 @@
#define VERSION "1.0"
+static unsigned int debug_mask = MWIFIEX_DEFAULT_DEBUG_MASK;
+module_param(debug_mask, uint, 0);
+MODULE_PARM_DESC(debug_mask, "bitmap for debug flags");
+
const char driver_version[] = "mwifiex " VERSION " (%s) ";
static char *cal_data_cfg;
module_param(cal_data_cfg, charp, 0);
@@ -63,6 +67,7 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
/* Save interface specific operations in adapter */
memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops));
+ adapter->debug_mask = debug_mask;
/* card specific initialization has been deferred until now .. */
if (adapter->if_ops.init_if)
@@ -89,7 +94,8 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
return 0;
error:
- dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n");
+ mwifiex_dbg(adapter, ERROR,
+ "info: leave mwifiex_register with error\n");
for (i = 0; i < adapter->priv_num; i++)
kfree(adapter->priv[i]);
@@ -231,11 +237,10 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter)
goto exit_main_proc;
} else {
adapter->mwifiex_processing = true;
+ spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
}
process_start:
do {
- adapter->more_task_flag = false;
- spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
if ((adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) ||
(adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY))
break;
@@ -275,7 +280,6 @@ process_start:
adapter->pm_wakeup_fw_try = true;
mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3));
adapter->if_ops.wakeup(adapter);
- spin_lock_irqsave(&adapter->main_proc_lock, flags);
continue;
}
@@ -335,7 +339,6 @@ process_start:
(adapter->ps_state == PS_STATE_PRE_SLEEP) ||
(adapter->ps_state == PS_STATE_SLEEP_CFM) ||
adapter->tx_lock_flag){
- spin_lock_irqsave(&adapter->main_proc_lock, flags);
continue;
}
@@ -386,12 +389,14 @@ process_start:
}
break;
}
- spin_lock_irqsave(&adapter->main_proc_lock, flags);
} while (true);
spin_lock_irqsave(&adapter->main_proc_lock, flags);
- if (adapter->more_task_flag)
+ if (adapter->more_task_flag) {
+ adapter->more_task_flag = false;
+ spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
goto process_start;
+ }
adapter->mwifiex_processing = false;
spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
@@ -455,8 +460,8 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
struct wireless_dev *wdev;
if (!firmware) {
- dev_err(adapter->dev,
- "Failed to get firmware %s\n", adapter->fw_name);
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to get firmware %s\n", adapter->fw_name);
goto err_dnld_fw;
}
@@ -472,13 +477,13 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
if (ret == -1)
goto err_dnld_fw;
- dev_notice(adapter->dev, "WLAN FW is active\n");
+ mwifiex_dbg(adapter, MSG, "WLAN FW is active\n");
if (cal_data_cfg) {
if ((request_firmware(&adapter->cal_data, cal_data_cfg,
adapter->dev)) < 0)
- dev_err(adapter->dev,
- "Cal data request_firmware() failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Cal data request_firmware() failed\n");
}
/* enable host interrupt after fw dnld is successful */
@@ -503,12 +508,14 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
priv = adapter->priv[MWIFIEX_BSS_ROLE_STA];
if (mwifiex_register_cfg80211(adapter)) {
- dev_err(adapter->dev, "cannot register with cfg80211\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot register with cfg80211\n");
goto err_init_fw;
}
if (mwifiex_init_channel_scan_gap(adapter)) {
- dev_err(adapter->dev, "could not init channel stats table\n");
+ mwifiex_dbg(adapter, ERROR,
+ "could not init channel stats table\n");
goto err_init_fw;
}
@@ -522,7 +529,8 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", NET_NAME_ENUM,
NL80211_IFTYPE_STATION, NULL, NULL);
if (IS_ERR(wdev)) {
- dev_err(adapter->dev, "cannot create default STA interface\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create default STA interface\n");
rtnl_unlock();
goto err_add_intf;
}
@@ -531,7 +539,8 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", NET_NAME_ENUM,
NL80211_IFTYPE_AP, NULL, NULL);
if (IS_ERR(wdev)) {
- dev_err(adapter->dev, "cannot create AP interface\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create AP interface\n");
rtnl_unlock();
goto err_add_intf;
}
@@ -542,8 +551,8 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
NL80211_IFTYPE_P2P_CLIENT, NULL,
NULL);
if (IS_ERR(wdev)) {
- dev_err(adapter->dev,
- "cannot create p2p client interface\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create p2p client interface\n");
rtnl_unlock();
goto err_add_intf;
}
@@ -551,7 +560,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
rtnl_unlock();
mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
- dev_notice(adapter->dev, "driver_version = %s\n", fmt);
+ mwifiex_dbg(adapter, MSG, "driver_version = %s\n", fmt);
goto done;
err_add_intf:
@@ -561,7 +570,8 @@ err_init_fw:
if (adapter->if_ops.disable_int)
adapter->if_ops.disable_int(adapter);
err_dnld_fw:
- pr_debug("info: %s: unregister device\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "info: %s: unregister device\n", __func__);
if (adapter->if_ops.unregister_dev)
adapter->if_ops.unregister_dev(adapter);
@@ -602,8 +612,8 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
adapter->dev, GFP_KERNEL, adapter,
mwifiex_fw_dpc);
if (ret < 0)
- dev_err(adapter->dev,
- "request_firmware_nowait() returned error %d\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "request_firmware_nowait error %d\n", ret);
return ret;
}
@@ -629,7 +639,8 @@ mwifiex_close(struct net_device *dev)
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (priv->scan_request) {
- dev_dbg(priv->adapter->dev, "aborting scan on ndo_stop\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "aborting scan on ndo_stop\n");
cfg80211_scan_done(priv->scan_request, 1);
priv->scan_request = NULL;
priv->scan_aborting = true;
@@ -650,7 +661,8 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
txq = netdev_get_tx_queue(priv->netdev, index);
if (!netif_tx_queue_stopped(txq)) {
netif_tx_stop_queue(txq);
- dev_dbg(priv->adapter->dev, "stop queue: %d\n", index);
+ mwifiex_dbg(priv->adapter, DATA,
+ "stop queue: %d\n", index);
}
}
@@ -715,8 +727,9 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct mwifiex_txinfo *tx_info;
bool multicast;
- dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n",
- jiffies, priv->bss_type, priv->bss_num);
+ mwifiex_dbg(priv->adapter, DATA,
+ "data: %lu BSS(%d-%d): Data <= kernel\n",
+ jiffies, priv->bss_type, priv->bss_num);
if (priv->adapter->surprise_removed) {
kfree_skb(skb);
@@ -724,28 +737,31 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
- dev_err(priv->adapter->dev, "Tx: bad skb len %d\n", skb->len);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Tx: bad skb len %d\n", skb->len);
kfree_skb(skb);
priv->stats.tx_dropped++;
return 0;
}
if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) {
- dev_dbg(priv->adapter->dev,
- "data: Tx: insufficient skb headroom %d\n",
- skb_headroom(skb));
+ mwifiex_dbg(priv->adapter, DATA,
+ "data: Tx: insufficient skb headroom %d\n",
+ skb_headroom(skb));
/* Insufficient skb headroom - allocate a new skb */
new_skb =
skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
if (unlikely(!new_skb)) {
- dev_err(priv->adapter->dev, "Tx: cannot alloca new_skb\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Tx: cannot alloca new_skb\n");
kfree_skb(skb);
priv->stats.tx_dropped++;
return 0;
}
kfree_skb(skb);
skb = new_skb;
- dev_dbg(priv->adapter->dev, "info: new skb headroomd %d\n",
- skb_headroom(skb));
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: new skb headroomd %d\n",
+ skb_headroom(skb));
}
tx_info = MWIFIEX_SKB_TXCB(skb);
@@ -803,8 +819,8 @@ mwifiex_set_mac_address(struct net_device *dev, void *addr)
if (!ret)
memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN);
else
- dev_err(priv->adapter->dev,
- "set mac address failed: ret=%d\n", ret);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "set mac address failed: ret=%d\n", ret);
memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
@@ -842,20 +858,22 @@ mwifiex_tx_timeout(struct net_device *dev)
priv->num_tx_timeout++;
priv->tx_timeout_cnt++;
- dev_err(priv->adapter->dev,
- "%lu : Tx timeout(#%d), bss_type-num = %d-%d\n",
- jiffies, priv->tx_timeout_cnt, priv->bss_type, priv->bss_num);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%lu : Tx timeout(#%d), bss_type-num = %d-%d\n",
+ jiffies, priv->tx_timeout_cnt, priv->bss_type,
+ priv->bss_num);
mwifiex_set_trans_start(dev);
if (priv->tx_timeout_cnt > TX_TIMEOUT_THRESHOLD &&
priv->adapter->if_ops.card_reset) {
- dev_err(priv->adapter->dev,
- "tx_timeout_cnt exceeds threshold. Triggering card reset!\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "tx_timeout_cnt exceeds threshold.\t"
+ "Triggering card reset!\n");
priv->adapter->if_ops.card_reset(priv->adapter);
}
}
-void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter)
+void mwifiex_drv_info_dump(struct mwifiex_adapter *adapter)
{
void *p;
char drv_version[64];
@@ -868,10 +886,11 @@ void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter)
if (adapter->drv_info_dump) {
vfree(adapter->drv_info_dump);
+ adapter->drv_info_dump = NULL;
adapter->drv_info_size = 0;
}
- dev_info(adapter->dev, "=== DRIVER INFO DUMP START===\n");
+ mwifiex_dbg(adapter, MSG, "===mwifiex driverinfo dump start===\n");
adapter->drv_info_dump = vzalloc(MWIFIEX_DRV_INFO_SIZE_MAX);
@@ -939,12 +958,12 @@ void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter)
}
if (adapter->iface_type == MWIFIEX_SDIO) {
- p += sprintf(p, "\n=== SDIO register DUMP===\n");
+ p += sprintf(p, "\n=== SDIO register dump===\n");
if (adapter->if_ops.reg_dump)
p += adapter->if_ops.reg_dump(adapter, p);
}
- p += sprintf(p, "\n=== MORE DEBUG INFORMATION\n");
+ p += sprintf(p, "\n=== more debug information\n");
debug_info = kzalloc(sizeof(*debug_info), GFP_KERNEL);
if (debug_info) {
for (i = 0; i < adapter->priv_num; i++) {
@@ -959,9 +978,99 @@ void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter)
}
adapter->drv_info_size = p - adapter->drv_info_dump;
- dev_info(adapter->dev, "=== DRIVER INFO DUMP END===\n");
+ mwifiex_dbg(adapter, MSG, "===mwifiex driverinfo dump end===\n");
+}
+EXPORT_SYMBOL_GPL(mwifiex_drv_info_dump);
+
+void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter)
+{
+ u8 idx, *dump_data, *fw_dump_ptr;
+ u32 dump_len;
+
+ dump_len = (strlen("========Start dump driverinfo========\n") +
+ adapter->drv_info_size +
+ strlen("\n========End dump========\n"));
+
+ for (idx = 0; idx < adapter->num_mem_types; idx++) {
+ struct memory_type_mapping *entry =
+ &adapter->mem_type_mapping_tbl[idx];
+
+ if (entry->mem_ptr) {
+ dump_len += (strlen("========Start dump ") +
+ strlen(entry->mem_name) +
+ strlen("========\n") +
+ (entry->mem_size + 1) +
+ strlen("\n========End dump========\n"));
+ }
+ }
+
+ dump_data = vzalloc(dump_len + 1);
+ if (!dump_data)
+ goto done;
+
+ fw_dump_ptr = dump_data;
+
+ /* Dump all the memory data into single file, a userspace script will
+ * be used to split all the memory data to multiple files
+ */
+ mwifiex_dbg(adapter, MSG,
+ "== mwifiex dump information to /sys/class/devcoredump start");
+
+ strcpy(fw_dump_ptr, "========Start dump driverinfo========\n");
+ fw_dump_ptr += strlen("========Start dump driverinfo========\n");
+ memcpy(fw_dump_ptr, adapter->drv_info_dump, adapter->drv_info_size);
+ fw_dump_ptr += adapter->drv_info_size;
+ strcpy(fw_dump_ptr, "\n========End dump========\n");
+ fw_dump_ptr += strlen("\n========End dump========\n");
+
+ for (idx = 0; idx < adapter->num_mem_types; idx++) {
+ struct memory_type_mapping *entry =
+ &adapter->mem_type_mapping_tbl[idx];
+
+ if (entry->mem_ptr) {
+ strcpy(fw_dump_ptr, "========Start dump ");
+ fw_dump_ptr += strlen("========Start dump ");
+
+ strcpy(fw_dump_ptr, entry->mem_name);
+ fw_dump_ptr += strlen(entry->mem_name);
+
+ strcpy(fw_dump_ptr, "========\n");
+ fw_dump_ptr += strlen("========\n");
+
+ memcpy(fw_dump_ptr, entry->mem_ptr, entry->mem_size);
+ fw_dump_ptr += entry->mem_size;
+
+ strcpy(fw_dump_ptr, "\n========End dump========\n");
+ fw_dump_ptr += strlen("\n========End dump========\n");
+ }
+ }
+
+ /* device dump data will be free in device coredump release function
+ * after 5 min
+ */
+ dev_coredumpv(adapter->dev, dump_data, dump_len, GFP_KERNEL);
+ mwifiex_dbg(adapter, MSG,
+ "== mwifiex dump information to /sys/class/devcoredump end");
+
+done:
+ for (idx = 0; idx < adapter->num_mem_types; idx++) {
+ struct memory_type_mapping *entry =
+ &adapter->mem_type_mapping_tbl[idx];
+
+ if (entry->mem_ptr) {
+ vfree(entry->mem_ptr);
+ entry->mem_ptr = NULL;
+ }
+ entry->mem_size = 0;
+ }
+
+ if (adapter->drv_info_dump) {
+ vfree(adapter->drv_info_dump);
+ adapter->drv_info_dump = NULL;
+ adapter->drv_info_size = 0;
+ }
}
-EXPORT_SYMBOL_GPL(mwifiex_dump_drv_info);
+EXPORT_SYMBOL_GPL(mwifiex_upload_device_dump);
/*
* CFG802.11 network device handler for statistics retrieval.
@@ -1230,21 +1339,24 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
}
}
- dev_dbg(adapter->dev, "cmd: calling mwifiex_shutdown_drv...\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: calling mwifiex_shutdown_drv...\n");
adapter->init_wait_q_woken = false;
if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS)
wait_event_interruptible(adapter->init_wait_q,
adapter->init_wait_q_woken);
- dev_dbg(adapter->dev, "cmd: mwifiex_shutdown_drv done\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: mwifiex_shutdown_drv done\n");
if (atomic_read(&adapter->rx_pending) ||
atomic_read(&adapter->tx_pending) ||
atomic_read(&adapter->cmd_pending)) {
- dev_err(adapter->dev, "rx_pending=%d, tx_pending=%d, "
- "cmd_pending=%d\n",
- atomic_read(&adapter->rx_pending),
- atomic_read(&adapter->tx_pending),
- atomic_read(&adapter->cmd_pending));
+ mwifiex_dbg(adapter, ERROR,
+ "rx_pending=%d, tx_pending=%d,\t"
+ "cmd_pending=%d\n",
+ atomic_read(&adapter->rx_pending),
+ atomic_read(&adapter->tx_pending),
+ atomic_read(&adapter->cmd_pending));
}
for (i = 0; i < adapter->priv_num; i++) {
@@ -1264,11 +1376,13 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
wiphy_free(adapter->wiphy);
/* Unregister device */
- dev_dbg(adapter->dev, "info: unregister device\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: unregister device\n");
if (adapter->if_ops.unregister_dev)
adapter->if_ops.unregister_dev(adapter);
/* Free adapter structure */
- dev_dbg(adapter->dev, "info: free adapter\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: free adapter\n");
mwifiex_free_adapter(adapter);
exit_remove:
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index fe1256044a6c..ae98b5b83b1f 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -36,6 +36,7 @@
#include <linux/of.h>
#include <linux/idr.h>
#include <linux/inetdevice.h>
+#include <linux/devcoredump.h>
#include "decl.h"
#include "ioctl.h"
@@ -147,6 +148,54 @@ enum {
/* Address alignment */
#define MWIFIEX_ALIGN_ADDR(p, a) (((long)(p) + (a) - 1) & ~((a) - 1))
+/**
+ *enum mwifiex_debug_level - marvell wifi debug level
+ */
+enum MWIFIEX_DEBUG_LEVEL {
+ MWIFIEX_DBG_MSG = 0x00000001,
+ MWIFIEX_DBG_FATAL = 0x00000002,
+ MWIFIEX_DBG_ERROR = 0x00000004,
+ MWIFIEX_DBG_DATA = 0x00000008,
+ MWIFIEX_DBG_CMD = 0x00000010,
+ MWIFIEX_DBG_EVENT = 0x00000020,
+ MWIFIEX_DBG_INTR = 0x00000040,
+ MWIFIEX_DBG_IOCTL = 0x00000080,
+
+ MWIFIEX_DBG_MPA_D = 0x00008000,
+ MWIFIEX_DBG_DAT_D = 0x00010000,
+ MWIFIEX_DBG_CMD_D = 0x00020000,
+ MWIFIEX_DBG_EVT_D = 0x00040000,
+ MWIFIEX_DBG_FW_D = 0x00080000,
+ MWIFIEX_DBG_IF_D = 0x00100000,
+
+ MWIFIEX_DBG_ENTRY = 0x10000000,
+ MWIFIEX_DBG_WARN = 0x20000000,
+ MWIFIEX_DBG_INFO = 0x40000000,
+ MWIFIEX_DBG_DUMP = 0x80000000,
+
+ MWIFIEX_DBG_ANY = 0xffffffff
+};
+
+#define MWIFIEX_DEFAULT_DEBUG_MASK (MWIFIEX_DBG_MSG | \
+ MWIFIEX_DBG_FATAL | \
+ MWIFIEX_DBG_ERROR)
+
+#define mwifiex_dbg(adapter, dbg_mask, fmt, args...) \
+do { \
+ if ((adapter)->debug_mask & MWIFIEX_DBG_##dbg_mask) \
+ if ((adapter)->dev) \
+ dev_info((adapter)->dev, fmt, ## args); \
+} while (0)
+
+#define DEBUG_DUMP_DATA_MAX_LEN 128
+#define mwifiex_dbg_dump(adapter, dbg_mask, str, buf, len) \
+do { \
+ if ((adapter)->debug_mask & MWIFIEX_DBG_##dbg_mask) \
+ print_hex_dump(KERN_DEBUG, str, \
+ DUMP_PREFIX_OFFSET, 16, 1, \
+ buf, len, false); \
+} while (0)
+
struct mwifiex_dbg {
u32 num_cmd_host_to_card_failure;
u32 num_cmd_sleep_cfm_host_to_card_failure;
@@ -451,7 +500,7 @@ enum rdwr_status {
};
enum mwifiex_iface_work_flags {
- MWIFIEX_IFACE_WORK_FW_DUMP,
+ MWIFIEX_IFACE_WORK_DEVICE_DUMP,
MWIFIEX_IFACE_WORK_CARD_RESET,
};
@@ -593,6 +642,7 @@ struct mwifiex_private {
u8 del_list_idx;
bool hs2_enabled;
struct mwifiex_uap_bss_param bss_cfg;
+ struct cfg80211_chan_def bss_chandef;
struct station_parameters *sta_params;
struct sk_buff_head tdls_txq;
u8 check_tdls_tx;
@@ -611,6 +661,7 @@ struct mwifiex_private {
struct delayed_work dfs_chan_sw_work;
struct cfg80211_beacon_data beacon_after;
struct mwifiex_11h_intf_state state_11h;
+ struct mwifiex_ds_mem_rw mem_rw;
};
@@ -690,6 +741,18 @@ struct mwifiex_tdls_capab {
struct ieee80211_vht_operation vhtoper;
};
+struct mwifiex_station_stats {
+ u64 last_rx;
+ s8 rssi;
+ u64 rx_bytes;
+ u64 tx_bytes;
+ u32 rx_packets;
+ u32 tx_packets;
+ u32 tx_failed;
+ u8 last_tx_rate;
+ u8 last_tx_htinfo;
+};
+
/* This is AP/TDLS specific structure which stores information
* about associated/peer STA
*/
@@ -704,6 +767,7 @@ struct mwifiex_sta_node {
u16 max_amsdu;
u8 tdls_status;
struct mwifiex_tdls_capab tdls_cap;
+ struct mwifiex_station_stats stats;
};
struct mwifiex_auto_tdls_peer {
@@ -740,8 +804,8 @@ struct mwifiex_if_ops {
int (*init_fw_port) (struct mwifiex_adapter *);
int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
void (*card_reset) (struct mwifiex_adapter *);
- void (*fw_dump)(struct mwifiex_adapter *);
int (*reg_dump)(struct mwifiex_adapter *, char *);
+ void (*device_dump)(struct mwifiex_adapter *);
int (*clean_pcie_ring) (struct mwifiex_adapter *adapter);
void (*iface_work)(struct work_struct *work);
void (*submit_rem_rx_urbs)(struct mwifiex_adapter *adapter);
@@ -750,6 +814,7 @@ struct mwifiex_if_ops {
struct mwifiex_adapter {
u8 iface_type;
+ unsigned int debug_mask;
struct mwifiex_iface_comb iface_limit;
struct mwifiex_iface_comb curr_iface_comb;
struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM];
@@ -900,7 +965,6 @@ struct mwifiex_adapter {
u8 key_api_major_ver, key_api_minor_ver;
struct memory_type_mapping *mem_type_mapping_tbl;
u8 num_mem_types;
- u8 curr_mem_idx;
void *drv_info_dump;
u32 drv_info_size;
bool scan_chan_gap_enabled;
@@ -909,6 +973,12 @@ struct mwifiex_adapter {
u32 num_in_chan_stats;
int survey_idx;
bool auto_tdls;
+ u8 coex_scan;
+ u8 coex_min_scan_time;
+ u8 coex_max_scan_time;
+ u8 coex_win_size;
+ u8 coex_tx_win_size;
+ u8 coex_rx_win_size;
};
void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
@@ -1085,6 +1155,9 @@ void mwifiex_set_ht_params(struct mwifiex_private *priv,
void mwifiex_set_vht_params(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
+void mwifiex_set_tpc_params(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_ap_settings *params);
void mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
void mwifiex_set_vht_width(struct mwifiex_private *priv,
@@ -1095,6 +1168,11 @@ mwifiex_set_wmm_params(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
void mwifiex_set_ba_params(struct mwifiex_private *priv);
+
+void mwifiex_update_ampdu_txwinsize(struct mwifiex_adapter *pmadapter);
+void mwifiex_bt_coex_wlan_param_update_event(struct mwifiex_private *priv,
+ struct sk_buff *event_skb);
+
void mwifiex_set_11ac_ba_params(struct mwifiex_private *priv);
int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
@@ -1332,6 +1410,7 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc);
u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type);
+u8 mwifiex_sec_chan_offset_to_chan_type(u8 second_chan_offset);
struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
const char *name,
@@ -1349,7 +1428,8 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
struct cfg80211_beacon_data *data);
int mwifiex_del_mgmt_ies(struct mwifiex_private *priv);
u8 *mwifiex_11d_code_2_region(u8 code);
-void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg,
+void mwifiex_uap_set_channel(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_chan_def chandef);
int mwifiex_config_start_uap(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_cfg);
@@ -1423,6 +1503,8 @@ mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv,
void mwifiex_dfs_cac_work_queue(struct work_struct *work);
void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work);
void mwifiex_abort_cac(struct mwifiex_private *priv);
+int mwifiex_stop_radar_detection(struct mwifiex_private *priv,
+ struct cfg80211_chan_def *chandef);
int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
struct sk_buff *skb);
@@ -1434,10 +1516,12 @@ void mwifiex_hist_data_add(struct mwifiex_private *priv,
u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv,
u8 rx_rate, u8 ht_info);
-void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter);
+void mwifiex_drv_info_dump(struct mwifiex_adapter *adapter);
+void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter);
void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags);
void mwifiex_queue_main_work(struct mwifiex_adapter *adapter);
-
+void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter);
+void mwifiex_11n_delba(struct mwifiex_private *priv, int tid);
#ifdef CONFIG_DEBUG_FS
void mwifiex_debugfs_init(void);
void mwifiex_debugfs_remove(void);
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index bcc7751d883c..77b9055a2d14 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -57,7 +57,7 @@ mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
mapping.addr = pci_map_single(card->dev, skb->data, size, flags);
if (pci_dma_mapping_error(card->dev, mapping.addr)) {
- dev_err(adapter->dev, "failed to map pci memory!\n");
+ mwifiex_dbg(adapter, ERROR, "failed to map pci memory!\n");
return -1;
}
mapping.len = size;
@@ -89,8 +89,9 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter)
if (card->sleep_cookie_vbase) {
cookie_addr = (u32 *)card->sleep_cookie_vbase;
- dev_dbg(adapter->dev, "info: ACCESS_HW: sleep cookie=0x%x\n",
- *cookie_addr);
+ mwifiex_dbg(adapter, INFO,
+ "info: ACCESS_HW: sleep cookie=0x%x\n",
+ *cookie_addr);
if (*cookie_addr == FW_AWAKE_COOKIE)
return true;
}
@@ -164,7 +165,8 @@ static int mwifiex_pcie_resume(struct device *dev)
adapter = card->adapter;
if (!adapter->is_suspended) {
- dev_warn(adapter->dev, "Device already resumed\n");
+ mwifiex_dbg(adapter, WARN,
+ "Device already resumed\n");
return 0;
}
@@ -361,16 +363,16 @@ static void mwifiex_delay_for_sleep_cookie(struct mwifiex_adapter *adapter,
sleep_cookie = *(u32 *)buffer;
if (sleep_cookie == MWIFIEX_DEF_SLEEP_COOKIE) {
- dev_dbg(adapter->dev,
- "sleep cookie found at count %d\n", count);
+ mwifiex_dbg(adapter, INFO,
+ "sleep cookie found at count %d\n", count);
break;
}
usleep_range(20, 30);
}
if (count >= max_delay_loop_cnt)
- dev_dbg(adapter->dev,
- "max count reached while accessing sleep cookie\n");
+ mwifiex_dbg(adapter, INFO,
+ "max count reached while accessing sleep cookie\n");
}
/* This function wakes up the card by reading fw_status register. */
@@ -380,20 +382,23 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
struct pcie_service_card *card = adapter->card;
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
- dev_dbg(adapter->dev, "event: Wakeup device...\n");
+ mwifiex_dbg(adapter, EVENT,
+ "event: Wakeup device...\n");
if (reg->sleep_cookie)
mwifiex_pcie_dev_wakeup_delay(adapter);
/* Reading fw_status register will wakeup device */
if (mwifiex_read_reg(adapter, reg->fw_status, &fw_status)) {
- dev_warn(adapter->dev, "Reading fw_status register failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Reading fw_status register failed\n");
return -1;
}
if (reg->sleep_cookie) {
mwifiex_pcie_dev_wakeup_delay(adapter);
- dev_dbg(adapter->dev, "PCIE wakeup: Setting PS_STATE_AWAKE\n");
+ mwifiex_dbg(adapter, INFO,
+ "PCIE wakeup: Setting PS_STATE_AWAKE\n");
adapter->ps_state = PS_STATE_AWAKE;
}
@@ -407,7 +412,8 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
*/
static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
{
- dev_dbg(adapter->dev, "cmd: Wakeup device completed\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: Wakeup device completed\n");
return 0;
}
@@ -423,7 +429,8 @@ static int mwifiex_pcie_disable_host_int(struct mwifiex_adapter *adapter)
if (mwifiex_pcie_ok_to_access_hw(adapter)) {
if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK,
0x00000000)) {
- dev_warn(adapter->dev, "Disable host interrupt failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Disable host interrupt failed\n");
return -1;
}
}
@@ -443,7 +450,8 @@ static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter)
/* Simply write the mask to the register */
if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK,
HOST_INTR_MASK)) {
- dev_warn(adapter->dev, "Enable host interrupt failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Enable host interrupt failed\n");
return -1;
}
}
@@ -499,8 +507,8 @@ static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter)
skb = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE,
GFP_KERNEL | GFP_DMA);
if (!skb) {
- dev_err(adapter->dev,
- "Unable to allocate skb for RX ring.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Unable to allocate skb for RX ring.\n");
kfree(card->rxbd_ring_vbase);
return -ENOMEM;
}
@@ -512,10 +520,10 @@ static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter)
buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
- dev_dbg(adapter->dev,
- "info: RX ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
- skb, skb->len, skb->data, (u32)buf_pa,
- (u32)((u64)buf_pa >> 32));
+ mwifiex_dbg(adapter, INFO,
+ "info: RX ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
+ skb, skb->len, skb->data, (u32)buf_pa,
+ (u32)((u64)buf_pa >> 32));
card->rx_buf_list[i] = skb;
if (reg->pfu_enabled) {
@@ -556,8 +564,8 @@ static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter)
/* Allocate skb here so that firmware can DMA data from it */
skb = dev_alloc_skb(MAX_EVENT_SIZE);
if (!skb) {
- dev_err(adapter->dev,
- "Unable to allocate skb for EVENT buf.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Unable to allocate skb for EVENT buf.\n");
kfree(card->evtbd_ring_vbase);
return -ENOMEM;
}
@@ -569,10 +577,10 @@ static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter)
buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
- dev_dbg(adapter->dev,
- "info: EVT ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
- skb, skb->len, skb->data, (u32)buf_pa,
- (u32)((u64)buf_pa >> 32));
+ mwifiex_dbg(adapter, EVENT,
+ "info: EVT ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
+ skb, skb->len, skb->data, (u32)buf_pa,
+ (u32)((u64)buf_pa >> 32));
card->evt_buf_list[i] = skb;
card->evtbd_ring[i] = (void *)(card->evtbd_ring_vbase +
@@ -715,21 +723,23 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
MWIFIEX_MAX_TXRX_BD;
- dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n",
- card->txbd_ring_size);
+ mwifiex_dbg(adapter, INFO,
+ "info: txbd_ring: Allocating %d bytes\n",
+ card->txbd_ring_size);
card->txbd_ring_vbase = pci_alloc_consistent(card->dev,
card->txbd_ring_size,
&card->txbd_ring_pbase);
if (!card->txbd_ring_vbase) {
- dev_err(adapter->dev,
- "allocate consistent memory (%d bytes) failed!\n",
- card->txbd_ring_size);
+ mwifiex_dbg(adapter, ERROR,
+ "allocate consistent memory (%d bytes) failed!\n",
+ card->txbd_ring_size);
return -ENOMEM;
}
- dev_dbg(adapter->dev,
- "info: txbd_ring - base: %p, pbase: %#x:%x, len: %x\n",
- card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase,
- (u32)((u64)card->txbd_ring_pbase >> 32), card->txbd_ring_size);
+ mwifiex_dbg(adapter, DATA,
+ "info: txbd_ring - base: %p, pbase: %#x:%x, len: %x\n",
+ card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase,
+ (u32)((u64)card->txbd_ring_pbase >> 32),
+ card->txbd_ring_size);
return mwifiex_init_txq_ring(adapter);
}
@@ -777,23 +787,24 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
MWIFIEX_MAX_TXRX_BD;
- dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n",
- card->rxbd_ring_size);
+ mwifiex_dbg(adapter, INFO,
+ "info: rxbd_ring: Allocating %d bytes\n",
+ card->rxbd_ring_size);
card->rxbd_ring_vbase = pci_alloc_consistent(card->dev,
card->rxbd_ring_size,
&card->rxbd_ring_pbase);
if (!card->rxbd_ring_vbase) {
- dev_err(adapter->dev,
- "allocate consistent memory (%d bytes) failed!\n",
- card->rxbd_ring_size);
+ mwifiex_dbg(adapter, ERROR,
+ "allocate consistent memory (%d bytes) failed!\n",
+ card->rxbd_ring_size);
return -ENOMEM;
}
- dev_dbg(adapter->dev,
- "info: rxbd_ring - base: %p, pbase: %#x:%x, len: %#x\n",
- card->rxbd_ring_vbase, (u32)card->rxbd_ring_pbase,
- (u32)((u64)card->rxbd_ring_pbase >> 32),
- card->rxbd_ring_size);
+ mwifiex_dbg(adapter, DATA,
+ "info: rxbd_ring - base: %p, pbase: %#x:%x, len: %#x\n",
+ card->rxbd_ring_vbase, (u32)card->rxbd_ring_pbase,
+ (u32)((u64)card->rxbd_ring_pbase >> 32),
+ card->rxbd_ring_size);
return mwifiex_init_rxq_ring(adapter);
}
@@ -840,23 +851,24 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
card->evtbd_ring_size = sizeof(struct mwifiex_evt_buf_desc) *
MWIFIEX_MAX_EVT_BD;
- dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n",
+ mwifiex_dbg(adapter, INFO,
+ "info: evtbd_ring: Allocating %d bytes\n",
card->evtbd_ring_size);
card->evtbd_ring_vbase = pci_alloc_consistent(card->dev,
card->evtbd_ring_size,
&card->evtbd_ring_pbase);
if (!card->evtbd_ring_vbase) {
- dev_err(adapter->dev,
- "allocate consistent memory (%d bytes) failed!\n",
- card->evtbd_ring_size);
+ mwifiex_dbg(adapter, ERROR,
+ "allocate consistent memory (%d bytes) failed!\n",
+ card->evtbd_ring_size);
return -ENOMEM;
}
- dev_dbg(adapter->dev,
- "info: CMDRSP/EVT bd_ring - base: %p pbase: %#x:%x len: %#x\n",
- card->evtbd_ring_vbase, (u32)card->evtbd_ring_pbase,
- (u32)((u64)card->evtbd_ring_pbase >> 32),
- card->evtbd_ring_size);
+ mwifiex_dbg(adapter, EVENT,
+ "info: CMDRSP/EVT bd_ring - base: %p pbase: %#x:%x len: %#x\n",
+ card->evtbd_ring_vbase, (u32)card->evtbd_ring_pbase,
+ (u32)((u64)card->evtbd_ring_pbase >> 32),
+ card->evtbd_ring_size);
return mwifiex_pcie_init_evt_ring(adapter);
}
@@ -895,8 +907,8 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter)
/* Allocate memory for receiving command response data */
skb = dev_alloc_skb(MWIFIEX_UPLD_SIZE);
if (!skb) {
- dev_err(adapter->dev,
- "Unable to allocate skb for command response data.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Unable to allocate skb for command response data.\n");
return -ENOMEM;
}
skb_put(skb, MWIFIEX_UPLD_SIZE);
@@ -944,14 +956,16 @@ static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter)
card->sleep_cookie_vbase = pci_alloc_consistent(card->dev, sizeof(u32),
&card->sleep_cookie_pbase);
if (!card->sleep_cookie_vbase) {
- dev_err(adapter->dev, "pci_alloc_consistent failed!\n");
+ mwifiex_dbg(adapter, ERROR,
+ "pci_alloc_consistent failed!\n");
return -ENOMEM;
}
/* Init val of Sleep Cookie */
*(u32 *)card->sleep_cookie_vbase = FW_AWAKE_COOKIE;
- dev_dbg(adapter->dev, "alloc_scook: sleep cookie=0x%x\n",
- *((u32 *)card->sleep_cookie_vbase));
+ mwifiex_dbg(adapter, INFO,
+ "alloc_scook: sleep cookie=0x%x\n",
+ *((u32 *)card->sleep_cookie_vbase));
return 0;
}
@@ -993,8 +1007,8 @@ static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter)
*/
if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
CPU_INTR_DNLD_RDY)) {
- dev_err(adapter->dev,
- "failed to assert dnld-rdy interrupt.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "failed to assert dnld-rdy interrupt.\n");
return -1;
}
}
@@ -1018,13 +1032,14 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
/* Read the TX ring read pointer set by firmware */
if (mwifiex_read_reg(adapter, reg->tx_rdptr, &rdptr)) {
- dev_err(adapter->dev,
- "SEND COMP: failed to read reg->tx_rdptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "SEND COMP: failed to read reg->tx_rdptr\n");
return -1;
}
- dev_dbg(adapter->dev, "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n",
- card->txbd_rdptr, rdptr);
+ mwifiex_dbg(adapter, DATA,
+ "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n",
+ card->txbd_rdptr, rdptr);
num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr;
/* free from previous txbd_rdptr to current txbd_rdptr */
@@ -1038,9 +1053,9 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
skb = card->tx_buf_list[wrdoneidx];
if (skb) {
- dev_dbg(adapter->dev,
- "SEND COMP: Detach skb %p at txbd_rdidx=%d\n",
- skb, wrdoneidx);
+ mwifiex_dbg(adapter, DATA,
+ "SEND COMP: Detach skb %p at txbd_rdidx=%d\n",
+ skb, wrdoneidx);
mwifiex_unmap_pci_memory(adapter, skb,
PCI_DMA_TODEVICE);
@@ -1112,8 +1127,9 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
__le16 *tmp;
if (!(skb->data && skb->len)) {
- dev_err(adapter->dev, "%s(): invalid parameter <%p, %#x>\n",
- __func__, skb->data, skb->len);
+ mwifiex_dbg(adapter, ERROR,
+ "%s(): invalid parameter <%p, %#x>\n",
+ __func__, skb->data, skb->len);
return -1;
}
@@ -1121,7 +1137,8 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
mwifiex_pm_wakeup_card(adapter);
num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr;
- dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n",
+ mwifiex_dbg(adapter, DATA,
+ "info: SEND DATA: <Rd: %#x, Wr: %#x>\n",
card->txbd_rdptr, card->txbd_wrptr);
if (mwifiex_pcie_txbd_not_full(card)) {
u8 *payload;
@@ -1175,39 +1192,40 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
/* Write the TX ring write pointer in to reg->tx_wrptr */
if (mwifiex_write_reg(adapter, reg->tx_wrptr,
card->txbd_wrptr | rx_val)) {
- dev_err(adapter->dev,
- "SEND DATA: failed to write reg->tx_wrptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "SEND DATA: failed to write reg->tx_wrptr\n");
ret = -1;
goto done_unmap;
}
if ((mwifiex_pcie_txbd_not_full(card)) &&
tx_param->next_pkt_len) {
/* have more packets and TxBD still can hold more */
- dev_dbg(adapter->dev,
- "SEND DATA: delay dnld-rdy interrupt.\n");
+ mwifiex_dbg(adapter, DATA,
+ "SEND DATA: delay dnld-rdy interrupt.\n");
adapter->data_sent = false;
} else {
/* Send the TX ready interrupt */
if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
CPU_INTR_DNLD_RDY)) {
- dev_err(adapter->dev,
- "SEND DATA: failed to assert dnld-rdy interrupt.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "SEND DATA: failed to assert dnld-rdy interrupt.\n");
ret = -1;
goto done_unmap;
}
}
- dev_dbg(adapter->dev, "info: SEND DATA: Updated <Rd: %#x, Wr: "
- "%#x> and sent packet to firmware successfully\n",
- card->txbd_rdptr, card->txbd_wrptr);
+ mwifiex_dbg(adapter, DATA,
+ "info: SEND DATA: Updated <Rd: %#x, Wr:\t"
+ "%#x> and sent packet to firmware successfully\n",
+ card->txbd_rdptr, card->txbd_wrptr);
} else {
- dev_dbg(adapter->dev,
- "info: TX Ring full, can't send packets to fw\n");
+ mwifiex_dbg(adapter, DATA,
+ "info: TX Ring full, can't send packets to fw\n");
adapter->data_sent = true;
/* Send the TX ready interrupt */
if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
CPU_INTR_DNLD_RDY))
- dev_err(adapter->dev,
- "SEND DATA: failed to assert door-bell intr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "SEND DATA: failed to assert door-bell intr\n");
return -EBUSY;
}
@@ -1243,8 +1261,8 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
/* Read the RX ring Write pointer set by firmware */
if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) {
- dev_err(adapter->dev,
- "RECV DATA: failed to read reg->rx_wrptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "RECV DATA: failed to read reg->rx_wrptr\n");
ret = -1;
goto done;
}
@@ -1277,15 +1295,15 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
rx_len = le16_to_cpu(pkt_len);
if (WARN_ON(rx_len <= INTF_HEADER_LEN ||
rx_len > MWIFIEX_RX_DATA_BUF_SIZE)) {
- dev_err(adapter->dev,
- "Invalid RX len %d, Rd=%#x, Wr=%#x\n",
- rx_len, card->rxbd_rdptr, wrptr);
+ mwifiex_dbg(adapter, ERROR,
+ "Invalid RX len %d, Rd=%#x, Wr=%#x\n",
+ rx_len, card->rxbd_rdptr, wrptr);
dev_kfree_skb_any(skb_data);
} else {
skb_put(skb_data, rx_len);
- dev_dbg(adapter->dev,
- "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
- card->rxbd_rdptr, wrptr, rx_len);
+ mwifiex_dbg(adapter, DATA,
+ "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
+ card->rxbd_rdptr, wrptr, rx_len);
skb_pull(skb_data, INTF_HEADER_LEN);
if (adapter->rx_work_enabled) {
skb_queue_tail(&adapter->rx_data_q, skb_data);
@@ -1299,8 +1317,8 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
skb_tmp = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE,
GFP_KERNEL | GFP_DMA);
if (!skb_tmp) {
- dev_err(adapter->dev,
- "Unable to allocate skb.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Unable to allocate skb.\n");
return -ENOMEM;
}
@@ -1311,9 +1329,9 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
buf_pa = MWIFIEX_SKB_DMA_ADDR(skb_tmp);
- dev_dbg(adapter->dev,
- "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n",
- skb_tmp, rd_index);
+ mwifiex_dbg(adapter, INFO,
+ "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n",
+ skb_tmp, rd_index);
card->rx_buf_list[rd_index] = skb_tmp;
if (reg->pfu_enabled) {
@@ -1336,28 +1354,29 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
reg->rx_rollover_ind) ^
reg->rx_rollover_ind);
}
- dev_dbg(adapter->dev, "info: RECV DATA: <Rd: %#x, Wr: %#x>\n",
- card->rxbd_rdptr, wrptr);
+ mwifiex_dbg(adapter, DATA,
+ "info: RECV DATA: <Rd: %#x, Wr: %#x>\n",
+ card->rxbd_rdptr, wrptr);
tx_val = card->txbd_wrptr & reg->tx_wrap_mask;
/* Write the RX ring read pointer in to reg->rx_rdptr */
if (mwifiex_write_reg(adapter, reg->rx_rdptr,
card->rxbd_rdptr | tx_val)) {
- dev_err(adapter->dev,
- "RECV DATA: failed to write reg->rx_rdptr\n");
+ mwifiex_dbg(adapter, DATA,
+ "RECV DATA: failed to write reg->rx_rdptr\n");
ret = -1;
goto done;
}
/* Read the RX ring Write pointer set by firmware */
if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) {
- dev_err(adapter->dev,
- "RECV DATA: failed to read reg->rx_wrptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "RECV DATA: failed to read reg->rx_wrptr\n");
ret = -1;
goto done;
}
- dev_dbg(adapter->dev,
- "info: RECV DATA: Rcvd packet from fw successfully\n");
+ mwifiex_dbg(adapter, DATA,
+ "info: RECV DATA: Rcvd packet from fw successfully\n");
card->rxbd_wrptr = wrptr;
}
@@ -1376,9 +1395,9 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
if (!(skb->data && skb->len)) {
- dev_err(adapter->dev,
- "Invalid parameter in %s <%p. len %d>\n",
- __func__, skb->data, skb->len);
+ mwifiex_dbg(adapter, ERROR,
+ "Invalid parameter in %s <%p. len %d>\n",
+ __func__, skb->data, skb->len);
return -1;
}
@@ -1391,9 +1410,9 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
* address scratch register
*/
if (mwifiex_write_reg(adapter, reg->cmd_addr_lo, (u32)buf_pa)) {
- dev_err(adapter->dev,
- "%s: failed to write download command to boot code.\n",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: failed to write download command to boot code.\n",
+ __func__);
mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
return -1;
}
@@ -1403,18 +1422,18 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
*/
if (mwifiex_write_reg(adapter, reg->cmd_addr_hi,
(u32)((u64)buf_pa >> 32))) {
- dev_err(adapter->dev,
- "%s: failed to write download command to boot code.\n",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: failed to write download command to boot code.\n",
+ __func__);
mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
return -1;
}
/* Write the command length to cmd_size scratch register */
if (mwifiex_write_reg(adapter, reg->cmd_size, skb->len)) {
- dev_err(adapter->dev,
- "%s: failed to write command len to cmd_size scratch reg\n",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: failed to write command len to cmd_size scratch reg\n",
+ __func__);
mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
return -1;
}
@@ -1422,8 +1441,8 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
/* Ring the door bell */
if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
CPU_INTR_DOOR_BELL)) {
- dev_err(adapter->dev,
- "%s: failed to assert door-bell intr\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: failed to assert door-bell intr\n", __func__);
mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
return -1;
}
@@ -1443,8 +1462,8 @@ static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter)
/* Write the RX ring read pointer in to reg->rx_rdptr */
if (mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr |
tx_wrap)) {
- dev_err(adapter->dev,
- "RECV DATA: failed to write reg->rx_rdptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "RECV DATA: failed to write reg->rx_rdptr\n");
return -1;
}
return 0;
@@ -1462,15 +1481,16 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
u8 *payload = (u8 *)skb->data;
if (!(skb->data && skb->len)) {
- dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x>\n",
- __func__, skb->data, skb->len);
+ mwifiex_dbg(adapter, ERROR,
+ "Invalid parameter in %s <%p, %#x>\n",
+ __func__, skb->data, skb->len);
return -1;
}
/* Make sure a command response buffer is available */
if (!card->cmdrsp_buf) {
- dev_err(adapter->dev,
- "No response buffer available, send command failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "No response buffer available, send command failed\n");
return -EBUSY;
}
@@ -1503,8 +1523,8 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
address */
if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo,
(u32)cmdrsp_buf_pa)) {
- dev_err(adapter->dev,
- "Failed to write download cmd to boot code.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to write download cmd to boot code.\n");
ret = -1;
goto done;
}
@@ -1512,8 +1532,8 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
address */
if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi,
(u32)((u64)cmdrsp_buf_pa >> 32))) {
- dev_err(adapter->dev,
- "Failed to write download cmd to boot code.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to write download cmd to boot code.\n");
ret = -1;
goto done;
}
@@ -1523,16 +1543,16 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
/* Write the lower 32bits of the physical address to reg->cmd_addr_lo */
if (mwifiex_write_reg(adapter, reg->cmd_addr_lo,
(u32)cmd_buf_pa)) {
- dev_err(adapter->dev,
- "Failed to write download cmd to boot code.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to write download cmd to boot code.\n");
ret = -1;
goto done;
}
/* Write the upper 32bits of the physical address to reg->cmd_addr_hi */
if (mwifiex_write_reg(adapter, reg->cmd_addr_hi,
(u32)((u64)cmd_buf_pa >> 32))) {
- dev_err(adapter->dev,
- "Failed to write download cmd to boot code.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to write download cmd to boot code.\n");
ret = -1;
goto done;
}
@@ -1540,8 +1560,8 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
/* Write the command length to reg->cmd_size */
if (mwifiex_write_reg(adapter, reg->cmd_size,
card->cmd_buf->len)) {
- dev_err(adapter->dev,
- "Failed to write cmd len to reg->cmd_size\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to write cmd len to reg->cmd_size\n");
ret = -1;
goto done;
}
@@ -1549,8 +1569,8 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
/* Ring the door bell */
if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
CPU_INTR_DOOR_BELL)) {
- dev_err(adapter->dev,
- "Failed to assert door-bell intr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to assert door-bell intr\n");
ret = -1;
goto done;
}
@@ -1574,7 +1594,8 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
u16 rx_len;
__le16 pkt_len;
- dev_dbg(adapter->dev, "info: Rx CMD Response\n");
+ mwifiex_dbg(adapter, CMD,
+ "info: Rx CMD Response\n");
mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_FROMDEVICE);
@@ -1598,8 +1619,8 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
if (mwifiex_write_reg(adapter,
PCIE_CPU_INT_EVENT,
CPU_INTR_SLEEP_CFM_DONE)) {
- dev_warn(adapter->dev,
- "Write register failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Write register failed\n");
return -1;
}
mwifiex_delay_for_sleep_cookie(adapter,
@@ -1608,8 +1629,8 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
mwifiex_pcie_ok_to_access_hw(adapter))
usleep_range(50, 60);
} else {
- dev_err(adapter->dev,
- "There is no command but got cmdrsp\n");
+ mwifiex_dbg(adapter, ERROR,
+ "There is no command but got cmdrsp\n");
}
memcpy(adapter->upld_buf, skb->data,
min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
@@ -1628,15 +1649,15 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
will prevent firmware from writing to the same response
buffer again. */
if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo, 0)) {
- dev_err(adapter->dev,
- "cmd_done: failed to clear cmd_rsp_addr_lo\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cmd_done: failed to clear cmd_rsp_addr_lo\n");
return -1;
}
/* Write the upper 32bits of the cmdrsp buffer physical
address */
if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi, 0)) {
- dev_err(adapter->dev,
- "cmd_done: failed to clear cmd_rsp_addr_hi\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cmd_done: failed to clear cmd_rsp_addr_hi\n");
return -1;
}
}
@@ -1678,25 +1699,28 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
mwifiex_pm_wakeup_card(adapter);
if (adapter->event_received) {
- dev_dbg(adapter->dev, "info: Event being processed, "
- "do not process this interrupt just yet\n");
+ mwifiex_dbg(adapter, EVENT,
+ "info: Event being processed,\t"
+ "do not process this interrupt just yet\n");
return 0;
}
if (rdptr >= MWIFIEX_MAX_EVT_BD) {
- dev_dbg(adapter->dev, "info: Invalid read pointer...\n");
+ mwifiex_dbg(adapter, ERROR,
+ "info: Invalid read pointer...\n");
return -1;
}
/* Read the event ring write pointer set by firmware */
if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) {
- dev_err(adapter->dev,
- "EventReady: failed to read reg->evt_wrptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "EventReady: failed to read reg->evt_wrptr\n");
return -1;
}
- dev_dbg(adapter->dev, "info: EventReady: Initial <Rd: 0x%x, Wr: 0x%x>",
- card->evtbd_rdptr, wrptr);
+ mwifiex_dbg(adapter, EVENT,
+ "info: EventReady: Initial <Rd: 0x%x, Wr: 0x%x>",
+ card->evtbd_rdptr, wrptr);
if (((wrptr & MWIFIEX_EVTBD_MASK) != (card->evtbd_rdptr
& MWIFIEX_EVTBD_MASK)) ||
((wrptr & reg->evt_rollover_ind) ==
@@ -1705,7 +1729,8 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
__le16 data_len = 0;
u16 evt_len;
- dev_dbg(adapter->dev, "info: Read Index: %d\n", rdptr);
+ mwifiex_dbg(adapter, INFO,
+ "info: Read Index: %d\n", rdptr);
skb_cmd = card->evt_buf_list[rdptr];
mwifiex_unmap_pci_memory(adapter, skb_cmd, PCI_DMA_FROMDEVICE);
@@ -1721,9 +1746,10 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
len is 2 bytes followed by type which is 2 bytes */
memcpy(&data_len, skb_cmd->data, sizeof(__le16));
evt_len = le16_to_cpu(data_len);
-
+ skb_trim(skb_cmd, evt_len);
skb_pull(skb_cmd, INTF_HEADER_LEN);
- dev_dbg(adapter->dev, "info: Event length: %d\n", evt_len);
+ mwifiex_dbg(adapter, EVENT,
+ "info: Event length: %d\n", evt_len);
if ((evt_len > 0) && (evt_len < MAX_EVENT_SIZE))
memcpy(adapter->event_body, skb_cmd->data +
@@ -1740,8 +1766,8 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
} else {
if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
CPU_INTR_EVENT_DONE)) {
- dev_warn(adapter->dev,
- "Write register failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Write register failed\n");
return -1;
}
}
@@ -1766,15 +1792,16 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
return 0;
if (rdptr >= MWIFIEX_MAX_EVT_BD) {
- dev_err(adapter->dev, "event_complete: Invalid rdptr 0x%x\n",
- rdptr);
+ mwifiex_dbg(adapter, ERROR,
+ "event_complete: Invalid rdptr 0x%x\n",
+ rdptr);
return -EINVAL;
}
/* Read the event ring write pointer set by firmware */
if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) {
- dev_err(adapter->dev,
- "event_complete: failed to read reg->evt_wrptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "event_complete: failed to read reg->evt_wrptr\n");
return -1;
}
@@ -1791,9 +1818,9 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
desc->flags = 0;
skb = NULL;
} else {
- dev_dbg(adapter->dev,
- "info: ERROR: buf still valid at index %d, <%p, %p>\n",
- rdptr, card->evt_buf_list[rdptr], skb);
+ mwifiex_dbg(adapter, ERROR,
+ "info: ERROR: buf still valid at index %d, <%p, %p>\n",
+ rdptr, card->evt_buf_list[rdptr], skb);
}
if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) {
@@ -1802,18 +1829,20 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
reg->evt_rollover_ind);
}
- dev_dbg(adapter->dev, "info: Updated <Rd: 0x%x, Wr: 0x%x>",
- card->evtbd_rdptr, wrptr);
+ mwifiex_dbg(adapter, EVENT,
+ "info: Updated <Rd: 0x%x, Wr: 0x%x>",
+ card->evtbd_rdptr, wrptr);
/* Write the event ring read pointer in to reg->evt_rdptr */
if (mwifiex_write_reg(adapter, reg->evt_rdptr,
card->evtbd_rdptr)) {
- dev_err(adapter->dev,
- "event_complete: failed to read reg->evt_rdptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "event_complete: failed to read reg->evt_rdptr\n");
return -1;
}
- dev_dbg(adapter->dev, "info: Check Events Again\n");
+ mwifiex_dbg(adapter, EVENT,
+ "info: Check Events Again\n");
ret = mwifiex_pcie_process_event_ready(adapter);
return ret;
@@ -1840,17 +1869,18 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
if (!firmware || !firmware_len) {
- dev_err(adapter->dev,
- "No firmware image found! Terminating download\n");
+ mwifiex_dbg(adapter, ERROR,
+ "No firmware image found! Terminating download\n");
return -1;
}
- dev_dbg(adapter->dev, "info: Downloading FW image (%d bytes)\n",
- firmware_len);
+ mwifiex_dbg(adapter, INFO,
+ "info: Downloading FW image (%d bytes)\n",
+ firmware_len);
if (mwifiex_pcie_disable_host_int(adapter)) {
- dev_err(adapter->dev,
- "%s: Disabling interrupts failed.\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: Disabling interrupts failed.\n", __func__);
return -1;
}
@@ -1872,8 +1902,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
ret = mwifiex_read_reg(adapter, reg->cmd_size,
&len);
if (ret) {
- dev_warn(adapter->dev,
- "Failed reading len from boot code\n");
+ mwifiex_dbg(adapter, FATAL,
+ "Failed reading len from boot code\n");
goto done;
}
if (len)
@@ -1884,8 +1914,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
if (!len) {
break;
} else if (len > MWIFIEX_UPLD_SIZE) {
- pr_err("FW download failure @ %d, invalid length %d\n",
- offset, len);
+ mwifiex_dbg(adapter, ERROR,
+ "FW download failure @ %d, invalid length %d\n",
+ offset, len);
ret = -1;
goto done;
}
@@ -1895,14 +1926,16 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
if (len & BIT(0)) {
block_retry_cnt++;
if (block_retry_cnt > MAX_WRITE_IOMEM_RETRY) {
- pr_err("FW download failure @ %d, over max "
- "retry count\n", offset);
+ mwifiex_dbg(adapter, ERROR,
+ "FW download failure @ %d, over max\t"
+ "retry count\n", offset);
ret = -1;
goto done;
}
- dev_err(adapter->dev, "FW CRC error indicated by the "
- "helper: len = 0x%04X, txlen = %d\n",
- len, txlen);
+ mwifiex_dbg(adapter, ERROR,
+ "FW CRC error indicated by the\t"
+ "helper: len = 0x%04X, txlen = %d\n",
+ len, txlen);
len &= ~BIT(0);
/* Setting this to 0 to resend from same offset */
txlen = 0;
@@ -1913,7 +1946,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
if (firmware_len - offset < txlen)
txlen = firmware_len - offset;
- dev_dbg(adapter->dev, ".");
+ mwifiex_dbg(adapter, INFO, ".");
tx_blocks = (txlen + card->pcie.blksz_fw_dl - 1) /
card->pcie.blksz_fw_dl;
@@ -1927,8 +1960,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
/* Send the boot command to device */
if (mwifiex_pcie_send_boot_cmd(adapter, skb)) {
- dev_err(adapter->dev,
- "Failed to send firmware download command\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to send firmware download command\n");
ret = -1;
goto done;
}
@@ -1937,9 +1970,10 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
do {
if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS,
&ireg_intr)) {
- dev_err(adapter->dev, "%s: Failed to read "
- "interrupt status during fw dnld.\n",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: Failed to read\t"
+ "interrupt status during fw dnld.\n",
+ __func__);
mwifiex_unmap_pci_memory(adapter, skb,
PCI_DMA_TODEVICE);
ret = -1;
@@ -1953,8 +1987,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
offset += txlen;
} while (true);
- dev_notice(adapter->dev,
- "info: FW download over, size %d bytes\n", offset);
+ mwifiex_dbg(adapter, MSG,
+ "info: FW download over, size %d bytes\n", offset);
ret = 0;
@@ -1980,15 +2014,17 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
/* Mask spurios interrupts */
if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS_MASK,
HOST_INTR_MASK)) {
- dev_warn(adapter->dev, "Write register failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Write register failed\n");
return -1;
}
- dev_dbg(adapter->dev, "Setting driver ready signature\n");
+ mwifiex_dbg(adapter, INFO,
+ "Setting driver ready signature\n");
if (mwifiex_write_reg(adapter, reg->drv_rdy,
FIRMWARE_READY_PCIE)) {
- dev_err(adapter->dev,
- "Failed to write driver ready signature\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to write driver ready signature\n");
return -1;
}
@@ -2015,12 +2051,13 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
&winner_status))
ret = -1;
else if (!winner_status) {
- dev_err(adapter->dev, "PCI-E is the winner\n");
+ mwifiex_dbg(adapter, INFO,
+ "PCI-E is the winner\n");
adapter->winner = 1;
} else {
- dev_err(adapter->dev,
- "PCI-E is not the winner <%#x,%d>, exit dnld\n",
- ret, adapter->winner);
+ mwifiex_dbg(adapter, ERROR,
+ "PCI-E is not the winner <%#x,%d>, exit dnld\n",
+ ret, adapter->winner);
}
}
@@ -2039,7 +2076,7 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
return;
if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, &pcie_ireg)) {
- dev_warn(adapter->dev, "Read register failed\n");
+ mwifiex_dbg(adapter, ERROR, "Read register failed\n");
return;
}
@@ -2050,7 +2087,8 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
/* Clear the pending interrupts */
if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS,
~pcie_ireg)) {
- dev_warn(adapter->dev, "Write register failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Write register failed\n");
return;
}
spin_lock_irqsave(&adapter->int_lock, flags);
@@ -2133,21 +2171,24 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
while (pcie_ireg & HOST_INTR_MASK) {
if (pcie_ireg & HOST_INTR_DNLD_DONE) {
pcie_ireg &= ~HOST_INTR_DNLD_DONE;
- dev_dbg(adapter->dev, "info: TX DNLD Done\n");
+ mwifiex_dbg(adapter, INTR,
+ "info: TX DNLD Done\n");
ret = mwifiex_pcie_send_data_complete(adapter);
if (ret)
return ret;
}
if (pcie_ireg & HOST_INTR_UPLD_RDY) {
pcie_ireg &= ~HOST_INTR_UPLD_RDY;
- dev_dbg(adapter->dev, "info: Rx DATA\n");
+ mwifiex_dbg(adapter, INTR,
+ "info: Rx DATA\n");
ret = mwifiex_pcie_process_recv_data(adapter);
if (ret)
return ret;
}
if (pcie_ireg & HOST_INTR_EVENT_RDY) {
pcie_ireg &= ~HOST_INTR_EVENT_RDY;
- dev_dbg(adapter->dev, "info: Rx EVENT\n");
+ mwifiex_dbg(adapter, INTR,
+ "info: Rx EVENT\n");
ret = mwifiex_pcie_process_event_ready(adapter);
if (ret)
return ret;
@@ -2156,8 +2197,8 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
if (pcie_ireg & HOST_INTR_CMD_DONE) {
pcie_ireg &= ~HOST_INTR_CMD_DONE;
if (adapter->cmd_sent) {
- dev_dbg(adapter->dev,
- "info: CMD sent Interrupt\n");
+ mwifiex_dbg(adapter, INTR,
+ "info: CMD sent Interrupt\n");
adapter->cmd_sent = false;
}
/* Handle command response */
@@ -2169,8 +2210,8 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
if (mwifiex_pcie_ok_to_access_hw(adapter)) {
if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
&pcie_ireg)) {
- dev_warn(adapter->dev,
- "Read register failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Read register failed\n");
return -1;
}
@@ -2178,16 +2219,17 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
if (mwifiex_write_reg(adapter,
PCIE_HOST_INT_STATUS,
~pcie_ireg)) {
- dev_warn(adapter->dev,
- "Write register failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Write register failed\n");
return -1;
}
}
}
}
- dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n",
- adapter->cmd_sent, adapter->data_sent);
+ mwifiex_dbg(adapter, INTR,
+ "info: cmd_sent=%d data_sent=%d\n",
+ adapter->cmd_sent, adapter->data_sent);
if (adapter->ps_state != PS_STATE_SLEEP)
mwifiex_pcie_enable_host_int(adapter);
@@ -2209,7 +2251,8 @@ static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type,
struct mwifiex_tx_param *tx_param)
{
if (!skb) {
- dev_err(adapter->dev, "Passed NULL skb to %s\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "Passed NULL skb to %s\n", __func__);
return -1;
}
@@ -2232,7 +2275,8 @@ mwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag)
ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl, FW_DUMP_HOST_READY);
if (ret) {
- dev_err(adapter->dev, "PCIE write err\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PCIE write err\n");
return RDWR_STATUS_FAILURE;
}
@@ -2243,24 +2287,25 @@ mwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag)
if (doneflag && ctrl_data == doneflag)
return RDWR_STATUS_DONE;
if (ctrl_data != FW_DUMP_HOST_READY) {
- dev_info(adapter->dev,
- "The ctrl reg was changed, re-try again!\n");
+ mwifiex_dbg(adapter, WARN,
+ "The ctrl reg was changed, re-try again!\n");
ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl,
FW_DUMP_HOST_READY);
if (ret) {
- dev_err(adapter->dev, "PCIE write err\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PCIE write err\n");
return RDWR_STATUS_FAILURE;
}
}
usleep_range(100, 200);
}
- dev_err(adapter->dev, "Fail to pull ctrl_data\n");
+ mwifiex_dbg(adapter, ERROR, "Fail to pull ctrl_data\n");
return RDWR_STATUS_FAILURE;
}
/* This function dump firmware memory to file */
-static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
+static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
const struct mwifiex_pcie_card_reg *creg = card->pcie.reg;
@@ -2269,7 +2314,6 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
enum rdwr_status stat;
u32 memory_size;
int ret;
- static char *env[] = { "DRIVER=mwifiex_pcie", "EVENT=fw_dump", NULL };
if (!card->pcie.can_dump_fw)
return;
@@ -2284,12 +2328,12 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
entry->mem_size = 0;
}
- dev_info(adapter->dev, "== mwifiex firmware dump start ==\n");
+ mwifiex_dbg(adapter, DUMP, "== mwifiex firmware dump start ==\n");
/* Read the number of the memories which will dump */
stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
if (stat == RDWR_STATUS_FAILURE)
- goto done;
+ return;
reg = creg->fw_dump_start;
mwifiex_read_reg_byte(adapter, reg, &dump_num);
@@ -2300,7 +2344,7 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
if (stat == RDWR_STATUS_FAILURE)
- goto done;
+ return;
memory_size = 0;
reg = creg->fw_dump_start;
@@ -2311,36 +2355,36 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
}
if (memory_size == 0) {
- dev_info(adapter->dev, "Firmware dump Finished!\n");
+ mwifiex_dbg(adapter, MSG, "Firmware dump Finished!\n");
ret = mwifiex_write_reg(adapter, creg->fw_dump_ctrl,
FW_DUMP_READ_DONE);
if (ret) {
- dev_err(adapter->dev, "PCIE write err\n");
- goto done;
+ mwifiex_dbg(adapter, ERROR, "PCIE write err\n");
+ return;
}
break;
}
- dev_info(adapter->dev,
- "%s_SIZE=0x%x\n", entry->mem_name, memory_size);
+ mwifiex_dbg(adapter, DUMP,
+ "%s_SIZE=0x%x\n", entry->mem_name, memory_size);
entry->mem_ptr = vmalloc(memory_size + 1);
entry->mem_size = memory_size;
if (!entry->mem_ptr) {
- dev_err(adapter->dev,
- "Vmalloc %s failed\n", entry->mem_name);
- goto done;
+ mwifiex_dbg(adapter, ERROR,
+ "Vmalloc %s failed\n", entry->mem_name);
+ return;
}
dbg_ptr = entry->mem_ptr;
end_ptr = dbg_ptr + memory_size;
doneflag = entry->done_flag;
- dev_info(adapter->dev, "Start %s output, please wait...\n",
- entry->mem_name);
+ mwifiex_dbg(adapter, DUMP, "Start %s output, please wait...\n",
+ entry->mem_name);
do {
stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
if (RDWR_STATUS_FAILURE == stat)
- goto done;
+ return;
reg_start = creg->fw_dump_start;
reg_end = creg->fw_dump_end;
@@ -2349,46 +2393,49 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
if (dbg_ptr < end_ptr) {
dbg_ptr++;
} else {
- dev_err(adapter->dev,
- "Allocated buf not enough\n");
- goto done;
+ mwifiex_dbg(adapter, ERROR,
+ "Allocated buf not enough\n");
+ return;
}
}
if (stat != RDWR_STATUS_DONE)
continue;
- dev_info(adapter->dev, "%s done: size=0x%tx\n",
- entry->mem_name, dbg_ptr - entry->mem_ptr);
+ mwifiex_dbg(adapter, DUMP,
+ "%s done: size=0x%tx\n",
+ entry->mem_name, dbg_ptr - entry->mem_ptr);
break;
} while (true);
}
- dev_info(adapter->dev, "== mwifiex firmware dump end ==\n");
-
- kobject_uevent_env(&adapter->wiphy->dev.kobj, KOBJ_CHANGE, env);
+ mwifiex_dbg(adapter, DUMP, "== mwifiex firmware dump end ==\n");
+}
-done:
- adapter->curr_mem_idx = 0;
+static void mwifiex_pcie_device_dump_work(struct mwifiex_adapter *adapter)
+{
+ mwifiex_drv_info_dump(adapter);
+ mwifiex_pcie_fw_dump(adapter);
+ mwifiex_upload_device_dump(adapter);
}
static unsigned long iface_work_flags;
static struct mwifiex_adapter *save_adapter;
static void mwifiex_pcie_work(struct work_struct *work)
{
- if (test_and_clear_bit(MWIFIEX_IFACE_WORK_FW_DUMP,
+ if (test_and_clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP,
&iface_work_flags))
- mwifiex_pcie_fw_dump_work(save_adapter);
+ mwifiex_pcie_device_dump_work(save_adapter);
}
static DECLARE_WORK(pcie_work, mwifiex_pcie_work);
/* This function dumps FW information */
-static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
+static void mwifiex_pcie_device_dump(struct mwifiex_adapter *adapter)
{
save_adapter = adapter;
- if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags))
+ if (test_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &iface_work_flags))
return;
- set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags);
+ set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &iface_work_flags);
schedule_work(&pcie_work);
}
@@ -2418,45 +2465,50 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter)
pci_set_master(pdev);
- dev_dbg(adapter->dev, "try set_consistent_dma_mask(32)\n");
+ mwifiex_dbg(adapter, INFO,
+ "try set_consistent_dma_mask(32)\n");
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
- dev_err(adapter->dev, "set_dma_mask(32) failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "set_dma_mask(32) failed\n");
goto err_set_dma_mask;
}
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
- dev_err(adapter->dev, "set_consistent_dma_mask(64) failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "set_consistent_dma_mask(64) failed\n");
goto err_set_dma_mask;
}
ret = pci_request_region(pdev, 0, DRV_NAME);
if (ret) {
- dev_err(adapter->dev, "req_reg(0) error\n");
+ mwifiex_dbg(adapter, ERROR,
+ "req_reg(0) error\n");
goto err_req_region0;
}
card->pci_mmap = pci_iomap(pdev, 0, 0);
if (!card->pci_mmap) {
- dev_err(adapter->dev, "iomap(0) error\n");
+ mwifiex_dbg(adapter, ERROR, "iomap(0) error\n");
ret = -EIO;
goto err_iomap0;
}
ret = pci_request_region(pdev, 2, DRV_NAME);
if (ret) {
- dev_err(adapter->dev, "req_reg(2) error\n");
+ mwifiex_dbg(adapter, ERROR, "req_reg(2) error\n");
goto err_req_region2;
}
card->pci_mmap1 = pci_iomap(pdev, 2, 0);
if (!card->pci_mmap1) {
- dev_err(adapter->dev, "iomap(2) error\n");
+ mwifiex_dbg(adapter, ERROR,
+ "iomap(2) error\n");
ret = -EIO;
goto err_iomap2;
}
- dev_dbg(adapter->dev,
- "PCI memory map Virt0: %p PCI memory map Virt2: %p\n",
- card->pci_mmap, card->pci_mmap1);
+ mwifiex_dbg(adapter, INFO,
+ "PCI memory map Virt0: %p PCI memory map Virt2: %p\n",
+ card->pci_mmap, card->pci_mmap1);
card->cmdrsp_buf = NULL;
ret = mwifiex_pcie_create_txbd_ring(adapter);
@@ -2521,10 +2573,11 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
if (user_rmmod) {
- dev_dbg(adapter->dev, "Clearing driver ready signature\n");
+ mwifiex_dbg(adapter, INFO,
+ "Clearing driver ready signature\n");
if (mwifiex_write_reg(adapter, reg->drv_rdy, 0x00000000))
- dev_err(adapter->dev,
- "Failed to write driver not-ready signature\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to write driver not-ready signature\n");
}
if (pdev) {
@@ -2555,7 +2608,8 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
ret = request_irq(pdev->irq, mwifiex_pcie_interrupt, IRQF_SHARED,
"MRVL_PCIE", pdev);
if (ret) {
- pr_err("request_irq failed: ret=%d\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "request_irq failed: ret=%d\n", ret);
adapter->card = NULL;
return -1;
}
@@ -2582,7 +2636,8 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
const struct mwifiex_pcie_card_reg *reg;
if (card) {
- dev_dbg(adapter->dev, "%s(): calling free_irq()\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "%s(): calling free_irq()\n", __func__);
free_irq(card->dev->irq, card->dev);
reg = card->pcie.reg;
@@ -2617,7 +2672,7 @@ static struct mwifiex_if_ops pcie_ops = {
.cleanup_mpa_buf = NULL,
.init_fw_port = mwifiex_pcie_init_fw_port,
.clean_pcie_ring = mwifiex_clean_pcie_ring_buf,
- .fw_dump = mwifiex_pcie_fw_dump,
+ .device_dump = mwifiex_pcie_device_dump,
};
/*
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 0ffdb7c5afd2..baf9715ddc10 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -241,20 +241,21 @@ mwifiex_is_bss_wpa(struct mwifiex_private *priv,
* LinkSys WRT54G && bss_desc->privacy
*/
) {
- dev_dbg(priv->adapter->dev, "info: %s: WPA:"
- " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
- "EncMode=%#x privacy=%#x\n", __func__,
- (bss_desc->bcn_wpa_ie) ?
- (*(bss_desc->bcn_wpa_ie)).
- vend_hdr.element_id : 0,
- (bss_desc->bcn_rsn_ie) ?
- (*(bss_desc->bcn_rsn_ie)).
- ieee_hdr.element_id : 0,
- (priv->sec_info.wep_enabled) ? "e" : "d",
- (priv->sec_info.wpa_enabled) ? "e" : "d",
- (priv->sec_info.wpa2_enabled) ? "e" : "d",
- priv->sec_info.encryption_mode,
- bss_desc->privacy);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: %s: WPA:\t"
+ "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s\t"
+ "EncMode=%#x privacy=%#x\n", __func__,
+ (bss_desc->bcn_wpa_ie) ?
+ (*bss_desc->bcn_wpa_ie).
+ vend_hdr.element_id : 0,
+ (bss_desc->bcn_rsn_ie) ?
+ (*bss_desc->bcn_rsn_ie).
+ ieee_hdr.element_id : 0,
+ (priv->sec_info.wep_enabled) ? "e" : "d",
+ (priv->sec_info.wpa_enabled) ? "e" : "d",
+ (priv->sec_info.wpa2_enabled) ? "e" : "d",
+ priv->sec_info.encryption_mode,
+ bss_desc->privacy);
return true;
}
return false;
@@ -277,20 +278,21 @@ mwifiex_is_bss_wpa2(struct mwifiex_private *priv,
* Privacy bit may NOT be set in some APs like
* LinkSys WRT54G && bss_desc->privacy
*/
- dev_dbg(priv->adapter->dev, "info: %s: WPA2: "
- " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
- "EncMode=%#x privacy=%#x\n", __func__,
- (bss_desc->bcn_wpa_ie) ?
- (*(bss_desc->bcn_wpa_ie)).
- vend_hdr.element_id : 0,
- (bss_desc->bcn_rsn_ie) ?
- (*(bss_desc->bcn_rsn_ie)).
- ieee_hdr.element_id : 0,
- (priv->sec_info.wep_enabled) ? "e" : "d",
- (priv->sec_info.wpa_enabled) ? "e" : "d",
- (priv->sec_info.wpa2_enabled) ? "e" : "d",
- priv->sec_info.encryption_mode,
- bss_desc->privacy);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: %s: WPA2:\t"
+ "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s\t"
+ "EncMode=%#x privacy=%#x\n", __func__,
+ (bss_desc->bcn_wpa_ie) ?
+ (*bss_desc->bcn_wpa_ie).
+ vend_hdr.element_id : 0,
+ (bss_desc->bcn_rsn_ie) ?
+ (*bss_desc->bcn_rsn_ie).
+ ieee_hdr.element_id : 0,
+ (priv->sec_info.wep_enabled) ? "e" : "d",
+ (priv->sec_info.wpa_enabled) ? "e" : "d",
+ (priv->sec_info.wpa2_enabled) ? "e" : "d",
+ priv->sec_info.encryption_mode,
+ bss_desc->privacy);
return true;
}
return false;
@@ -333,18 +335,19 @@ mwifiex_is_bss_dynamic_wep(struct mwifiex_private *priv,
((!bss_desc->bcn_rsn_ie) ||
((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) &&
priv->sec_info.encryption_mode && bss_desc->privacy) {
- dev_dbg(priv->adapter->dev, "info: %s: dynamic "
- "WEP: wpa_ie=%#x wpa2_ie=%#x "
- "EncMode=%#x privacy=%#x\n",
- __func__,
- (bss_desc->bcn_wpa_ie) ?
- (*(bss_desc->bcn_wpa_ie)).
- vend_hdr.element_id : 0,
- (bss_desc->bcn_rsn_ie) ?
- (*(bss_desc->bcn_rsn_ie)).
- ieee_hdr.element_id : 0,
- priv->sec_info.encryption_mode,
- bss_desc->privacy);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: %s: dynamic\t"
+ "WEP: wpa_ie=%#x wpa2_ie=%#x\t"
+ "EncMode=%#x privacy=%#x\n",
+ __func__,
+ (bss_desc->bcn_wpa_ie) ?
+ (*bss_desc->bcn_wpa_ie).
+ vend_hdr.element_id : 0,
+ (bss_desc->bcn_rsn_ie) ?
+ (*bss_desc->bcn_rsn_ie).
+ ieee_hdr.element_id : 0,
+ priv->sec_info.encryption_mode,
+ bss_desc->privacy);
return true;
}
return false;
@@ -383,19 +386,20 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
return 0;
if (priv->wps.session_enable) {
- dev_dbg(adapter->dev,
- "info: return success directly in WPS period\n");
+ mwifiex_dbg(adapter, IOCTL,
+ "info: return success directly in WPS period\n");
return 0;
}
if (bss_desc->chan_sw_ie_present) {
- dev_err(adapter->dev,
- "Don't connect to AP with WLAN_EID_CHANNEL_SWITCH\n");
+ mwifiex_dbg(adapter, INFO,
+ "Don't connect to AP with WLAN_EID_CHANNEL_SWITCH\n");
return -1;
}
if (mwifiex_is_bss_wapi(priv, bss_desc)) {
- dev_dbg(adapter->dev, "info: return success for WAPI AP\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: return success for WAPI AP\n");
return 0;
}
@@ -405,7 +409,8 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
return 0;
} else if (mwifiex_is_bss_static_wep(priv, bss_desc)) {
/* Static WEP enabled */
- dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: Disable 11n in WEP mode.\n");
bss_desc->disable_11n = true;
return 0;
} else if (mwifiex_is_bss_wpa(priv, bss_desc)) {
@@ -418,9 +423,9 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
if (mwifiex_is_wpa_oui_present
(bss_desc, CIPHER_SUITE_TKIP)) {
- dev_dbg(adapter->dev,
- "info: Disable 11n if AES "
- "is not supported by AP\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: Disable 11n if AES\t"
+ "is not supported by AP\n");
bss_desc->disable_11n = true;
} else {
return -1;
@@ -437,9 +442,9 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
if (mwifiex_is_rsn_oui_present
(bss_desc, CIPHER_SUITE_TKIP)) {
- dev_dbg(adapter->dev,
- "info: Disable 11n if AES "
- "is not supported by AP\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: Disable 11n if AES\t"
+ "is not supported by AP\n");
bss_desc->disable_11n = true;
} else {
return -1;
@@ -455,17 +460,18 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
}
/* Security doesn't match */
- dev_dbg(adapter->dev,
- "info: %s: failed: wpa_ie=%#x wpa2_ie=%#x WEP=%s "
- "WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n", __func__,
- (bss_desc->bcn_wpa_ie) ?
- (*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id : 0,
- (bss_desc->bcn_rsn_ie) ?
- (*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id : 0,
- (priv->sec_info.wep_enabled) ? "e" : "d",
- (priv->sec_info.wpa_enabled) ? "e" : "d",
- (priv->sec_info.wpa2_enabled) ? "e" : "d",
- priv->sec_info.encryption_mode, bss_desc->privacy);
+ mwifiex_dbg(adapter, ERROR,
+ "info: %s: failed: wpa_ie=%#x wpa2_ie=%#x WEP=%s\t"
+ "WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n",
+ __func__,
+ (bss_desc->bcn_wpa_ie) ?
+ (*bss_desc->bcn_wpa_ie).vend_hdr.element_id : 0,
+ (bss_desc->bcn_rsn_ie) ?
+ (*bss_desc->bcn_rsn_ie).ieee_hdr.element_id : 0,
+ (priv->sec_info.wep_enabled) ? "e" : "d",
+ (priv->sec_info.wpa_enabled) ? "e" : "d",
+ (priv->sec_info.wpa2_enabled) ? "e" : "d",
+ priv->sec_info.encryption_mode, bss_desc->privacy);
return -1;
}
@@ -560,7 +566,8 @@ mwifiex_append_rate_tlv(struct mwifiex_private *priv,
else
rates_size = mwifiex_get_supported_rates(priv, rates);
- dev_dbg(priv->adapter->dev, "info: SCAN_CMD: Rates size = %d\n",
+ mwifiex_dbg(priv->adapter, CMD,
+ "info: SCAN_CMD: Rates size = %d\n",
rates_size);
rates_tlv = (struct mwifiex_ie_types_rates_param_set *)tlv_pos;
rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
@@ -600,9 +607,9 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
u8 radio_type;
if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) {
- dev_dbg(priv->adapter->dev,
- "info: Scan: Null detect: %p, %p, %p\n",
- scan_cfg_out, chan_tlv_out, scan_chan_list);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "info: Scan: Null detect: %p, %p, %p\n",
+ scan_cfg_out, chan_tlv_out, scan_chan_list);
return -1;
}
@@ -645,16 +652,16 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
}
radio_type = tmp_chan_list->radio_type;
- dev_dbg(priv->adapter->dev,
- "info: Scan: Chan(%3d), Radio(%d),"
- " Mode(%d, %d), Dur(%d)\n",
- tmp_chan_list->chan_number,
- tmp_chan_list->radio_type,
- tmp_chan_list->chan_scan_mode_bitmap
- & MWIFIEX_PASSIVE_SCAN,
- (tmp_chan_list->chan_scan_mode_bitmap
- & MWIFIEX_DISABLE_CHAN_FILT) >> 1,
- le16_to_cpu(tmp_chan_list->max_scan_time));
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: Scan: Chan(%3d), Radio(%d),\t"
+ "Mode(%d, %d), Dur(%d)\n",
+ tmp_chan_list->chan_number,
+ tmp_chan_list->radio_type,
+ tmp_chan_list->chan_scan_mode_bitmap
+ & MWIFIEX_PASSIVE_SCAN,
+ (tmp_chan_list->chan_scan_mode_bitmap
+ & MWIFIEX_DISABLE_CHAN_FILT) >> 1,
+ le16_to_cpu(tmp_chan_list->max_scan_time));
/* Copy the current channel TLV to the command being
prepared */
@@ -718,9 +725,11 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
/* The total scan time should be less than scan command timeout
value */
if (total_scan_time > MWIFIEX_MAX_TOTAL_SCAN_TIME) {
- dev_err(priv->adapter->dev, "total scan time %dms"
- " is over limit (%dms), scan skipped\n",
- total_scan_time, MWIFIEX_MAX_TOTAL_SCAN_TIME);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "total scan time %dms\t"
+ "is over limit (%dms), scan skipped\n",
+ total_scan_time,
+ MWIFIEX_MAX_TOTAL_SCAN_TIME);
ret = -1;
break;
}
@@ -905,9 +914,10 @@ mwifiex_config_scan(struct mwifiex_private *priv,
tlv_pos += (sizeof(wildcard_ssid_tlv->header)
+ le16_to_cpu(wildcard_ssid_tlv->header.len));
- dev_dbg(adapter->dev, "info: scan: ssid[%d]: %s, %d\n",
- i, wildcard_ssid_tlv->ssid,
- wildcard_ssid_tlv->max_ssid_length);
+ mwifiex_dbg(adapter, INFO,
+ "info: scan: ssid[%d]: %s, %d\n",
+ i, wildcard_ssid_tlv->ssid,
+ wildcard_ssid_tlv->max_ssid_length);
/* Empty wildcard ssid with a maxlen will match many or
potentially all SSIDs (maxlen == 32), therefore do
@@ -928,8 +938,9 @@ mwifiex_config_scan(struct mwifiex_private *priv,
*filtered_scan = true;
if (user_scan_in->scan_chan_gap) {
- dev_dbg(adapter->dev, "info: scan: channel gap = %d\n",
- user_scan_in->scan_chan_gap);
+ mwifiex_dbg(adapter, INFO,
+ "info: scan: channel gap = %d\n",
+ user_scan_in->scan_chan_gap);
*max_chan_per_scan =
MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN;
@@ -961,8 +972,9 @@ mwifiex_config_scan(struct mwifiex_private *priv,
add tlv */
if (num_probes) {
- dev_dbg(adapter->dev, "info: scan: num_probes = %d\n",
- num_probes);
+ mwifiex_dbg(adapter, INFO,
+ "info: scan: num_probes = %d\n",
+ num_probes);
num_probes_tlv = (struct mwifiex_ie_types_num_probes *) tlv_pos;
num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES);
@@ -1003,7 +1015,8 @@ mwifiex_config_scan(struct mwifiex_private *priv,
if (user_scan_in && user_scan_in->chan_list[0].chan_number) {
- dev_dbg(adapter->dev, "info: Scan: Using supplied channel list\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: Scan: Using supplied channel list\n");
for (chan_idx = 0;
chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX &&
@@ -1056,13 +1069,13 @@ mwifiex_config_scan(struct mwifiex_private *priv,
(user_scan_in->chan_list[0].chan_number ==
priv->curr_bss_params.bss_descriptor.channel)) {
*scan_current_only = true;
- dev_dbg(adapter->dev,
- "info: Scan: Scanning current channel only\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: Scan: Scanning current channel only\n");
}
chan_num = chan_idx;
} else {
- dev_dbg(adapter->dev,
- "info: Scan: Creating full region channel list\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: Scan: Creating full region channel list\n");
chan_num = mwifiex_scan_create_channel_list(priv, user_scan_in,
scan_chan_list,
*filtered_scan);
@@ -1094,8 +1107,9 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter,
tlv_buf_left = tlv_buf_size;
*tlv_data = NULL;
- dev_dbg(adapter->dev, "info: SCAN_RESP: tlv_buf_size = %d\n",
- tlv_buf_size);
+ mwifiex_dbg(adapter, INFO,
+ "info: SCAN_RESP: tlv_buf_size = %d\n",
+ tlv_buf_size);
while (tlv_buf_left >= sizeof(struct mwifiex_ie_types_header)) {
@@ -1103,26 +1117,31 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter,
tlv_len = le16_to_cpu(current_tlv->header.len);
if (sizeof(tlv->header) + tlv_len > tlv_buf_left) {
- dev_err(adapter->dev, "SCAN_RESP: TLV buffer corrupt\n");
+ mwifiex_dbg(adapter, ERROR,
+ "SCAN_RESP: TLV buffer corrupt\n");
break;
}
if (req_tlv_type == tlv_type) {
switch (tlv_type) {
case TLV_TYPE_TSFTIMESTAMP:
- dev_dbg(adapter->dev, "info: SCAN_RESP: TSF "
- "timestamp TLV, len = %d\n", tlv_len);
+ mwifiex_dbg(adapter, INFO,
+ "info: SCAN_RESP: TSF\t"
+ "timestamp TLV, len = %d\n",
+ tlv_len);
*tlv_data = current_tlv;
break;
case TLV_TYPE_CHANNELBANDLIST:
- dev_dbg(adapter->dev, "info: SCAN_RESP: channel"
- " band list TLV, len = %d\n", tlv_len);
+ mwifiex_dbg(adapter, INFO,
+ "info: SCAN_RESP: channel\t"
+ "band list TLV, len = %d\n",
+ tlv_len);
*tlv_data = current_tlv;
break;
default:
- dev_err(adapter->dev,
- "SCAN_RESP: unhandled TLV = %d\n",
- tlv_type);
+ mwifiex_dbg(adapter, ERROR,
+ "SCAN_RESP: unhandled TLV = %d\n",
+ tlv_type);
/* Give up, this seems corrupted */
return;
}
@@ -1177,8 +1196,9 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
total_ie_len = element_len + sizeof(struct ieee_types_header);
if (bytes_left < total_ie_len) {
- dev_err(adapter->dev, "err: InterpretIE: in processing"
- " IE, bytes left < IE length\n");
+ mwifiex_dbg(adapter, ERROR,
+ "err: InterpretIE: in processing\t"
+ "IE, bytes left < IE length\n");
return -1;
}
switch (element_id) {
@@ -1186,9 +1206,9 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
bss_entry->ssid.ssid_len = element_len;
memcpy(bss_entry->ssid.ssid, (current_ptr + 2),
element_len);
- dev_dbg(adapter->dev,
- "info: InterpretIE: ssid: %-32s\n",
- bss_entry->ssid.ssid);
+ mwifiex_dbg(adapter, INFO,
+ "info: InterpretIE: ssid: %-32s\n",
+ bss_entry->ssid.ssid);
break;
case WLAN_EID_SUPP_RATES:
@@ -1419,19 +1439,20 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
unsigned long flags;
if (adapter->scan_processing) {
- dev_err(adapter->dev, "cmd: Scan already in process...\n");
+ mwifiex_dbg(adapter, WARN,
+ "cmd: Scan already in process...\n");
return -EBUSY;
}
if (priv->scan_block) {
- dev_err(adapter->dev,
- "cmd: Scan is blocked during association...\n");
+ mwifiex_dbg(adapter, WARN,
+ "cmd: Scan is blocked during association...\n");
return -EBUSY;
}
if (adapter->surprise_removed || adapter->is_cmd_timedout) {
- dev_err(adapter->dev,
- "Ignore scan. Card removed or firmware in bad state\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Ignore scan. Card removed or firmware in bad state\n");
return -EFAULT;
}
@@ -1478,7 +1499,8 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
/* Perform internal scan synchronously */
if (!priv->scan_request) {
- dev_dbg(adapter->dev, "wait internal scan\n");
+ mwifiex_dbg(adapter, INFO,
+ "wait internal scan\n");
mwifiex_wait_queue_complete(adapter, cmd_node);
}
} else {
@@ -1553,8 +1575,8 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
ret = mwifiex_is_network_compatible(priv, bss_desc,
priv->bss_mode);
if (ret)
- dev_err(priv->adapter->dev,
- "Incompatible network settings\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Incompatible network settings\n");
break;
default:
ret = 0;
@@ -1656,7 +1678,8 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
*/
if (curr_bcn_bytes < ETH_ALEN + sizeof(u8) +
sizeof(struct mwifiex_fixed_bcn_param)) {
- dev_err(adapter->dev, "InterpretIE: not enough bytes left\n");
+ mwifiex_dbg(adapter, ERROR,
+ "InterpretIE: not enough bytes left\n");
return -EFAULT;
}
@@ -1669,7 +1692,8 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
rssi = (-rssi) * 100; /* Convert dBm to mBm */
current_ptr += sizeof(u8);
curr_bcn_bytes -= sizeof(u8);
- dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%d\n", rssi);
+ mwifiex_dbg(adapter, INFO,
+ "info: InterpretIE: RSSI=%d\n", rssi);
} else {
rssi = rssi_val;
}
@@ -1682,14 +1706,16 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
beacon_period = le16_to_cpu(bcn_param->beacon_period);
cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap);
- dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n",
- cap_info_bitmap);
+ mwifiex_dbg(adapter, INFO,
+ "info: InterpretIE: capabilities=0x%X\n",
+ cap_info_bitmap);
/* Rest of the current buffer are IE's */
ie_buf = current_ptr;
ie_len = curr_bcn_bytes;
- dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n",
- curr_bcn_bytes);
+ mwifiex_dbg(adapter, INFO,
+ "info: InterpretIE: IELength for this AP = %d\n",
+ curr_bcn_bytes);
while (curr_bcn_bytes >= sizeof(struct ieee_types_header)) {
u8 element_id, element_len;
@@ -1698,8 +1724,8 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
element_len = *(current_ptr + 1);
if (curr_bcn_bytes < element_len +
sizeof(struct ieee_types_header)) {
- dev_err(adapter->dev,
- "%s: bytes left < IE length\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: bytes left < IE length\n", __func__);
return -EFAULT;
}
if (element_id == WLAN_EID_DS_PARAMS) {
@@ -1719,8 +1745,8 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
/* Skip entry if on csa closed channel */
if (channel == priv->csa_chan) {
- dev_dbg(adapter->dev,
- "Dropping entry on csa closed channel\n");
+ mwifiex_dbg(adapter, WARN,
+ "Dropping entry on csa closed channel\n");
return 0;
}
@@ -1751,7 +1777,7 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
cfg80211_put_bss(priv->wdev.wiphy, bss);
}
} else {
- dev_dbg(adapter->dev, "missing BSS channel IE\n");
+ mwifiex_dbg(adapter, WARN, "missing BSS channel IE\n");
}
return 0;
@@ -1765,7 +1791,8 @@ static void mwifiex_complete_scan(struct mwifiex_private *priv)
if (adapter->curr_cmd->wait_q_enabled) {
adapter->cmd_wait_q.status = 0;
if (!priv->scan_request) {
- dev_dbg(adapter->dev, "complete internal scan\n");
+ mwifiex_dbg(adapter, INFO,
+ "complete internal scan\n");
mwifiex_complete_cmd(adapter, adapter->curr_cmd);
}
}
@@ -1788,12 +1815,14 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
mwifiex_complete_scan(priv);
if (priv->scan_request) {
- dev_dbg(adapter->dev, "info: notifying scan done\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: notifying scan done\n");
cfg80211_scan_done(priv->scan_request, 0);
priv->scan_request = NULL;
} else {
priv->scan_aborting = false;
- dev_dbg(adapter->dev, "info: scan already aborted\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: scan already aborted\n");
}
} else if ((priv->scan_aborting && !priv->scan_request) ||
priv->scan_block) {
@@ -1809,12 +1838,14 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
if (priv->scan_request) {
- dev_dbg(adapter->dev, "info: aborting scan\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: aborting scan\n");
cfg80211_scan_done(priv->scan_request, 1);
priv->scan_request = NULL;
} else {
priv->scan_aborting = false;
- dev_dbg(adapter->dev, "info: scan already aborted\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: scan already aborted\n");
}
} else {
/* Get scan command from scan_pending_q and put to
@@ -1877,8 +1908,9 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) {
- dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n",
- scan_rsp->number_of_sets);
+ mwifiex_dbg(adapter, ERROR,
+ "SCAN_RESP: too many AP returned (%d)\n",
+ scan_rsp->number_of_sets);
ret = -1;
goto check_next_scan;
}
@@ -1887,14 +1919,15 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
mwifiex_11h_get_csa_closed_channel(priv);
bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
- dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n",
- bytes_left);
+ mwifiex_dbg(adapter, INFO,
+ "info: SCAN_RESP: bss_descript_size %d\n",
+ bytes_left);
scan_resp_size = le16_to_cpu(resp->size);
- dev_dbg(adapter->dev,
- "info: SCAN_RESP: returned %d APs before parsing\n",
- scan_rsp->number_of_sets);
+ mwifiex_dbg(adapter, INFO,
+ "info: SCAN_RESP: returned %d APs before parsing\n",
+ scan_rsp->number_of_sets);
bss_info = scan_rsp->bss_desc_and_tlv_buffer;
@@ -2007,13 +2040,13 @@ mwifiex_update_chan_statistics(struct mwifiex_private *priv,
le16_to_cpu(fw_chan_stats->cca_scan_dur);
chan_stats.cca_busy_dur =
le16_to_cpu(fw_chan_stats->cca_busy_dur);
- dev_dbg(adapter->dev,
- "chan=%d, noise=%d, total_network=%d scan_duration=%d, busy_duration=%d\n",
- chan_stats.chan_num,
- chan_stats.noise,
- chan_stats.total_bss,
- chan_stats.cca_scan_dur,
- chan_stats.cca_busy_dur);
+ mwifiex_dbg(adapter, INFO,
+ "chan=%d, noise=%d, total_network=%d scan_duration=%d, busy_duration=%d\n",
+ chan_stats.chan_num,
+ chan_stats.noise,
+ chan_stats.total_bss,
+ chan_stats.cca_scan_dur,
+ chan_stats.cca_busy_dur);
memcpy(&adapter->chan_stats[adapter->survey_idx++], &chan_stats,
sizeof(struct mwifiex_chan_stats));
fw_chan_stats++;
@@ -2035,7 +2068,7 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
unsigned long cmd_flags, scan_flags;
bool complete_scan = false;
- dev_dbg(priv->adapter->dev, "info: EXT scan returns successfully\n");
+ mwifiex_dbg(adapter, INFO, "info: EXT scan returns successfully\n");
ext_scan_resp = &resp->params.ext_scan;
@@ -2048,8 +2081,8 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
len = le16_to_cpu(tlv->len);
if (buf_left < (sizeof(struct mwifiex_ie_types_header) + len)) {
- dev_err(adapter->dev,
- "error processing scan response TLVs");
+ mwifiex_dbg(adapter, ERROR,
+ "error processing scan response TLVs");
break;
}
@@ -2075,8 +2108,8 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
cmd_ptr = (void *)cmd_node->cmd_skb->data;
if (le16_to_cpu(cmd_ptr->command) ==
HostCmd_CMD_802_11_SCAN_EXT) {
- dev_dbg(priv->adapter->dev,
- "Scan pending in command pending list");
+ mwifiex_dbg(adapter, INFO,
+ "Scan pending in command pending list");
complete_scan = false;
break;
}
@@ -2114,17 +2147,20 @@ int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
u16 scan_resp_size = le16_to_cpu(event_scan->buf_size);
if (num_of_set > MWIFIEX_MAX_AP) {
- dev_err(adapter->dev,
- "EXT_SCAN: Invalid number of AP returned (%d)!!\n",
- num_of_set);
+ mwifiex_dbg(adapter, ERROR,
+ "EXT_SCAN: Invalid number of AP returned (%d)!!\n",
+ num_of_set);
ret = -1;
goto check_next_scan;
}
bytes_left = scan_resp_size;
- dev_dbg(adapter->dev,
- "EXT_SCAN: size %d, returned %d APs...",
- scan_resp_size, num_of_set);
+ mwifiex_dbg(adapter, INFO,
+ "EXT_SCAN: size %d, returned %d APs...",
+ scan_resp_size, num_of_set);
+ mwifiex_dbg_dump(adapter, CMD_D, "EXT_SCAN buffer:", buf,
+ scan_resp_size +
+ sizeof(struct mwifiex_event_scan_result));
tlv = (struct mwifiex_ie_types_data *)scan_resp;
@@ -2132,7 +2168,8 @@ int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
type = le16_to_cpu(tlv->header.type);
len = le16_to_cpu(tlv->header.len);
if (bytes_left < sizeof(struct mwifiex_ie_types_header) + len) {
- dev_err(adapter->dev, "EXT_SCAN: Error bytes left < TLV length\n");
+ mwifiex_dbg(adapter, ERROR,
+ "EXT_SCAN: Error bytes left < TLV length\n");
break;
}
scan_rsp_tlv = NULL;
@@ -2158,8 +2195,9 @@ int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
len = le16_to_cpu(tlv->header.len);
if (bytes_left_for_tlv <
sizeof(struct mwifiex_ie_types_header) + len) {
- dev_err(adapter->dev,
- "EXT_SCAN: Error in processing TLV, bytes left < TLV length\n");
+ mwifiex_dbg(adapter, ERROR,
+ "EXT_SCAN: Error in processing TLV,\t"
+ "bytes left < TLV length\n");
scan_rsp_tlv = NULL;
bytes_left_for_tlv = 0;
continue;
@@ -2199,8 +2237,8 @@ int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
if (scan_info_tlv) {
rssi = (s32)(s16)(le16_to_cpu(scan_info_tlv->rssi));
rssi *= 100; /* Convert dBm to mBm */
- dev_dbg(adapter->dev,
- "info: InterpretIE: RSSI=%d\n", rssi);
+ mwifiex_dbg(adapter, INFO,
+ "info: InterpretIE: RSSI=%d\n", rssi);
fw_tsf = le64_to_cpu(scan_info_tlv->tsf);
radio_type = &scan_info_tlv->radio_type;
} else {
@@ -2271,13 +2309,14 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
struct mwifiex_user_scan_cfg *scan_cfg;
if (adapter->scan_processing) {
- dev_err(adapter->dev, "cmd: Scan already in process...\n");
+ mwifiex_dbg(adapter, WARN,
+ "cmd: Scan already in process...\n");
return -EBUSY;
}
if (priv->scan_block) {
- dev_err(adapter->dev,
- "cmd: Scan is blocked during association...\n");
+ mwifiex_dbg(adapter, WARN,
+ "cmd: Scan is blocked during association...\n");
return -EBUSY;
}
@@ -2309,8 +2348,9 @@ int mwifiex_request_scan(struct mwifiex_private *priv,
int ret;
if (down_interruptible(&priv->async_sem)) {
- dev_err(priv->adapter->dev, "%s: acquire semaphore\n",
- __func__);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: acquire semaphore fail\n",
+ __func__);
return -1;
}
@@ -2400,8 +2440,9 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf,
curr_bss->beacon_buf_size);
- dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n",
- priv->curr_bcn_size);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: current beacon saved %d\n",
+ priv->curr_bcn_size);
curr_bss->beacon_buf = priv->curr_bcn_buf;
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index d10320f89bc1..a0b121f3460c 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -166,7 +166,8 @@ static int mwifiex_sdio_resume(struct device *dev)
adapter = card->adapter;
if (!adapter->is_suspended) {
- dev_warn(adapter->dev, "device already resumed\n");
+ mwifiex_dbg(adapter, WARN,
+ "device already resumed\n");
return 0;
}
@@ -191,8 +192,6 @@ mwifiex_sdio_remove(struct sdio_func *func)
struct mwifiex_adapter *adapter;
struct mwifiex_private *priv;
- pr_debug("info: SDIO func num=%d\n", func->num);
-
card = sdio_get_drvdata(func);
if (!card)
return;
@@ -201,6 +200,8 @@ mwifiex_sdio_remove(struct sdio_func *func)
if (!adapter || !adapter->priv_num)
return;
+ mwifiex_dbg(adapter, INFO, "info: SDIO func num=%d\n", func->num);
+
if (user_rmmod) {
if (adapter->is_suspended)
mwifiex_sdio_resume(adapter->dev);
@@ -257,12 +258,14 @@ static int mwifiex_sdio_suspend(struct device *dev)
/* Enable the Host Sleep */
if (!mwifiex_enable_hs(adapter)) {
- dev_err(adapter->dev, "cmd: failed to suspend\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cmd: failed to suspend\n");
adapter->hs_enabling = false;
return -EFAULT;
}
- dev_dbg(adapter->dev, "cmd: suspend with MMC_PM_KEEP_POWER\n");
+ mwifiex_dbg(adapter, INFO,
+ "cmd: suspend with MMC_PM_KEEP_POWER\n");
ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
/* Indicate device suspended */
@@ -386,8 +389,8 @@ mwifiex_write_data_sync(struct mwifiex_adapter *adapter,
u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK);
if (adapter->is_suspended) {
- dev_err(adapter->dev,
- "%s: not allowed while suspended\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: not allowed while suspended\n", __func__);
return -1;
}
@@ -434,7 +437,8 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer,
*/
static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
{
- dev_dbg(adapter->dev, "event: wakeup device...\n");
+ mwifiex_dbg(adapter, EVENT,
+ "event: wakeup device...\n");
return mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP);
}
@@ -446,7 +450,8 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
*/
static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
{
- dev_dbg(adapter->dev, "cmd: wakeup device completed\n");
+ mwifiex_dbg(adapter, EVENT,
+ "cmd: wakeup device completed\n");
return mwifiex_write_reg(adapter, CONFIGURATION_REG, 0);
}
@@ -524,7 +529,8 @@ static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter)
else
return -1;
cont:
- pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport);
+ mwifiex_dbg(adapter, INFO,
+ "info: SDIO FUNC1 IO port: %#x\n", adapter->ioport);
/* Set Host interrupt reset to read to clear */
if (!mwifiex_read_reg(adapter, card->reg->host_int_rsr_reg, &reg))
@@ -556,10 +562,12 @@ static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter,
ret = mwifiex_write_data_sync(adapter, payload, pkt_len, port);
if (ret) {
i++;
- dev_err(adapter->dev, "host_to_card, write iomem"
- " (%d) failed: %d\n", i, ret);
+ mwifiex_dbg(adapter, ERROR,
+ "host_to_card, write iomem\t"
+ "(%d) failed: %d\n", i, ret);
if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04))
- dev_err(adapter->dev, "write CFG reg failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "write CFG reg failed\n");
ret = -1;
if (i > MAX_WRITE_IOMEM_RETRY)
@@ -584,7 +592,8 @@ static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port)
const struct mwifiex_sdio_card_reg *reg = card->reg;
u32 rd_bitmap = card->mp_rd_bitmap;
- dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%08x\n", rd_bitmap);
+ mwifiex_dbg(adapter, DATA,
+ "data: mp_rd_bitmap=0x%08x\n", rd_bitmap);
if (card->supports_sdio_new_mode) {
if (!(rd_bitmap & reg->data_port_mask))
@@ -598,8 +607,9 @@ static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port)
(card->mp_rd_bitmap & CTRL_PORT_MASK)) {
card->mp_rd_bitmap &= (u32) (~CTRL_PORT_MASK);
*port = CTRL_PORT;
- dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%08x\n",
- *port, card->mp_rd_bitmap);
+ mwifiex_dbg(adapter, DATA,
+ "data: port=%d mp_rd_bitmap=0x%08x\n",
+ *port, card->mp_rd_bitmap);
return 0;
}
@@ -613,9 +623,9 @@ static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port)
if (++card->curr_rd_port == card->max_ports)
card->curr_rd_port = reg->start_rd_port;
- dev_dbg(adapter->dev,
- "data: port=%d mp_rd_bitmap=0x%08x -> 0x%08x\n",
- *port, rd_bitmap, card->mp_rd_bitmap);
+ mwifiex_dbg(adapter, DATA,
+ "data: port=%d mp_rd_bitmap=0x%08x -> 0x%08x\n",
+ *port, rd_bitmap, card->mp_rd_bitmap);
return 0;
}
@@ -633,7 +643,8 @@ static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u32 *port)
const struct mwifiex_sdio_card_reg *reg = card->reg;
u32 wr_bitmap = card->mp_wr_bitmap;
- dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%08x\n", wr_bitmap);
+ mwifiex_dbg(adapter, DATA,
+ "data: mp_wr_bitmap=0x%08x\n", wr_bitmap);
if (!(wr_bitmap & card->mp_data_port_mask)) {
adapter->data_sent = true;
@@ -651,15 +662,16 @@ static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u32 *port)
}
if ((card->has_control_mask) && (*port == CTRL_PORT)) {
- dev_err(adapter->dev,
- "invalid data port=%d cur port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
- *port, card->curr_wr_port, wr_bitmap,
- card->mp_wr_bitmap);
+ mwifiex_dbg(adapter, ERROR,
+ "invalid data port=%d cur port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
+ *port, card->curr_wr_port, wr_bitmap,
+ card->mp_wr_bitmap);
return -1;
}
- dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
- *port, wr_bitmap, card->mp_wr_bitmap);
+ mwifiex_dbg(adapter, DATA,
+ "data: port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
+ *port, wr_bitmap, card->mp_wr_bitmap);
return 0;
}
@@ -683,7 +695,8 @@ mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits)
usleep_range(10, 20);
}
- dev_err(adapter->dev, "poll card status failed, tries = %d\n", tries);
+ mwifiex_dbg(adapter, ERROR,
+ "poll card status failed, tries = %d\n", tries);
return -1;
}
@@ -738,7 +751,7 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
if (mwifiex_read_data_sync(adapter, card->mp_regs,
card->reg->max_mp_regs,
REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0)) {
- dev_err(adapter->dev, "read mp_regs failed\n");
+ mwifiex_dbg(adapter, ERROR, "read mp_regs failed\n");
return;
}
@@ -751,7 +764,8 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
* UP_LD_CMD_PORT_HOST_INT_STATUS
* Clear the interrupt status register
*/
- dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg);
+ mwifiex_dbg(adapter, INTR,
+ "int: sdio_ireg = %#x\n", sdio_ireg);
spin_lock_irqsave(&adapter->int_lock, flags);
adapter->int_status |= sdio_ireg;
spin_unlock_irqrestore(&adapter->int_lock, flags);
@@ -802,7 +816,8 @@ static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter)
/* Request the SDIO IRQ */
ret = sdio_claim_irq(func, mwifiex_sdio_interrupt);
if (ret) {
- dev_err(adapter->dev, "claim irq failed: ret=%d\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "claim irq failed: ret=%d\n", ret);
goto out;
}
@@ -810,7 +825,8 @@ static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter)
ret = mwifiex_write_reg_locked(func, card->reg->host_int_mask_reg,
card->reg->host_int_enable);
if (ret) {
- dev_err(adapter->dev, "enable host interrupt failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "enable host interrupt failed\n");
sdio_release_irq(func);
}
@@ -830,22 +846,25 @@ static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter,
u32 nb;
if (!buffer) {
- dev_err(adapter->dev, "%s: buffer is NULL\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: buffer is NULL\n", __func__);
return -1;
}
ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 1);
if (ret) {
- dev_err(adapter->dev, "%s: read iomem failed: %d\n", __func__,
+ mwifiex_dbg(adapter, ERROR,
+ "%s: read iomem failed: %d\n", __func__,
ret);
return -1;
}
nb = le16_to_cpu(*(__le16 *) (buffer));
if (nb > npayload) {
- dev_err(adapter->dev, "%s: invalid packet, nb=%d npayload=%d\n",
- __func__, nb, npayload);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: invalid packet, nb=%d npayload=%d\n",
+ __func__, nb, npayload);
return -1;
}
@@ -877,13 +896,14 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
u32 i = 0;
if (!firmware_len) {
- dev_err(adapter->dev,
- "firmware image not found! Terminating download\n");
+ mwifiex_dbg(adapter, ERROR,
+ "firmware image not found! Terminating download\n");
return -1;
}
- dev_dbg(adapter->dev, "info: downloading FW image (%d bytes)\n",
- firmware_len);
+ mwifiex_dbg(adapter, INFO,
+ "info: downloading FW image (%d bytes)\n",
+ firmware_len);
/* Assume that the allocated buffer is 8-byte aligned */
fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL);
@@ -897,8 +917,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY |
DN_LD_CARD_RDY);
if (ret) {
- dev_err(adapter->dev, "FW download with helper:"
- " poll status timeout @ %d\n", offset);
+ mwifiex_dbg(adapter, ERROR,
+ "FW download with helper:\t"
+ "poll status timeout @ %d\n", offset);
goto done;
}
@@ -910,19 +931,19 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
ret = mwifiex_read_reg(adapter, reg->base_0_reg,
&base0);
if (ret) {
- dev_err(adapter->dev,
- "dev BASE0 register read failed: "
- "base0=%#04X(%d). Terminating dnld\n",
- base0, base0);
+ mwifiex_dbg(adapter, ERROR,
+ "dev BASE0 register read failed:\t"
+ "base0=%#04X(%d). Terminating dnld\n",
+ base0, base0);
goto done;
}
ret = mwifiex_read_reg(adapter, reg->base_1_reg,
&base1);
if (ret) {
- dev_err(adapter->dev,
- "dev BASE1 register read failed: "
- "base1=%#04X(%d). Terminating dnld\n",
- base1, base1);
+ mwifiex_dbg(adapter, ERROR,
+ "dev BASE1 register read failed:\t"
+ "base1=%#04X(%d). Terminating dnld\n",
+ base1, base1);
goto done;
}
len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff));
@@ -936,9 +957,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
if (!len) {
break;
} else if (len > MWIFIEX_UPLD_SIZE) {
- dev_err(adapter->dev,
- "FW dnld failed @ %d, invalid length %d\n",
- offset, len);
+ mwifiex_dbg(adapter, ERROR,
+ "FW dnld failed @ %d, invalid length %d\n",
+ offset, len);
ret = -1;
goto done;
}
@@ -948,14 +969,15 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
if (len & BIT(0)) {
i++;
if (i > MAX_WRITE_IOMEM_RETRY) {
- dev_err(adapter->dev,
- "FW dnld failed @ %d, over max retry\n",
- offset);
+ mwifiex_dbg(adapter, ERROR,
+ "FW dnld failed @ %d, over max retry\n",
+ offset);
ret = -1;
goto done;
}
- dev_err(adapter->dev, "CRC indicated by the helper:"
- " len = 0x%04X, txlen = %d\n", len, txlen);
+ mwifiex_dbg(adapter, ERROR,
+ "CRC indicated by the helper:\t"
+ "len = 0x%04X, txlen = %d\n", len, txlen);
len &= ~BIT(0);
/* Setting this to 0 to resend from same offset */
txlen = 0;
@@ -978,11 +1000,12 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
MWIFIEX_SDIO_BLOCK_SIZE,
adapter->ioport);
if (ret) {
- dev_err(adapter->dev,
- "FW download, write iomem (%d) failed @ %d\n",
- i, offset);
+ mwifiex_dbg(adapter, ERROR,
+ "FW download, write iomem (%d) failed @ %d\n",
+ i, offset);
if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04))
- dev_err(adapter->dev, "write CFG reg failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "write CFG reg failed\n");
ret = -1;
goto done;
@@ -991,8 +1014,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
offset += txlen;
} while (true);
- dev_notice(adapter->dev,
- "info: FW download over, size %d bytes\n", offset);
+ mwifiex_dbg(adapter, MSG,
+ "info: FW download over, size %d bytes\n", offset);
ret = 0;
done:
@@ -1066,18 +1089,20 @@ static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter,
blk_num = *(data + BLOCK_NUMBER_OFFSET);
blk_size = adapter->sdio_rx_block_size * blk_num;
if (blk_size > total_pkt_len) {
- dev_err(adapter->dev, "%s: error in pkt,\t"
- "blk_num=%d, blk_size=%d, total_pkt_len=%d\n",
- __func__, blk_num, blk_size, total_pkt_len);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: error in blk_size,\t"
+ "blk_num=%d, blk_size=%d, total_pkt_len=%d\n",
+ __func__, blk_num, blk_size, total_pkt_len);
break;
}
pkt_len = le16_to_cpu(*(__le16 *)(data + SDIO_HEADER_OFFSET));
pkt_type = le16_to_cpu(*(__le16 *)(data + SDIO_HEADER_OFFSET +
2));
if ((pkt_len + SDIO_HEADER_OFFSET) > blk_size) {
- dev_err(adapter->dev, "%s: error in pkt,\t"
- "pkt_len=%d, blk_size=%d\n",
- __func__, pkt_len, blk_size);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: error in pkt_len,\t"
+ "pkt_len=%d, blk_size=%d\n",
+ __func__, pkt_len, blk_size);
break;
}
skb_deaggr = mwifiex_alloc_dma_align_buf(pkt_len,
@@ -1116,7 +1141,8 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
switch (upld_typ) {
case MWIFIEX_TYPE_AGGR_DATA:
- dev_dbg(adapter->dev, "info: --- Rx: Aggr Data packet ---\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: --- Rx: Aggr Data packet ---\n");
rx_info = MWIFIEX_SKB_RXCB(skb);
rx_info->buf_type = MWIFIEX_TYPE_AGGR_DATA;
if (adapter->rx_work_enabled) {
@@ -1130,7 +1156,8 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
break;
case MWIFIEX_TYPE_DATA:
- dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n");
+ mwifiex_dbg(adapter, DATA,
+ "info: --- Rx: Data packet ---\n");
if (adapter->rx_work_enabled) {
skb_queue_tail(&adapter->rx_data_q, skb);
adapter->data_received = true;
@@ -1141,7 +1168,8 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
break;
case MWIFIEX_TYPE_CMD:
- dev_dbg(adapter->dev, "info: --- Rx: Cmd Response ---\n");
+ mwifiex_dbg(adapter, CMD,
+ "info: --- Rx: Cmd Response ---\n");
/* take care of curr_cmd = NULL case */
if (!adapter->curr_cmd) {
cmd_buf = adapter->upld_buf;
@@ -1163,7 +1191,8 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
break;
case MWIFIEX_TYPE_EVENT:
- dev_dbg(adapter->dev, "info: --- Rx: Event ---\n");
+ mwifiex_dbg(adapter, EVENT,
+ "info: --- Rx: Event ---\n");
adapter->event_cause = le32_to_cpu(*(__le32 *) skb->data);
if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE))
@@ -1178,7 +1207,8 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
break;
default:
- dev_err(adapter->dev, "unknown upload type %#x\n", upld_typ);
+ mwifiex_dbg(adapter, ERROR,
+ "unknown upload type %#x\n", upld_typ);
dev_kfree_skb_any(skb);
break;
}
@@ -1210,16 +1240,18 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
if ((card->has_control_mask) && (port == CTRL_PORT)) {
/* Read the command Resp without aggr */
- dev_dbg(adapter->dev, "info: %s: no aggregation for cmd "
- "response\n", __func__);
+ mwifiex_dbg(adapter, CMD,
+ "info: %s: no aggregation for cmd\t"
+ "response\n", __func__);
f_do_rx_cur = 1;
goto rx_curr_single;
}
if (!card->mpa_rx.enabled) {
- dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n",
- __func__);
+ mwifiex_dbg(adapter, WARN,
+ "info: %s: rx aggregation disabled\n",
+ __func__);
f_do_rx_cur = 1;
goto rx_curr_single;
@@ -1230,7 +1262,8 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
(card->has_control_mask && (card->mp_rd_bitmap &
(~((u32) CTRL_PORT_MASK))))) {
/* Some more data RX pending */
- dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: not last packet\n", __func__);
if (MP_RX_AGGR_IN_PROGRESS(card)) {
if (MP_RX_AGGR_BUF_HAS_ROOM(card, rx_len)) {
@@ -1247,7 +1280,8 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
} else {
/* No more data RX pending */
- dev_dbg(adapter->dev, "info: %s: last packet\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: last packet\n", __func__);
if (MP_RX_AGGR_IN_PROGRESS(card)) {
f_do_rx_aggr = 1;
@@ -1262,14 +1296,16 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
}
if (f_aggr_cur) {
- dev_dbg(adapter->dev, "info: current packet aggregation\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: current packet aggregation\n");
/* Curr pkt can be aggregated */
mp_rx_aggr_setup(card, rx_len, port);
if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) ||
mp_rx_aggr_port_limit_reached(card)) {
- dev_dbg(adapter->dev, "info: %s: aggregated packet "
- "limit reached\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: aggregated packet\t"
+ "limit reached\n", __func__);
/* No more pkts allowed in Aggr buf, rx it */
f_do_rx_aggr = 1;
}
@@ -1277,8 +1313,9 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
if (f_do_rx_aggr) {
/* do aggr RX now */
- dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n",
- card->mpa_rx.pkt_cnt);
+ mwifiex_dbg(adapter, DATA,
+ "info: do_rx_aggr: num of packets: %d\n",
+ card->mpa_rx.pkt_cnt);
if (card->supports_sdio_new_mode) {
int i;
@@ -1318,8 +1355,9 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
GFP_KERNEL |
GFP_DMA);
if (!skb_deaggr) {
- dev_err(adapter->dev, "skb allocation failure drop pkt len=%d type=%d\n",
- pkt_len, pkt_type);
+ mwifiex_dbg(adapter, ERROR, "skb allocation failure\t"
+ "drop pkt len=%d type=%d\n",
+ pkt_len, pkt_type);
curr_ptr += len_arr[pind];
continue;
}
@@ -1339,12 +1377,12 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
mwifiex_decode_rx_packet(adapter, skb_deaggr,
pkt_type);
} else {
- dev_err(adapter->dev, " drop wrong aggr pkt:\t"
- "sdio_single_port_rx_aggr=%d\t"
- "type=%d len=%d max_len=%d\n",
- adapter->sdio_rx_aggr_enable,
- pkt_type, pkt_len,
- len_arr[pind]);
+ mwifiex_dbg(adapter, ERROR,
+ "drop wrong aggr pkt:\t"
+ "sdio_single_port_rx_aggr=%d\t"
+ "type=%d len=%d max_len=%d\n",
+ adapter->sdio_rx_aggr_enable,
+ pkt_type, pkt_len, len_arr[pind]);
dev_kfree_skb_any(skb_deaggr);
}
curr_ptr += len_arr[pind];
@@ -1354,13 +1392,14 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
rx_curr_single:
if (f_do_rx_cur) {
- dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n",
- port, rx_len);
+ mwifiex_dbg(adapter, INFO, "info: RX: port: %d, rx_len: %d\n",
+ port, rx_len);
skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA);
if (!skb) {
- dev_err(adapter->dev, "single skb allocated fail,\t"
- "drop pkt port=%d len=%d\n", port, rx_len);
+ mwifiex_dbg(adapter, ERROR,
+ "single skb allocated fail,\t"
+ "drop pkt port=%d len=%d\n", port, rx_len);
if (mwifiex_sdio_card_to_host(adapter, &pkt_type,
card->mpa_rx.buf, rx_len,
adapter->ioport + port))
@@ -1376,9 +1415,9 @@ rx_curr_single:
goto error;
if (!adapter->sdio_rx_aggr_enable &&
pkt_type == MWIFIEX_TYPE_AGGR_DATA) {
- dev_err(adapter->dev, "drop wrong pkt type %d\t"
- "current SDIO RX Aggr not enabled\n",
- pkt_type);
+ mwifiex_dbg(adapter, ERROR, "drop wrong pkt type %d\t"
+ "current SDIO RX Aggr not enabled\n",
+ pkt_type);
dev_kfree_skb_any(skb);
return 0;
}
@@ -1386,7 +1425,8 @@ rx_curr_single:
mwifiex_decode_rx_packet(adapter, skb, pkt_type);
}
if (f_post_aggr_cur) {
- dev_dbg(adapter->dev, "info: current packet aggregation\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: current packet aggregation\n");
/* Curr pkt can be aggregated */
mp_rx_aggr_setup(card, rx_len, port);
}
@@ -1458,7 +1498,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
MWIFIEX_RX_DATA_BUF_SIZE)
return -1;
rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE);
- dev_dbg(adapter->dev, "info: rx_len = %d\n", rx_len);
+ mwifiex_dbg(adapter, INFO, "info: rx_len = %d\n", rx_len);
skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA);
if (!skb)
@@ -1469,17 +1509,17 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
if (mwifiex_sdio_card_to_host(adapter, &pkt_type, skb->data,
skb->len, adapter->ioport |
CMD_PORT_SLCT)) {
- dev_err(adapter->dev,
- "%s: failed to card_to_host", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: failed to card_to_host", __func__);
dev_kfree_skb_any(skb);
goto term_cmd;
}
if ((pkt_type != MWIFIEX_TYPE_CMD) &&
(pkt_type != MWIFIEX_TYPE_EVENT))
- dev_err(adapter->dev,
- "%s:Received wrong packet on cmd port",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s:Received wrong packet on cmd port",
+ __func__);
mwifiex_decode_rx_packet(adapter, skb, pkt_type);
}
@@ -1495,12 +1535,13 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
}
card->mp_wr_bitmap = bitmap;
- dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%x\n",
- card->mp_wr_bitmap);
+ mwifiex_dbg(adapter, INTR,
+ "int: DNLD: wr_bitmap=0x%x\n",
+ card->mp_wr_bitmap);
if (adapter->data_sent &&
(card->mp_wr_bitmap & card->mp_data_port_mask)) {
- dev_dbg(adapter->dev,
- "info: <--- Tx DONE Interrupt --->\n");
+ mwifiex_dbg(adapter, INTR,
+ "info: <--- Tx DONE Interrupt --->\n");
adapter->data_sent = false;
}
}
@@ -1517,8 +1558,8 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
adapter->cmd_sent = false;
}
- dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n",
- adapter->cmd_sent, adapter->data_sent);
+ mwifiex_dbg(adapter, INTR, "info: cmd_sent=%d data_sent=%d\n",
+ adapter->cmd_sent, adapter->data_sent);
if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
bitmap = (u32) card->mp_regs[reg->rd_bitmap_l];
bitmap |= ((u32) card->mp_regs[reg->rd_bitmap_u]) << 8;
@@ -1529,40 +1570,45 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
((u32) card->mp_regs[reg->rd_bitmap_1u]) << 24;
}
card->mp_rd_bitmap = bitmap;
- dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%x\n",
- card->mp_rd_bitmap);
+ mwifiex_dbg(adapter, INTR,
+ "int: UPLD: rd_bitmap=0x%x\n",
+ card->mp_rd_bitmap);
while (true) {
ret = mwifiex_get_rd_port(adapter, &port);
if (ret) {
- dev_dbg(adapter->dev,
- "info: no more rd_port available\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: no more rd_port available\n");
break;
}
len_reg_l = reg->rd_len_p0_l + (port << 1);
len_reg_u = reg->rd_len_p0_u + (port << 1);
rx_len = ((u16) card->mp_regs[len_reg_u]) << 8;
rx_len |= (u16) card->mp_regs[len_reg_l];
- dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n",
- port, rx_len);
+ mwifiex_dbg(adapter, INFO,
+ "info: RX: port=%d rx_len=%u\n",
+ port, rx_len);
rx_blocks =
(rx_len + MWIFIEX_SDIO_BLOCK_SIZE -
1) / MWIFIEX_SDIO_BLOCK_SIZE;
if (rx_len <= INTF_HEADER_LEN ||
(rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) >
card->mpa_rx.buf_size) {
- dev_err(adapter->dev, "invalid rx_len=%d\n",
- rx_len);
+ mwifiex_dbg(adapter, ERROR,
+ "invalid rx_len=%d\n",
+ rx_len);
return -1;
}
rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE);
- dev_dbg(adapter->dev, "info: rx_len = %d\n", rx_len);
+ mwifiex_dbg(adapter, INFO, "info: rx_len = %d\n",
+ rx_len);
if (mwifiex_sdio_card_to_host_mp_aggr(adapter, rx_len,
port)) {
- dev_err(adapter->dev, "card_to_host_mpa failed:"
- " int status=%#x\n", sdio_ireg);
+ mwifiex_dbg(adapter, ERROR,
+ "card_to_host_mpa failed: int status=%#x\n",
+ sdio_ireg);
goto term_cmd;
}
}
@@ -1573,19 +1619,23 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
term_cmd:
/* terminate cmd */
if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr))
- dev_err(adapter->dev, "read CFG reg failed\n");
+ mwifiex_dbg(adapter, ERROR, "read CFG reg failed\n");
else
- dev_dbg(adapter->dev, "info: CFG reg val = %d\n", cr);
+ mwifiex_dbg(adapter, INFO,
+ "info: CFG reg val = %d\n", cr);
if (mwifiex_write_reg(adapter, CONFIGURATION_REG, (cr | 0x04)))
- dev_err(adapter->dev, "write CFG reg failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "write CFG reg failed\n");
else
- dev_dbg(adapter->dev, "info: write success\n");
+ mwifiex_dbg(adapter, INFO, "info: write success\n");
if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr))
- dev_err(adapter->dev, "read CFG reg failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "read CFG reg failed\n");
else
- dev_dbg(adapter->dev, "info: CFG reg val =%x\n", cr);
+ mwifiex_dbg(adapter, INFO,
+ "info: CFG reg val =%x\n", cr);
return -1;
}
@@ -1619,8 +1669,9 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
if (!card->mpa_tx.enabled ||
(card->has_control_mask && (port == CTRL_PORT)) ||
(card->supports_sdio_new_mode && (port == CMD_PORT_SLCT))) {
- dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n",
- __func__);
+ mwifiex_dbg(adapter, WARN,
+ "info: %s: tx aggregation disabled\n",
+ __func__);
f_send_cur_buf = 1;
goto tx_curr_single;
@@ -1628,8 +1679,9 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
if (next_pkt_len) {
/* More pkt in TX queue */
- dev_dbg(adapter->dev, "info: %s: more packets in queue.\n",
- __func__);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: more packets in queue.\n",
+ __func__);
if (MP_TX_AGGR_IN_PROGRESS(card)) {
if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) {
@@ -1659,8 +1711,9 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
}
} else {
/* Last pkt in TX queue */
- dev_dbg(adapter->dev, "info: %s: Last packet in Tx Queue.\n",
- __func__);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: Last packet in Tx Queue.\n",
+ __func__);
if (MP_TX_AGGR_IN_PROGRESS(card)) {
/* some packs in Aggr buf already */
@@ -1677,8 +1730,9 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
}
if (f_precopy_cur_buf) {
- dev_dbg(adapter->dev, "data: %s: precopy current buffer\n",
- __func__);
+ mwifiex_dbg(adapter, DATA,
+ "data: %s: precopy current buffer\n",
+ __func__);
MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port);
if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) ||
@@ -1688,9 +1742,10 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
}
if (f_send_aggr_buf) {
- dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n",
- __func__,
- card->mpa_tx.start_port, card->mpa_tx.ports);
+ mwifiex_dbg(adapter, DATA,
+ "data: %s: send aggr buffer: %d %d\n",
+ __func__, card->mpa_tx.start_port,
+ card->mpa_tx.ports);
if (card->supports_sdio_new_mode) {
u32 port_count;
int i;
@@ -1719,15 +1774,17 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
tx_curr_single:
if (f_send_cur_buf) {
- dev_dbg(adapter->dev, "data: %s: send current buffer %d\n",
- __func__, port);
+ mwifiex_dbg(adapter, DATA,
+ "data: %s: send current buffer %d\n",
+ __func__, port);
ret = mwifiex_write_data_to_card(adapter, payload, pkt_len,
adapter->ioport + port);
}
if (f_postcopy_cur_buf) {
- dev_dbg(adapter->dev, "data: %s: postcopy current buffer\n",
- __func__);
+ mwifiex_dbg(adapter, DATA,
+ "data: %s: postcopy current buffer\n",
+ __func__);
MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port);
}
@@ -1771,8 +1828,9 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
if (type == MWIFIEX_TYPE_DATA) {
ret = mwifiex_get_wr_port_data(adapter, &port);
if (ret) {
- dev_err(adapter->dev, "%s: no wr_port available\n",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: no wr_port available\n",
+ __func__);
return ret;
}
} else {
@@ -1781,8 +1839,9 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
if (pkt_len <= INTF_HEADER_LEN ||
pkt_len > MWIFIEX_UPLD_SIZE)
- dev_err(adapter->dev, "%s: payload=%p, nb=%d\n",
- __func__, payload, pkt_len);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: payload=%p, nb=%d\n",
+ __func__, payload, pkt_len);
if (card->supports_sdio_new_mode)
port = CMD_PORT_SLCT;
@@ -1896,7 +1955,8 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE);
sdio_release_host(func);
if (ret) {
- pr_err("cannot set SDIO block size\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot set SDIO block size\n");
return ret;
}
@@ -1977,7 +2037,8 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
card->mp_tx_agg_buf_size,
card->mp_rx_agg_buf_size);
if (ret) {
- dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n");
+ mwifiex_dbg(adapter, ERROR,
+ "failed to alloc sdio mp-a buffers\n");
kfree(card->mp_regs);
return -1;
}
@@ -2041,8 +2102,9 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port)
card->curr_wr_port = reg->start_wr_port;
- dev_dbg(adapter->dev, "cmd: mp_end_port %d, data port mask 0x%x\n",
- port, card->mp_data_port_mask);
+ mwifiex_dbg(adapter, CMD,
+ "cmd: mp_end_port %d, data port mask 0x%x\n",
+ port, card->mp_data_port_mask);
}
static struct mwifiex_adapter *save_adapter;
@@ -2059,7 +2121,7 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter)
* We run it in a totally independent workqueue.
*/
- pr_err("Resetting card...\n");
+ mwifiex_dbg(adapter, WARN, "Resetting card...\n");
mmc_remove_host(target);
/* 200ms delay is based on experiment with sdhci controller */
mdelay(200);
@@ -2079,14 +2141,14 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter,
sdio_writeb(card->func, FW_DUMP_HOST_READY, card->reg->fw_dump_ctrl,
&ret);
if (ret) {
- dev_err(adapter->dev, "SDIO Write ERR\n");
+ mwifiex_dbg(adapter, ERROR, "SDIO Write ERR\n");
return RDWR_STATUS_FAILURE;
}
for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
ctrl_data = sdio_readb(card->func, card->reg->fw_dump_ctrl,
&ret);
if (ret) {
- dev_err(adapter->dev, "SDIO read err\n");
+ mwifiex_dbg(adapter, ERROR, "SDIO read err\n");
return RDWR_STATUS_FAILURE;
}
if (ctrl_data == FW_DUMP_DONE)
@@ -2094,19 +2156,20 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter,
if (doneflag && ctrl_data == doneflag)
return RDWR_STATUS_DONE;
if (ctrl_data != FW_DUMP_HOST_READY) {
- dev_info(adapter->dev,
- "The ctrl reg was changed, re-try again!\n");
+ mwifiex_dbg(adapter, WARN,
+ "The ctrl reg was changed, re-try again!\n");
sdio_writeb(card->func, FW_DUMP_HOST_READY,
card->reg->fw_dump_ctrl, &ret);
if (ret) {
- dev_err(adapter->dev, "SDIO write err\n");
+ mwifiex_dbg(adapter, ERROR, "SDIO write err\n");
return RDWR_STATUS_FAILURE;
}
}
usleep_range(100, 200);
}
if (ctrl_data == FW_DUMP_HOST_READY) {
- dev_err(adapter->dev, "Fail to pull ctrl_data\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Fail to pull ctrl_data\n");
return RDWR_STATUS_FAILURE;
}
@@ -2114,7 +2177,7 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter,
}
/* This function dump firmware memory to file */
-static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter)
+static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter)
{
struct sdio_mmc_card *card = adapter->card;
int ret = 0;
@@ -2122,9 +2185,6 @@ static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter)
u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0;
enum rdwr_status stat;
u32 memory_size;
- static char *env[] = { "DRIVER=mwifiex_sdio", "EVENT=fw_dump", NULL };
-
- mwifiex_dump_drv_info(adapter);
if (!card->can_dump_fw)
return;
@@ -2142,7 +2202,7 @@ static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter)
mwifiex_pm_wakeup_card(adapter);
sdio_claim_host(card->func);
- dev_info(adapter->dev, "== mwifiex firmware dump start ==\n");
+ mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump start ==\n");
stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag);
if (stat == RDWR_STATUS_FAILURE)
@@ -2152,7 +2212,7 @@ static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter)
/* Read the number of the memories which will dump */
dump_num = sdio_readb(card->func, reg, &ret);
if (ret) {
- dev_err(adapter->dev, "SDIO read memory length err\n");
+ mwifiex_dbg(adapter, ERROR, "SDIO read memory length err\n");
goto done;
}
@@ -2169,7 +2229,7 @@ static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter)
for (i = 0; i < 4; i++) {
read_reg = sdio_readb(card->func, reg, &ret);
if (ret) {
- dev_err(adapter->dev, "SDIO read err\n");
+ mwifiex_dbg(adapter, ERROR, "SDIO read err\n");
goto done;
}
memory_size |= (read_reg << i*8);
@@ -2177,25 +2237,33 @@ static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter)
}
if (memory_size == 0) {
- dev_info(adapter->dev, "Firmware dump Finished!\n");
+ mwifiex_dbg(adapter, DUMP, "Firmware dump Finished!\n");
+ ret = mwifiex_write_reg(adapter,
+ card->reg->fw_dump_ctrl,
+ FW_DUMP_READ_DONE);
+ if (ret) {
+ mwifiex_dbg(adapter, ERROR, "SDIO write err\n");
+ return;
+ }
break;
}
- dev_info(adapter->dev,
- "%s_SIZE=0x%x\n", entry->mem_name, memory_size);
+ mwifiex_dbg(adapter, DUMP,
+ "%s_SIZE=0x%x\n", entry->mem_name, memory_size);
entry->mem_ptr = vmalloc(memory_size + 1);
entry->mem_size = memory_size;
if (!entry->mem_ptr) {
- dev_err(adapter->dev, "Vmalloc %s failed\n",
- entry->mem_name);
+ mwifiex_dbg(adapter, ERROR, "Vmalloc %s failed\n",
+ entry->mem_name);
goto done;
}
dbg_ptr = entry->mem_ptr;
end_ptr = dbg_ptr + memory_size;
doneflag = entry->done_flag;
- dev_info(adapter->dev, "Start %s output, please wait...\n",
- entry->mem_name);
+ mwifiex_dbg(adapter, DUMP,
+ "Start %s output, please wait...\n",
+ entry->mem_name);
do {
stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag);
@@ -2207,39 +2275,43 @@ static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter)
for (reg = reg_start; reg <= reg_end; reg++) {
*dbg_ptr = sdio_readb(card->func, reg, &ret);
if (ret) {
- dev_err(adapter->dev,
- "SDIO read err\n");
+ mwifiex_dbg(adapter, ERROR,
+ "SDIO read err\n");
goto done;
}
if (dbg_ptr < end_ptr)
dbg_ptr++;
else
- dev_err(adapter->dev,
- "Allocated buf not enough\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Allocated buf not enough\n");
}
if (stat != RDWR_STATUS_DONE)
continue;
- dev_info(adapter->dev, "%s done: size=0x%tx\n",
- entry->mem_name, dbg_ptr - entry->mem_ptr);
+ mwifiex_dbg(adapter, DUMP, "%s done: size=0x%tx\n",
+ entry->mem_name, dbg_ptr - entry->mem_ptr);
break;
} while (1);
}
- dev_info(adapter->dev, "== mwifiex firmware dump end ==\n");
-
- kobject_uevent_env(&adapter->wiphy->dev.kobj, KOBJ_CHANGE, env);
+ mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n");
done:
sdio_release_host(card->func);
- adapter->curr_mem_idx = 0;
+}
+
+static void mwifiex_sdio_device_dump_work(struct mwifiex_adapter *adapter)
+{
+ mwifiex_drv_info_dump(adapter);
+ mwifiex_sdio_fw_dump(adapter);
+ mwifiex_upload_device_dump(adapter);
}
static void mwifiex_sdio_work(struct work_struct *work)
{
- if (test_and_clear_bit(MWIFIEX_IFACE_WORK_FW_DUMP,
+ if (test_and_clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP,
&iface_work_flags))
- mwifiex_sdio_fw_dump_work(save_adapter);
+ mwifiex_sdio_device_dump_work(save_adapter);
if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET,
&iface_work_flags))
mwifiex_sdio_card_reset_work(save_adapter);
@@ -2259,13 +2331,13 @@ static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter)
}
/* This function dumps FW information */
-static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter)
+static void mwifiex_sdio_device_dump(struct mwifiex_adapter *adapter)
{
save_adapter = adapter;
- if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags))
+ if (test_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &iface_work_flags))
return;
- set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags);
+ set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &iface_work_flags);
schedule_work(&sdio_work);
}
@@ -2285,7 +2357,7 @@ mwifiex_sdio_reg_dump(struct mwifiex_adapter *adapter, char *drv_buf)
if (!p)
return 0;
- dev_info(adapter->dev, "SDIO register DUMP START\n");
+ mwifiex_dbg(adapter, MSG, "SDIO register dump start\n");
mwifiex_pm_wakeup_card(adapter);
@@ -2351,13 +2423,13 @@ mwifiex_sdio_reg_dump(struct mwifiex_adapter *adapter, char *drv_buf)
reg++;
}
- dev_info(adapter->dev, "%s\n", buf);
+ mwifiex_dbg(adapter, MSG, "%s\n", buf);
p += sprintf(p, "%s\n", buf);
}
sdio_release_host(cardp->func);
- dev_info(adapter->dev, "SDIO register DUMP END\n");
+ mwifiex_dbg(adapter, MSG, "SDIO register dump end\n");
return p - drv_buf;
}
@@ -2382,8 +2454,8 @@ static struct mwifiex_if_ops sdio_ops = {
.cmdrsp_complete = mwifiex_sdio_cmdrsp_complete,
.event_complete = mwifiex_sdio_event_complete,
.card_reset = mwifiex_sdio_card_reset,
- .fw_dump = mwifiex_sdio_fw_dump,
.reg_dump = mwifiex_sdio_reg_dump,
+ .device_dump = mwifiex_sdio_device_dump,
.deaggr_pkt = mwifiex_deaggr_sdio_pkt,
};
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 49422f2a5380..037adcd1f484 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -77,8 +77,8 @@ static int mwifiex_cmd_mac_control(struct mwifiex_private *priv,
struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl;
if (cmd_action != HostCmd_ACT_GEN_SET) {
- dev_err(priv->adapter->dev,
- "mac_control: only support set cmd\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "mac_control: only support set cmd\n");
return -1;
}
@@ -112,7 +112,8 @@ static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv,
{
struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib;
- dev_dbg(priv->adapter->dev, "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib)
- 1 + S_DS_GEN);
@@ -129,11 +130,11 @@ static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv,
le16_add_cpu(&cmd->size, sizeof(u16));
}
- dev_dbg(priv->adapter->dev,
- "cmd: SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x,"
- " Value=0x%x\n",
- cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size),
- le16_to_cpu(*(__le16 *) snmp_mib->value));
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: SNMP_CMD: Action=0x%x, OID=0x%x,\t"
+ "OIDSize=0x%x, Value=0x%x\n",
+ cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size),
+ le16_to_cpu(*(__le16 *)snmp_mib->value));
return 0;
}
@@ -356,9 +357,9 @@ mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv,
(hscfg_param->conditions != cpu_to_le32(HS_CFG_CANCEL)) &&
((adapter->arp_filter_size > 0) &&
(adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) {
- dev_dbg(adapter->dev,
- "cmd: Attach %d bytes ArpFilter to HSCfg cmd\n",
- adapter->arp_filter_size);
+ mwifiex_dbg(adapter, CMD,
+ "cmd: Attach %d bytes ArpFilter to HSCfg cmd\n",
+ adapter->arp_filter_size);
memcpy(((u8 *) hs_cfg) +
sizeof(struct host_cmd_ds_802_11_hs_cfg_enh),
adapter->arp_filter, adapter->arp_filter_size);
@@ -378,11 +379,11 @@ mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv,
hs_cfg->params.hs_config.conditions = hscfg_param->conditions;
hs_cfg->params.hs_config.gpio = hscfg_param->gpio;
hs_cfg->params.hs_config.gap = hscfg_param->gap;
- dev_dbg(adapter->dev,
- "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
- hs_cfg->params.hs_config.conditions,
- hs_cfg->params.hs_config.gpio,
- hs_cfg->params.hs_config.gap);
+ mwifiex_dbg(adapter, CMD,
+ "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
+ hs_cfg->params.hs_config.conditions,
+ hs_cfg->params.hs_config.gpio,
+ hs_cfg->params.hs_config.gap);
}
return 0;
@@ -462,7 +463,7 @@ static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv,
/* Set AP MAC address */
memcpy(deauth->mac_addr, mac, ETH_ALEN);
- dev_dbg(priv->adapter->dev, "cmd: Deauth: %pM\n", deauth->mac_addr);
+ mwifiex_dbg(priv->adapter, CMD, "cmd: Deauth: %pM\n", deauth->mac_addr);
deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING);
@@ -540,9 +541,9 @@ mwifiex_set_keyparamset_wep(struct mwifiex_private *priv,
} else if (!priv->wep_key[i].key_length) {
continue;
} else {
- dev_err(priv->adapter->dev,
- "key%d Length = %d is incorrect\n",
- (i + 1), priv->wep_key[i].key_length);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "key%d Length = %d is incorrect\n",
+ (i + 1), priv->wep_key[i].key_length);
return -1;
}
}
@@ -562,7 +563,8 @@ static int mwifiex_set_aes_key_v2(struct mwifiex_private *priv,
u16 size, len = KEY_PARAMS_FIXED_LEN;
if (enc_key->is_igtk_key) {
- dev_dbg(adapter->dev, "%s: Set CMAC AES Key\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "%s: Set CMAC AES Key\n", __func__);
if (enc_key->is_rx_seq_valid)
memcpy(km->key_param_set.key_params.cmac_aes.ipn,
enc_key->pn, enc_key->pn_len);
@@ -575,7 +577,8 @@ static int mwifiex_set_aes_key_v2(struct mwifiex_private *priv,
enc_key->key_material, enc_key->key_len);
len += sizeof(struct mwifiex_cmac_aes_param);
} else {
- dev_dbg(adapter->dev, "%s: Set AES Key\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "%s: Set AES Key\n", __func__);
if (enc_key->is_rx_seq_valid)
memcpy(km->key_param_set.key_params.aes.pn,
enc_key->pn, enc_key->pn_len);
@@ -619,7 +622,7 @@ mwifiex_cmd_802_11_key_material_v2(struct mwifiex_private *priv,
km->action = cpu_to_le16(cmd_action);
if (cmd_action == HostCmd_ACT_GEN_GET) {
- dev_dbg(adapter->dev, "%s: Get key\n", __func__);
+ mwifiex_dbg(adapter, INFO, "%s: Get key\n", __func__);
km->key_param_set.key_idx =
enc_key->key_index & KEY_INDEX_MASK;
km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
@@ -646,7 +649,7 @@ mwifiex_cmd_802_11_key_material_v2(struct mwifiex_private *priv,
sizeof(struct mwifiex_ie_type_key_param_set_v2));
if (enc_key->key_disable) {
- dev_dbg(adapter->dev, "%s: Remove key\n", __func__);
+ mwifiex_dbg(adapter, INFO, "%s: Remove key\n", __func__);
km->action = cpu_to_le16(HostCmd_ACT_GEN_REMOVE);
km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
km->key_param_set.len = cpu_to_le16(KEY_PARAMS_FIXED_LEN);
@@ -667,7 +670,7 @@ mwifiex_cmd_802_11_key_material_v2(struct mwifiex_private *priv,
memcpy(km->key_param_set.mac_addr, mac, ETH_ALEN);
if (enc_key->key_len <= WLAN_KEY_LEN_WEP104) {
- dev_dbg(adapter->dev, "%s: Set WEP Key\n", __func__);
+ mwifiex_dbg(adapter, INFO, "%s: Set WEP Key\n", __func__);
len += sizeof(struct mwifiex_wep_param);
km->key_param_set.len = cpu_to_le16(len);
km->key_param_set.key_type = KEY_TYPE_ID_WEP;
@@ -710,7 +713,7 @@ mwifiex_cmd_802_11_key_material_v2(struct mwifiex_private *priv,
key_info |= KEY_UNICAST | KEY_TX_KEY | KEY_RX_KEY;
if (enc_key->is_wapi_key) {
- dev_dbg(adapter->dev, "%s: Set WAPI Key\n", __func__);
+ mwifiex_dbg(adapter, INFO, "%s: Set WAPI Key\n", __func__);
km->key_param_set.key_type = KEY_TYPE_ID_WAPI;
memcpy(km->key_param_set.key_params.wapi.pn, enc_key->pn,
PN_LEN);
@@ -750,7 +753,8 @@ mwifiex_cmd_802_11_key_material_v2(struct mwifiex_private *priv,
return mwifiex_set_aes_key_v2(priv, cmd, enc_key, km);
if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
- dev_dbg(adapter->dev, "%s: Set TKIP Key\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "%s: Set TKIP Key\n", __func__);
if (enc_key->is_rx_seq_valid)
memcpy(km->key_param_set.key_params.tkip.pn,
enc_key->pn, enc_key->pn_len);
@@ -814,7 +818,7 @@ mwifiex_cmd_802_11_key_material_v1(struct mwifiex_private *priv,
memset(&key_material->key_param_set, 0,
sizeof(struct mwifiex_ie_type_key_param_set));
if (enc_key->is_wapi_key) {
- dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n");
+ mwifiex_dbg(priv->adapter, INFO, "info: Set WAPI Key\n");
key_material->key_param_set.key_type_id =
cpu_to_le16(KEY_TYPE_ID_WAPI);
if (cmd_oid == KEY_INFO_ENABLED)
@@ -860,7 +864,7 @@ mwifiex_cmd_802_11_key_material_v1(struct mwifiex_private *priv,
}
if (enc_key->key_len == WLAN_KEY_LEN_CCMP) {
if (enc_key->is_igtk_key) {
- dev_dbg(priv->adapter->dev, "cmd: CMAC_AES\n");
+ mwifiex_dbg(priv->adapter, CMD, "cmd: CMAC_AES\n");
key_material->key_param_set.key_type_id =
cpu_to_le16(KEY_TYPE_ID_AES_CMAC);
if (cmd_oid == KEY_INFO_ENABLED)
@@ -873,7 +877,7 @@ mwifiex_cmd_802_11_key_material_v1(struct mwifiex_private *priv,
key_material->key_param_set.key_info |=
cpu_to_le16(KEY_IGTK);
} else {
- dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
+ mwifiex_dbg(priv->adapter, CMD, "cmd: WPA_AES\n");
key_material->key_param_set.key_type_id =
cpu_to_le16(KEY_TYPE_ID_AES);
if (cmd_oid == KEY_INFO_ENABLED)
@@ -892,7 +896,7 @@ mwifiex_cmd_802_11_key_material_v1(struct mwifiex_private *priv,
cpu_to_le16(KEY_MCAST);
}
} else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
- dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n");
+ mwifiex_dbg(priv->adapter, CMD, "cmd: WPA_TKIP\n");
key_material->key_param_set.key_type_id =
cpu_to_le16(KEY_TYPE_ID_TKIP);
key_material->key_param_set.key_info =
@@ -999,7 +1003,8 @@ static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv,
&domain_info->domain;
u8 no_of_triplet = adapter->domain_reg.no_of_triplet;
- dev_dbg(adapter->dev, "info: 11D: no_of_triplet=0x%x\n", no_of_triplet);
+ mwifiex_dbg(adapter, INFO,
+ "info: 11D: no_of_triplet=0x%x\n", no_of_triplet);
cmd->command = cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO);
domain_info->action = cpu_to_le16(cmd_action);
@@ -1071,6 +1076,26 @@ static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd,
return 0;
}
+/* This function prepares command buffer to get/set memory location value.
+ */
+static int
+mwifiex_cmd_mem_access(struct host_cmd_ds_command *cmd, u16 cmd_action,
+ void *pdata_buf)
+{
+ struct mwifiex_ds_mem_rw *mem_rw = (void *)pdata_buf;
+ struct host_cmd_ds_mem_access *mem_access = (void *)&cmd->params.mem;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_MEM_ACCESS);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mem_access) +
+ S_DS_GEN);
+
+ mem_access->action = cpu_to_le16(cmd_action);
+ mem_access->addr = cpu_to_le32(mem_rw->addr);
+ mem_access->value = cpu_to_le32(mem_rw->value);
+
+ return 0;
+}
+
/*
* This function prepares command to set/get register value.
*
@@ -1215,8 +1240,9 @@ mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv,
(u32)(card->sleep_cookie_pbase);
host_spec->sleep_cookie_addr_hi =
(u32)(((u64)(card->sleep_cookie_pbase)) >> 32);
- dev_dbg(priv->adapter->dev, "sleep_cook_lo phy addr: 0x%x\n",
- host_spec->sleep_cookie_addr_lo);
+ mwifiex_dbg(priv->adapter, INFO,
+ "sleep_cook_lo phy addr: 0x%x\n",
+ host_spec->sleep_cookie_addr_lo);
}
return 0;
@@ -1243,7 +1269,8 @@ mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv,
S_DS_GEN);
subsc_evt->action = cpu_to_le16(subsc_evt_cfg->action);
- dev_dbg(priv->adapter->dev, "cmd: action: %d\n", subsc_evt_cfg->action);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: action: %d\n", subsc_evt_cfg->action);
/*For query requests, no configuration TLV structures are to be added.*/
if (subsc_evt_cfg->action == HostCmd_ACT_GEN_GET)
@@ -1252,14 +1279,15 @@ mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv,
subsc_evt->events = cpu_to_le16(subsc_evt_cfg->events);
event_bitmap = subsc_evt_cfg->events;
- dev_dbg(priv->adapter->dev, "cmd: event bitmap : %16x\n",
- event_bitmap);
+ mwifiex_dbg(priv->adapter, CMD, "cmd: event bitmap : %16x\n",
+ event_bitmap);
if (((subsc_evt_cfg->action == HostCmd_ACT_BITWISE_CLR) ||
(subsc_evt_cfg->action == HostCmd_ACT_BITWISE_SET)) &&
(event_bitmap == 0)) {
- dev_dbg(priv->adapter->dev, "Error: No event specified "
- "for bitwise action type\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Error: No event specified\t"
+ "for bitwise action type\n");
return -EINVAL;
}
@@ -1284,10 +1312,11 @@ mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv,
rssi_tlv->abs_value = subsc_evt_cfg->bcn_l_rssi_cfg.abs_value;
rssi_tlv->evt_freq = subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq;
- dev_dbg(priv->adapter->dev, "Cfg Beacon Low Rssi event, "
- "RSSI:-%d dBm, Freq:%d\n",
- subsc_evt_cfg->bcn_l_rssi_cfg.abs_value,
- subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq);
+ mwifiex_dbg(priv->adapter, EVENT,
+ "Cfg Beacon Low Rssi event,\t"
+ "RSSI:-%d dBm, Freq:%d\n",
+ subsc_evt_cfg->bcn_l_rssi_cfg.abs_value,
+ subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq);
pos += sizeof(struct mwifiex_ie_types_rssi_threshold);
le16_add_cpu(&cmd->size,
@@ -1304,10 +1333,11 @@ mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv,
rssi_tlv->abs_value = subsc_evt_cfg->bcn_h_rssi_cfg.abs_value;
rssi_tlv->evt_freq = subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq;
- dev_dbg(priv->adapter->dev, "Cfg Beacon High Rssi event, "
- "RSSI:-%d dBm, Freq:%d\n",
- subsc_evt_cfg->bcn_h_rssi_cfg.abs_value,
- subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq);
+ mwifiex_dbg(priv->adapter, EVENT,
+ "Cfg Beacon High Rssi event,\t"
+ "RSSI:-%d dBm, Freq:%d\n",
+ subsc_evt_cfg->bcn_h_rssi_cfg.abs_value,
+ subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq);
pos += sizeof(struct mwifiex_ie_types_rssi_threshold);
le16_add_cpu(&cmd->size,
@@ -1463,12 +1493,14 @@ static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv,
data, len);
if (ret)
return ret;
- dev_dbg(adapter->dev,
- "download cfg_data from device tree: %s\n", prop->name);
+ mwifiex_dbg(adapter, INFO,
+ "download cfg_data from device tree: %s\n",
+ prop->name);
} else if (adapter->cal_data->data && adapter->cal_data->size > 0) {
len = mwifiex_parse_cal_cfg((u8 *)adapter->cal_data->data,
adapter->cal_data->size, data);
- dev_dbg(adapter->dev, "download cfg_data from config file\n");
+ mwifiex_dbg(adapter, INFO,
+ "download cfg_data from config file\n");
} else {
return -1;
}
@@ -1583,9 +1615,9 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv,
tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_CONFIG);
if (!params) {
- dev_err(priv->adapter->dev,
- "TDLS config params not available for %pM\n",
- oper->peer_mac);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "TDLS config params not available for %pM\n",
+ oper->peer_mac);
return -ENODATA;
}
@@ -1663,7 +1695,7 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv,
break;
default:
- dev_err(priv->adapter->dev, "Unknown TDLS operation\n");
+ mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS operation\n");
return -ENOTSUPP;
}
@@ -1870,8 +1902,8 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action, data_buf);
break;
case HostCmd_CMD_WMM_GET_STATUS:
- dev_dbg(priv->adapter->dev,
- "cmd: WMM: WMM_GET_STATUS cmd sent\n");
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: WMM: WMM_GET_STATUS cmd sent\n");
cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
cmd_ptr->size =
cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) +
@@ -1885,6 +1917,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
case HostCmd_CMD_802_11_SCAN_EXT:
ret = mwifiex_cmd_802_11_scan_ext(priv, cmd_ptr, data_buf);
break;
+ case HostCmd_CMD_MEM_ACCESS:
+ ret = mwifiex_cmd_mem_access(cmd_ptr, cmd_action, data_buf);
+ break;
case HostCmd_CMD_MAC_REG_ACCESS:
case HostCmd_CMD_BBP_REG_ACCESS:
case HostCmd_CMD_RF_REG_ACCESS:
@@ -1932,8 +1967,8 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
data_buf);
break;
default:
- dev_err(priv->adapter->dev,
- "PREP_CMD: unknown cmd- %#x\n", cmd_no);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "PREP_CMD: unknown cmd- %#x\n", cmd_no);
ret = -1;
break;
}
@@ -2024,8 +2059,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
&sdio_sp_rx_aggr_enable,
true);
if (ret) {
- dev_err(priv->adapter->dev,
- "error while enabling SP aggregation..disable it");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "error while enabling SP aggregation..disable it");
adapter->sdio_rx_aggr_enable = false;
}
}
@@ -2108,8 +2143,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
HostCmd_ACT_GEN_SET, DOT11D_I,
&state_11d, true);
if (ret)
- dev_err(priv->adapter->dev,
- "11D: failed to enable 11D\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "11D: failed to enable 11D\n");
}
/* Send cmd to FW to configure 11n specific configuration
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 88dc6b672ef4..b645884b3b97 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -49,8 +49,9 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
struct host_cmd_ds_802_11_ps_mode_enh *pm;
unsigned long flags;
- dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n",
- resp->command, resp->result);
+ mwifiex_dbg(adapter, ERROR,
+ "CMD_RESP: cmd %#x error, result=%#x\n",
+ resp->command, resp->result);
if (adapter->curr_cmd->wait_q_enabled)
adapter->cmd_wait_q.status = -1;
@@ -58,9 +59,9 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
switch (le16_to_cpu(resp->command)) {
case HostCmd_CMD_802_11_PS_MODE_ENH:
pm = &resp->params.psmode_enh;
- dev_err(adapter->dev,
- "PS_MODE_ENH cmd failed: result=0x%x action=0x%X\n",
- resp->result, le16_to_cpu(pm->action));
+ mwifiex_dbg(adapter, ERROR,
+ "PS_MODE_ENH cmd failed: result=0x%x action=0x%X\n",
+ resp->result, le16_to_cpu(pm->action));
/* We do not re-try enter-ps command in ad-hoc mode. */
if (le16_to_cpu(pm->action) == EN_AUTO_PS &&
(le16_to_cpu(pm->params.ps_bitmap) & BITMAP_STA_PS) &&
@@ -91,7 +92,8 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
break;
case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:
- dev_err(priv->adapter->dev, "SDIO RX single-port aggregation Not support\n");
+ mwifiex_dbg(adapter, MSG,
+ "SDIO RX single-port aggregation Not support\n");
break;
default:
@@ -187,29 +189,34 @@ static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv,
u16 query_type = le16_to_cpu(smib->query_type);
u32 ul_temp;
- dev_dbg(priv->adapter->dev, "info: SNMP_RESP: oid value = %#x,"
- " query_type = %#x, buf size = %#x\n",
- oid, query_type, le16_to_cpu(smib->buf_size));
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: SNMP_RESP: oid value = %#x,\t"
+ "query_type = %#x, buf size = %#x\n",
+ oid, query_type, le16_to_cpu(smib->buf_size));
if (query_type == HostCmd_ACT_GEN_GET) {
ul_temp = le16_to_cpu(*((__le16 *) (smib->value)));
if (data_buf)
*data_buf = ul_temp;
switch (oid) {
case FRAG_THRESH_I:
- dev_dbg(priv->adapter->dev,
- "info: SNMP_RESP: FragThsd =%u\n", ul_temp);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: SNMP_RESP: FragThsd =%u\n",
+ ul_temp);
break;
case RTS_THRESH_I:
- dev_dbg(priv->adapter->dev,
- "info: SNMP_RESP: RTSThsd =%u\n", ul_temp);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: SNMP_RESP: RTSThsd =%u\n",
+ ul_temp);
break;
case SHORT_RETRY_LIM_I:
- dev_dbg(priv->adapter->dev,
- "info: SNMP_RESP: TxRetryCount=%u\n", ul_temp);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: SNMP_RESP: TxRetryCount=%u\n",
+ ul_temp);
break;
case DTIM_PERIOD_I:
- dev_dbg(priv->adapter->dev,
- "info: SNMP_RESP: DTIM period=%u\n", ul_temp);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: SNMP_RESP: DTIM period=%u\n",
+ ul_temp);
default:
break;
}
@@ -426,14 +433,15 @@ static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv,
priv->tx_power_level = (u16) pg->power_min;
break;
default:
- dev_err(adapter->dev, "CMD_RESP: unknown cmd action %d\n",
- action);
+ mwifiex_dbg(adapter, ERROR,
+ "CMD_RESP: unknown cmd action %d\n",
+ action);
return 0;
}
- dev_dbg(adapter->dev,
- "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n",
- priv->tx_power_level, priv->max_tx_power_level,
- priv->min_tx_power_level);
+ mwifiex_dbg(adapter, INFO,
+ "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n",
+ priv->tx_power_level, priv->max_tx_power_level,
+ priv->min_tx_power_level);
return 0;
}
@@ -454,10 +462,10 @@ static int mwifiex_ret_rf_tx_power(struct mwifiex_private *priv,
priv->min_tx_power_level = txp->min_power;
}
- dev_dbg(priv->adapter->dev,
- "Current TxPower Level=%d, Max Power=%d, Min Power=%d\n",
- priv->tx_power_level, priv->max_tx_power_level,
- priv->min_tx_power_level);
+ mwifiex_dbg(priv->adapter, INFO,
+ "Current TxPower Level=%d, Max Power=%d, Min Power=%d\n",
+ priv->tx_power_level, priv->max_tx_power_level,
+ priv->min_tx_power_level);
return 0;
}
@@ -473,18 +481,18 @@ static int mwifiex_ret_rf_antenna(struct mwifiex_private *priv,
struct mwifiex_adapter *adapter = priv->adapter;
if (adapter->hw_dev_mcs_support == HT_STREAM_2X2)
- dev_dbg(adapter->dev,
- "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x"
- " Rx action = 0x%x, Rx Mode = 0x%04x\n",
- le16_to_cpu(ant_mimo->action_tx),
- le16_to_cpu(ant_mimo->tx_ant_mode),
- le16_to_cpu(ant_mimo->action_rx),
- le16_to_cpu(ant_mimo->rx_ant_mode));
+ mwifiex_dbg(adapter, INFO,
+ "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x\t"
+ "Rx action = 0x%x, Rx Mode = 0x%04x\n",
+ le16_to_cpu(ant_mimo->action_tx),
+ le16_to_cpu(ant_mimo->tx_ant_mode),
+ le16_to_cpu(ant_mimo->action_rx),
+ le16_to_cpu(ant_mimo->rx_ant_mode));
else
- dev_dbg(adapter->dev,
- "RF_ANT_RESP: action = 0x%x, Mode = 0x%04x\n",
- le16_to_cpu(ant_siso->action),
- le16_to_cpu(ant_siso->ant_mode));
+ mwifiex_dbg(adapter, INFO,
+ "RF_ANT_RESP: action = 0x%x, Mode = 0x%04x\n",
+ le16_to_cpu(ant_siso->action),
+ le16_to_cpu(ant_siso->ant_mode));
return 0;
}
@@ -502,8 +510,8 @@ static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv,
memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN);
- dev_dbg(priv->adapter->dev,
- "info: set mac address: %pM\n", priv->curr_addr);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: set mac address: %pM\n", priv->curr_addr);
return 0;
}
@@ -587,7 +595,8 @@ static int mwifiex_ret_802_11_key_material_v1(struct mwifiex_private *priv,
if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) {
if ((le16_to_cpu(key->key_param_set.key_info) & KEY_MCAST)) {
- dev_dbg(priv->adapter->dev, "info: key: GTK is set\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: key: GTK is set\n");
priv->wpa_is_gtk_set = true;
priv->scan_block = false;
}
@@ -617,7 +626,7 @@ static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv,
key_v2 = &resp->params.key_material_v2;
if (le16_to_cpu(key_v2->action) == HostCmd_ACT_GEN_SET) {
if ((le16_to_cpu(key_v2->key_param_set.key_info) & KEY_MCAST)) {
- dev_dbg(priv->adapter->dev, "info: key: GTK is set\n");
+ mwifiex_dbg(priv->adapter, INFO, "info: key: GTK is set\n");
priv->wpa_is_gtk_set = true;
priv->scan_block = false;
}
@@ -663,14 +672,14 @@ static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv,
- IEEE80211_COUNTRY_STRING_LEN)
/ sizeof(struct ieee80211_country_ie_triplet));
- dev_dbg(priv->adapter->dev,
- "info: 11D Domain Info Resp: no_of_triplet=%d\n",
- no_of_triplet);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: 11D Domain Info Resp: no_of_triplet=%d\n",
+ no_of_triplet);
if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) {
- dev_warn(priv->adapter->dev,
- "11D: invalid number of triplets %d returned\n",
- no_of_triplet);
+ mwifiex_dbg(priv->adapter, FATAL,
+ "11D: invalid number of triplets %d returned\n",
+ no_of_triplet);
return -1;
}
@@ -680,8 +689,8 @@ static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv,
case HostCmd_ACT_GEN_GET:
break;
default:
- dev_err(priv->adapter->dev,
- "11D: invalid action:%d\n", domain_info->action);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "11D: invalid action:%d\n", domain_info->action);
return -1;
}
@@ -741,6 +750,19 @@ mwifiex_ret_p2p_mode_cfg(struct mwifiex_private *priv,
return 0;
}
+/* This function handles the command response of mem_access command
+ */
+static int
+mwifiex_ret_mem_access(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp, void *pioctl_buf)
+{
+ struct host_cmd_ds_mem_access *mem = (void *)&resp->params.mem;
+
+ priv->mem_rw.addr = le32_to_cpu(mem->addr);
+ priv->mem_rw.value = le32_to_cpu(mem->value);
+
+ return 0;
+}
/*
* This function handles the command response of register access.
*
@@ -830,12 +852,12 @@ static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv,
if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET)
return 0;
- dev_dbg(priv->adapter->dev,
- "info: new BSSID %pM\n", ibss_coal_resp->bssid);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: new BSSID %pM\n", ibss_coal_resp->bssid);
/* If rsp has NULL BSSID, Just return..... No Action */
if (is_zero_ether_addr(ibss_coal_resp->bssid)) {
- dev_warn(priv->adapter->dev, "new BSSID is NULL\n");
+ mwifiex_dbg(priv->adapter, FATAL, "new BSSID is NULL\n");
return 0;
}
@@ -871,48 +893,48 @@ static int mwifiex_ret_tdls_oper(struct mwifiex_private *priv,
case ACT_TDLS_DELETE:
if (reason) {
if (!node || reason == TDLS_ERR_LINK_NONEXISTENT)
- dev_dbg(priv->adapter->dev,
- "TDLS link delete for %pM failed: reason %d\n",
- cmd_tdls_oper->peer_mac, reason);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "TDLS link delete for %pM failed: reason %d\n",
+ cmd_tdls_oper->peer_mac, reason);
else
- dev_err(priv->adapter->dev,
- "TDLS link delete for %pM failed: reason %d\n",
- cmd_tdls_oper->peer_mac, reason);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "TDLS link delete for %pM failed: reason %d\n",
+ cmd_tdls_oper->peer_mac, reason);
} else {
- dev_dbg(priv->adapter->dev,
- "TDLS link delete for %pM successful\n",
- cmd_tdls_oper->peer_mac);
+ mwifiex_dbg(priv->adapter, MSG,
+ "TDLS link delete for %pM successful\n",
+ cmd_tdls_oper->peer_mac);
}
break;
case ACT_TDLS_CREATE:
if (reason) {
- dev_err(priv->adapter->dev,
- "TDLS link creation for %pM failed: reason %d",
- cmd_tdls_oper->peer_mac, reason);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "TDLS link creation for %pM failed: reason %d",
+ cmd_tdls_oper->peer_mac, reason);
if (node && reason != TDLS_ERR_LINK_EXISTS)
node->tdls_status = TDLS_SETUP_FAILURE;
} else {
- dev_dbg(priv->adapter->dev,
- "TDLS link creation for %pM successful",
- cmd_tdls_oper->peer_mac);
+ mwifiex_dbg(priv->adapter, MSG,
+ "TDLS link creation for %pM successful",
+ cmd_tdls_oper->peer_mac);
}
break;
case ACT_TDLS_CONFIG:
if (reason) {
- dev_err(priv->adapter->dev,
- "TDLS link config for %pM failed, reason %d\n",
- cmd_tdls_oper->peer_mac, reason);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "TDLS link config for %pM failed, reason %d\n",
+ cmd_tdls_oper->peer_mac, reason);
if (node)
node->tdls_status = TDLS_SETUP_FAILURE;
} else {
- dev_dbg(priv->adapter->dev,
- "TDLS link config for %pM successful\n",
- cmd_tdls_oper->peer_mac);
+ mwifiex_dbg(priv->adapter, MSG,
+ "TDLS link config for %pM successful\n",
+ cmd_tdls_oper->peer_mac);
}
break;
default:
- dev_err(priv->adapter->dev,
- "Unknown TDLS command action response %d", action);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Unknown TDLS command action response %d", action);
return -1;
}
@@ -929,8 +951,30 @@ static int mwifiex_ret_subsc_evt(struct mwifiex_private *priv,
/* For every subscribe event command (Get/Set/Clear), FW reports the
* current set of subscribed events*/
- dev_dbg(priv->adapter->dev, "Bitmap of currently subscribed events: %16x\n",
- le16_to_cpu(cmd_sub_event->events));
+ mwifiex_dbg(priv->adapter, EVENT,
+ "Bitmap of currently subscribed events: %16x\n",
+ le16_to_cpu(cmd_sub_event->events));
+
+ return 0;
+}
+
+static int mwifiex_ret_uap_sta_list(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ struct host_cmd_ds_sta_list *sta_list =
+ &resp->params.sta_list;
+ struct mwifiex_ie_types_sta_info *sta_info = (void *)&sta_list->tlv;
+ int i;
+ struct mwifiex_sta_node *sta_node;
+
+ for (i = 0; i < sta_list->sta_count; i++) {
+ sta_node = mwifiex_get_sta_entry(priv, sta_info->mac);
+ if (unlikely(!sta_node))
+ continue;
+
+ sta_node->stats.rssi = sta_info->rssi;
+ sta_info++;
+ }
return 0;
}
@@ -940,7 +984,7 @@ static int mwifiex_ret_cfg_data(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp)
{
if (resp->result != HostCmd_RESULT_OK) {
- dev_err(priv->adapter->dev, "Cal data cmd resp failed\n");
+ mwifiex_dbg(priv->adapter, ERROR, "Cal data cmd resp failed\n");
return -1;
}
@@ -1008,8 +1052,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
break;
case HostCmd_CMD_802_11_BG_SCAN_QUERY:
ret = mwifiex_ret_802_11_scan(priv, resp);
- dev_dbg(adapter->dev,
- "info: CMD_RESP: BG_SCAN result is ready!\n");
+ mwifiex_dbg(adapter, CMD,
+ "info: CMD_RESP: BG_SCAN result is ready!\n");
break;
case HostCmd_CMD_TXPWR_CFG:
ret = mwifiex_ret_tx_power_cfg(priv, resp);
@@ -1088,8 +1132,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
/ MWIFIEX_SDIO_BLOCK_SIZE)
* MWIFIEX_SDIO_BLOCK_SIZE;
adapter->curr_tx_buf_size = adapter->tx_buf_size;
- dev_dbg(adapter->dev, "cmd: curr_tx_buf_size=%d\n",
- adapter->curr_tx_buf_size);
+ mwifiex_dbg(adapter, CMD, "cmd: curr_tx_buf_size=%d\n",
+ adapter->curr_tx_buf_size);
if (adapter->if_ops.update_mp_end_port)
adapter->if_ops.update_mp_end_port(adapter,
@@ -1103,6 +1147,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
ret = mwifiex_ret_ibss_coalescing_status(priv, resp);
break;
+ case HostCmd_CMD_MEM_ACCESS:
+ ret = mwifiex_ret_mem_access(priv, resp, data_buf);
+ break;
case HostCmd_CMD_MAC_REG_ACCESS:
case HostCmd_CMD_BBP_REG_ACCESS:
case HostCmd_CMD_RF_REG_ACCESS:
@@ -1122,6 +1169,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
break;
case HostCmd_CMD_UAP_SYS_CONFIG:
break;
+ case HOST_CMD_APCMD_STA_LIST:
+ ret = mwifiex_ret_uap_sta_list(priv, resp);
+ break;
case HostCmd_CMD_UAP_BSS_START:
adapter->tx_lock_flag = false;
adapter->pps_uapsd_mode = false;
@@ -1133,6 +1183,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
break;
case HostCmd_CMD_UAP_STA_DEAUTH:
break;
+ case HOST_CMD_APCMD_SYS_RESET:
+ break;
case HostCmd_CMD_MEF_CFG:
break;
case HostCmd_CMD_COALESCE_CFG:
@@ -1146,8 +1198,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
ret = mwifiex_ret_sdio_rx_aggr_cfg(priv, resp);
break;
default:
- dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
- resp->command);
+ mwifiex_dbg(adapter, ERROR,
+ "CMD_RESP: unknown cmd response %#x\n",
+ resp->command);
break;
}
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index 0dc7a1d3993d..848de2621958 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -48,7 +48,8 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
if (!priv->media_connected)
return;
- dev_dbg(adapter->dev, "info: handles disconnect event\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: handles disconnect event\n");
priv->media_connected = false;
@@ -104,12 +105,14 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
* it could be used for re-assoc
*/
- dev_dbg(adapter->dev, "info: previous SSID=%s, SSID len=%u\n",
- priv->prev_ssid.ssid, priv->prev_ssid.ssid_len);
+ mwifiex_dbg(adapter, INFO,
+ "info: previous SSID=%s, SSID len=%u\n",
+ priv->prev_ssid.ssid, priv->prev_ssid.ssid_len);
- dev_dbg(adapter->dev, "info: current SSID=%s, SSID len=%u\n",
- priv->curr_bss_params.bss_descriptor.ssid.ssid,
- priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
+ mwifiex_dbg(adapter, INFO,
+ "info: current SSID=%s, SSID len=%u\n",
+ priv->curr_bss_params.bss_descriptor.ssid.ssid,
+ priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
memcpy(&priv->prev_ssid,
&priv->curr_bss_params.bss_descriptor.ssid,
@@ -127,13 +130,13 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
if (adapter->is_cmd_timedout && adapter->curr_cmd)
return;
priv->media_connected = false;
- dev_dbg(adapter->dev,
- "info: successfully disconnected from %pM: reason code %d\n",
- priv->cfg_bssid, reason_code);
+ mwifiex_dbg(adapter, MSG,
+ "info: successfully disconnected from %pM: reason code %d\n",
+ priv->cfg_bssid, reason_code);
if (priv->bss_mode == NL80211_IFTYPE_STATION ||
priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
cfg80211_disconnected(priv->netdev, reason_code, NULL, 0,
- GFP_KERNEL);
+ false, GFP_KERNEL);
}
eth_zero_addr(priv->cfg_bssid);
@@ -154,13 +157,13 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv,
/* reserved 2 bytes are not mandatory in tdls event */
if (event_skb->len < (sizeof(struct mwifiex_tdls_generic_event) -
sizeof(u16) - sizeof(adapter->event_cause))) {
- dev_err(adapter->dev, "Invalid event length!\n");
+ mwifiex_dbg(adapter, ERROR, "Invalid event length!\n");
return -1;
}
sta_ptr = mwifiex_get_sta_entry(priv, tdls_evt->peer_mac);
if (!sta_ptr) {
- dev_err(adapter->dev, "cannot get sta entry!\n");
+ mwifiex_dbg(adapter, ERROR, "cannot get sta entry!\n");
return -1;
}
@@ -180,6 +183,63 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv,
}
/*
+* This function handles coex events generated by firmware
+*/
+void mwifiex_bt_coex_wlan_param_update_event(struct mwifiex_private *priv,
+ struct sk_buff *event_skb)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_ie_types_header *tlv;
+ struct mwifiex_ie_types_btcoex_aggr_win_size *winsizetlv;
+ struct mwifiex_ie_types_btcoex_scan_time *scantlv;
+ s32 len = event_skb->len - sizeof(u32);
+ u8 *cur_ptr = event_skb->data + sizeof(u32);
+ u16 tlv_type, tlv_len;
+
+ while (len >= sizeof(struct mwifiex_ie_types_header)) {
+ tlv = (struct mwifiex_ie_types_header *)cur_ptr;
+ tlv_len = le16_to_cpu(tlv->len);
+ tlv_type = le16_to_cpu(tlv->type);
+
+ if ((tlv_len + sizeof(struct mwifiex_ie_types_header)) > len)
+ break;
+ switch (tlv_type) {
+ case TLV_BTCOEX_WL_AGGR_WINSIZE:
+ winsizetlv =
+ (struct mwifiex_ie_types_btcoex_aggr_win_size *)tlv;
+ adapter->coex_win_size = winsizetlv->coex_win_size;
+ adapter->coex_tx_win_size =
+ winsizetlv->tx_win_size;
+ adapter->coex_rx_win_size =
+ winsizetlv->rx_win_size;
+ mwifiex_coex_ampdu_rxwinsize(adapter);
+ mwifiex_update_ampdu_txwinsize(adapter);
+ break;
+
+ case TLV_BTCOEX_WL_SCANTIME:
+ scantlv =
+ (struct mwifiex_ie_types_btcoex_scan_time *)tlv;
+ adapter->coex_scan = scantlv->coex_scan;
+ adapter->coex_min_scan_time = scantlv->min_scan_time;
+ adapter->coex_max_scan_time = scantlv->max_scan_time;
+ break;
+
+ default:
+ break;
+ }
+
+ len -= tlv_len + sizeof(struct mwifiex_ie_types_header);
+ cur_ptr += tlv_len +
+ sizeof(struct mwifiex_ie_types_header);
+ }
+
+ dev_dbg(adapter->dev, "coex_scan=%d min_scan=%d coex_win=%d, tx_win=%d rx_win=%d\n",
+ adapter->coex_scan, adapter->coex_min_scan_time,
+ adapter->coex_win_size, adapter->coex_tx_win_size,
+ adapter->coex_rx_win_size);
+}
+
+/*
* This function handles events generated by firmware.
*
* This is a generic function and handles all events.
@@ -239,21 +299,21 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
switch (eventcause) {
case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
- dev_err(adapter->dev,
- "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL, ignore it\n");
+ mwifiex_dbg(adapter, ERROR,
+ "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL, ignore it\n");
break;
case EVENT_LINK_SENSED:
- dev_dbg(adapter->dev, "event: LINK_SENSED\n");
+ mwifiex_dbg(adapter, EVENT, "event: LINK_SENSED\n");
if (!netif_carrier_ok(priv->netdev))
netif_carrier_on(priv->netdev);
mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
break;
case EVENT_DEAUTHENTICATED:
- dev_dbg(adapter->dev, "event: Deauthenticated\n");
+ mwifiex_dbg(adapter, EVENT, "event: Deauthenticated\n");
if (priv->wps.session_enable) {
- dev_dbg(adapter->dev,
- "info: receive deauth event in wps session\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: receive deauth event in wps session\n");
break;
}
adapter->dbg.num_event_deauth++;
@@ -265,10 +325,10 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_DISASSOCIATED:
- dev_dbg(adapter->dev, "event: Disassociated\n");
+ mwifiex_dbg(adapter, EVENT, "event: Disassociated\n");
if (priv->wps.session_enable) {
- dev_dbg(adapter->dev,
- "info: receive disassoc event in wps session\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: receive disassoc event in wps session\n");
break;
}
adapter->dbg.num_event_disassoc++;
@@ -280,7 +340,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_LINK_LOST:
- dev_dbg(adapter->dev, "event: Link lost\n");
+ mwifiex_dbg(adapter, EVENT, "event: Link lost\n");
adapter->dbg.num_event_link_lost++;
if (priv->media_connected) {
reason_code =
@@ -290,7 +350,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_PS_SLEEP:
- dev_dbg(adapter->dev, "info: EVENT: SLEEP\n");
+ mwifiex_dbg(adapter, EVENT, "info: EVENT: SLEEP\n");
adapter->ps_state = PS_STATE_PRE_SLEEP;
@@ -298,12 +358,12 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_PS_AWAKE:
- dev_dbg(adapter->dev, "info: EVENT: AWAKE\n");
+ mwifiex_dbg(adapter, EVENT, "info: EVENT: AWAKE\n");
if (!adapter->pps_uapsd_mode &&
priv->media_connected && adapter->sleep_period.period) {
adapter->pps_uapsd_mode = true;
- dev_dbg(adapter->dev,
- "event: PPS/UAPSD mode activated\n");
+ mwifiex_dbg(adapter, EVENT,
+ "event: PPS/UAPSD mode activated\n");
}
adapter->tx_lock_flag = false;
if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
@@ -333,26 +393,26 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
case EVENT_DEEP_SLEEP_AWAKE:
adapter->if_ops.wakeup_complete(adapter);
- dev_dbg(adapter->dev, "event: DS_AWAKE\n");
+ mwifiex_dbg(adapter, EVENT, "event: DS_AWAKE\n");
if (adapter->is_deep_sleep)
adapter->is_deep_sleep = false;
break;
case EVENT_HS_ACT_REQ:
- dev_dbg(adapter->dev, "event: HS_ACT_REQ\n");
+ mwifiex_dbg(adapter, EVENT, "event: HS_ACT_REQ\n");
ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_HS_CFG_ENH,
0, 0, NULL, false);
break;
case EVENT_MIC_ERR_UNICAST:
- dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n");
+ mwifiex_dbg(adapter, EVENT, "event: UNICAST MIC ERROR\n");
cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid,
NL80211_KEYTYPE_PAIRWISE,
-1, NULL, GFP_KERNEL);
break;
case EVENT_MIC_ERR_MULTICAST:
- dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n");
+ mwifiex_dbg(adapter, EVENT, "event: MULTICAST MIC ERROR\n");
cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid,
NL80211_KEYTYPE_GROUP,
-1, NULL, GFP_KERNEL);
@@ -362,7 +422,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_ADHOC_BCN_LOST:
- dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n");
+ mwifiex_dbg(adapter, EVENT, "event: ADHOC_BCN_LOST\n");
priv->adhoc_is_link_sensed = false;
mwifiex_clean_txrx(priv);
mwifiex_stop_net_dev_queue(priv->netdev, adapter);
@@ -371,17 +431,17 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_BG_SCAN_REPORT:
- dev_dbg(adapter->dev, "event: BGS_REPORT\n");
+ mwifiex_dbg(adapter, EVENT, "event: BGS_REPORT\n");
ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_QUERY,
HostCmd_ACT_GEN_GET, 0, NULL, false);
break;
case EVENT_PORT_RELEASE:
- dev_dbg(adapter->dev, "event: PORT RELEASE\n");
+ mwifiex_dbg(adapter, EVENT, "event: PORT RELEASE\n");
break;
case EVENT_EXT_SCAN_REPORT:
- dev_dbg(adapter->dev, "event: EXT_SCAN Report\n");
+ mwifiex_dbg(adapter, EVENT, "event: EXT_SCAN Report\n");
if (adapter->ext_scan)
ret = mwifiex_handle_event_ext_scan_report(priv,
adapter->event_skb->data);
@@ -389,7 +449,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_WMM_STATUS_CHANGE:
- dev_dbg(adapter->dev, "event: WMM status changed\n");
+ mwifiex_dbg(adapter, EVENT, "event: WMM status changed\n");
ret = mwifiex_send_cmd(priv, HostCmd_CMD_WMM_GET_STATUS,
0, 0, NULL, false);
break;
@@ -401,13 +461,13 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
HostCmd_ACT_GEN_GET, 0, NULL, false);
priv->subsc_evt_rssi_state = RSSI_LOW_RECVD;
- dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n");
+ mwifiex_dbg(adapter, EVENT, "event: Beacon RSSI_LOW\n");
break;
case EVENT_SNR_LOW:
- dev_dbg(adapter->dev, "event: Beacon SNR_LOW\n");
+ mwifiex_dbg(adapter, EVENT, "event: Beacon SNR_LOW\n");
break;
case EVENT_MAX_FAIL:
- dev_dbg(adapter->dev, "event: MAX_FAIL\n");
+ mwifiex_dbg(adapter, EVENT, "event: MAX_FAIL\n");
break;
case EVENT_RSSI_HIGH:
cfg80211_cqm_rssi_notify(priv->netdev,
@@ -416,47 +476,47 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
HostCmd_ACT_GEN_GET, 0, NULL, false);
priv->subsc_evt_rssi_state = RSSI_HIGH_RECVD;
- dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n");
+ mwifiex_dbg(adapter, EVENT, "event: Beacon RSSI_HIGH\n");
break;
case EVENT_SNR_HIGH:
- dev_dbg(adapter->dev, "event: Beacon SNR_HIGH\n");
+ mwifiex_dbg(adapter, EVENT, "event: Beacon SNR_HIGH\n");
break;
case EVENT_DATA_RSSI_LOW:
- dev_dbg(adapter->dev, "event: Data RSSI_LOW\n");
+ mwifiex_dbg(adapter, EVENT, "event: Data RSSI_LOW\n");
break;
case EVENT_DATA_SNR_LOW:
- dev_dbg(adapter->dev, "event: Data SNR_LOW\n");
+ mwifiex_dbg(adapter, EVENT, "event: Data SNR_LOW\n");
break;
case EVENT_DATA_RSSI_HIGH:
- dev_dbg(adapter->dev, "event: Data RSSI_HIGH\n");
+ mwifiex_dbg(adapter, EVENT, "event: Data RSSI_HIGH\n");
break;
case EVENT_DATA_SNR_HIGH:
- dev_dbg(adapter->dev, "event: Data SNR_HIGH\n");
+ mwifiex_dbg(adapter, EVENT, "event: Data SNR_HIGH\n");
break;
case EVENT_LINK_QUALITY:
- dev_dbg(adapter->dev, "event: Link Quality\n");
+ mwifiex_dbg(adapter, EVENT, "event: Link Quality\n");
break;
case EVENT_PRE_BEACON_LOST:
- dev_dbg(adapter->dev, "event: Pre-Beacon Lost\n");
+ mwifiex_dbg(adapter, EVENT, "event: Pre-Beacon Lost\n");
break;
case EVENT_IBSS_COALESCED:
- dev_dbg(adapter->dev, "event: IBSS_COALESCED\n");
+ mwifiex_dbg(adapter, EVENT, "event: IBSS_COALESCED\n");
ret = mwifiex_send_cmd(priv,
HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
HostCmd_ACT_GEN_GET, 0, NULL, false);
break;
case EVENT_ADDBA:
- dev_dbg(adapter->dev, "event: ADDBA Request\n");
+ mwifiex_dbg(adapter, EVENT, "event: ADDBA Request\n");
mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP,
HostCmd_ACT_GEN_SET, 0,
adapter->event_body, false);
break;
case EVENT_DELBA:
- dev_dbg(adapter->dev, "event: DELBA Request\n");
+ mwifiex_dbg(adapter, EVENT, "event: DELBA Request\n");
mwifiex_11n_delete_ba_stream(priv, adapter->event_body);
break;
case EVENT_BA_STREAM_TIEMOUT:
- dev_dbg(adapter->dev, "event: BA Stream timeout\n");
+ mwifiex_dbg(adapter, EVENT, "event: BA Stream timeout\n");
mwifiex_11n_ba_stream_timeout(priv,
(struct host_cmd_ds_11n_batimeout
*)
@@ -464,28 +524,31 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_AMSDU_AGGR_CTRL:
ctrl = le16_to_cpu(*(__le16 *)adapter->event_body);
- dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", ctrl);
+ mwifiex_dbg(adapter, EVENT,
+ "event: AMSDU_AGGR_CTRL %d\n", ctrl);
adapter->tx_buf_size =
min_t(u16, adapter->curr_tx_buf_size, ctrl);
- dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
- adapter->tx_buf_size);
+ mwifiex_dbg(adapter, EVENT, "event: tx_buf_size %d\n",
+ adapter->tx_buf_size);
break;
case EVENT_WEP_ICV_ERR:
- dev_dbg(adapter->dev, "event: WEP ICV error\n");
+ mwifiex_dbg(adapter, EVENT, "event: WEP ICV error\n");
break;
case EVENT_BW_CHANGE:
- dev_dbg(adapter->dev, "event: BW Change\n");
+ mwifiex_dbg(adapter, EVENT, "event: BW Change\n");
break;
case EVENT_HOSTWAKE_STAIE:
- dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause);
+ mwifiex_dbg(adapter, EVENT,
+ "event: HOSTWAKE_STAIE %d\n", eventcause);
break;
case EVENT_REMAIN_ON_CHAN_EXPIRED:
- dev_dbg(adapter->dev, "event: Remain on channel expired\n");
+ mwifiex_dbg(adapter, EVENT,
+ "event: Remain on channel expired\n");
cfg80211_remain_on_channel_expired(&priv->wdev,
priv->roc_cfg.cookie,
&priv->roc_cfg.chan,
@@ -496,7 +559,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_CHANNEL_SWITCH_ANN:
- dev_dbg(adapter->dev, "event: Channel Switch Announcement\n");
+ mwifiex_dbg(adapter, EVENT, "event: Channel Switch Announcement\n");
priv->csa_expire_time =
jiffies + msecs_to_jiffies(DFS_CHAN_MOVE_TIME);
priv->csa_chan = priv->curr_bss_params.bss_descriptor.channel;
@@ -511,23 +574,28 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_TX_STATUS_REPORT:
- dev_dbg(adapter->dev, "event: TX_STATUS Report\n");
+ mwifiex_dbg(adapter, EVENT, "event: TX_STATUS Report\n");
mwifiex_parse_tx_status_event(priv, adapter->event_body);
break;
case EVENT_CHANNEL_REPORT_RDY:
- dev_dbg(adapter->dev, "event: Channel Report\n");
+ mwifiex_dbg(adapter, EVENT, "event: Channel Report\n");
ret = mwifiex_11h_handle_chanrpt_ready(priv,
adapter->event_skb);
break;
case EVENT_RADAR_DETECTED:
- dev_dbg(adapter->dev, "event: Radar detected\n");
+ mwifiex_dbg(adapter, EVENT, "event: Radar detected\n");
ret = mwifiex_11h_handle_radar_detected(priv,
adapter->event_skb);
break;
+ case EVENT_BT_COEX_WLAN_PARA_CHANGE:
+ dev_dbg(adapter->dev, "EVENT: BT coex wlan param update\n");
+ mwifiex_bt_coex_wlan_param_update_event(priv,
+ adapter->event_skb);
+ break;
default:
- dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
- eventcause);
+ mwifiex_dbg(adapter, ERROR, "event: unknown event id: %#x\n",
+ eventcause);
break;
}
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 0599e41e253c..d8b7d9c20450 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -64,7 +64,10 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
*(cmd_queued->condition),
(12 * HZ));
if (status <= 0) {
- dev_err(adapter->dev, "cmd_wait_q terminated: %d\n", status);
+ if (status == 0)
+ status = -ETIMEDOUT;
+ mwifiex_dbg(adapter, ERROR,
+ "cmd_wait_q terminated: %d\n", status);
mwifiex_cancel_all_pending_cmd(adapter);
return status;
}
@@ -91,7 +94,8 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
old_pkt_filter = priv->curr_pkt_filter;
if (mcast_list->mode == MWIFIEX_PROMISC_MODE) {
- dev_dbg(priv->adapter->dev, "info: Enable Promiscuous mode\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: Enable Promiscuous mode\n");
priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
priv->curr_pkt_filter &=
~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
@@ -99,16 +103,16 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
/* Multicast */
priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
if (mcast_list->mode == MWIFIEX_ALL_MULTI_MODE) {
- dev_dbg(priv->adapter->dev,
- "info: Enabling All Multicast!\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: Enabling All Multicast!\n");
priv->curr_pkt_filter |=
HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
} else {
priv->curr_pkt_filter &=
~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
- dev_dbg(priv->adapter->dev,
- "info: Set multicast list=%d\n",
- mcast_list->num_multicast_addr);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: Set multicast list=%d\n",
+ mcast_list->num_multicast_addr);
/* Send multicast addresses to firmware */
ret = mwifiex_send_cmd(priv,
HostCmd_CMD_MAC_MULTICAST_ADR,
@@ -116,9 +120,9 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
mcast_list, false);
}
}
- dev_dbg(priv->adapter->dev,
- "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",
- old_pkt_filter, priv->curr_pkt_filter);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",
+ old_pkt_filter, priv->curr_pkt_filter);
if (old_pkt_filter != priv->curr_pkt_filter) {
ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
HostCmd_ACT_GEN_SET,
@@ -151,7 +155,8 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
rcu_read_unlock();
if (!beacon_ie) {
- dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ " failed to alloc beacon_ie\n");
return -ENOMEM;
}
@@ -165,7 +170,8 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
bss_desc->bss_band = bss_priv->band;
bss_desc->fw_tsf = bss_priv->fw_tsf;
if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
- dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: InterpretIE: AP WEP enabled\n");
bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
} else {
bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
@@ -219,8 +225,8 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv,
if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) {
rcu_read_unlock();
- wiphy_dbg(priv->wdev.wiphy,
- "11D: skip setting domain info in FW\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "11D: skip setting domain info in FW\n");
return 0;
}
memcpy(priv->adapter->country_code, &country_ie[2], 2);
@@ -241,8 +247,8 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv,
if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
HostCmd_ACT_GEN_SET, 0, NULL, false)) {
- wiphy_err(priv->adapter->wiphy,
- "11D: setting domain info in FW\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "11D: setting domain info in FW fail\n");
return -1;
}
@@ -304,14 +310,15 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
if (mwifiex_11h_get_csa_closed_channel(priv) ==
(u8)bss_desc->channel) {
- dev_err(adapter->dev,
- "Attempt to reconnect on csa closed chan(%d)\n",
- bss_desc->channel);
+ mwifiex_dbg(adapter, ERROR,
+ "Attempt to reconnect on csa closed chan(%d)\n",
+ bss_desc->channel);
goto done;
}
- dev_dbg(adapter->dev, "info: SSID found in scan list ... "
- "associating...\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: SSID found in scan list ...\t"
+ "associating...\n");
mwifiex_stop_net_dev_queue(priv->netdev, adapter);
if (netif_carrier_ok(priv->netdev))
@@ -353,15 +360,17 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
netif_carrier_off(priv->netdev);
if (!ret) {
- dev_dbg(adapter->dev, "info: network found in scan"
- " list. Joining...\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: network found in scan\t"
+ " list. Joining...\n");
ret = mwifiex_adhoc_join(priv, bss_desc);
if (bss)
cfg80211_put_bss(priv->adapter->wiphy, bss);
} else {
- dev_dbg(adapter->dev, "info: Network not found in "
- "the list, creating adhoc with ssid = %s\n",
- req_ssid->ssid);
+ mwifiex_dbg(adapter, INFO,
+ "info: Network not found in\t"
+ "the list, creating adhoc with ssid = %s\n",
+ req_ssid->ssid);
ret = mwifiex_adhoc_start(priv, req_ssid);
}
}
@@ -396,8 +405,9 @@ int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
switch (action) {
case HostCmd_ACT_GEN_SET:
if (adapter->pps_uapsd_mode) {
- dev_dbg(adapter->dev, "info: Host Sleep IOCTL"
- " is blocked in UAPSD/PPS mode\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: Host Sleep IOCTL\t"
+ "is blocked in UAPSD/PPS mode\n");
status = -1;
break;
}
@@ -494,7 +504,8 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
}
if (adapter->hs_activated) {
- dev_dbg(adapter->dev, "cmd: HS Already activated\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: HS Already activated\n");
return true;
}
@@ -510,14 +521,16 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
MWIFIEX_BSS_ROLE_STA),
HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD,
&hscfg)) {
- dev_err(adapter->dev, "IOCTL request HS enable failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "IOCTL request HS enable failed\n");
return false;
}
if (wait_event_interruptible_timeout(adapter->hs_activate_wait_q,
adapter->hs_activate_wait_q_woken,
(10 * HZ)) <= 0) {
- dev_err(adapter->dev, "hs_activate_wait_q terminated\n");
+ mwifiex_dbg(adapter, ERROR,
+ "hs_activate_wait_q terminated\n");
return false;
}
@@ -637,10 +650,11 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv,
dbm = (u16) power_cfg->power_level;
if ((dbm < priv->min_tx_power_level) ||
(dbm > priv->max_tx_power_level)) {
- dev_err(priv->adapter->dev, "txpower value %d dBm"
- " is out of range (%d dBm-%d dBm)\n",
- dbm, priv->min_tx_power_level,
- priv->max_tx_power_level);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "txpower value %d dBm\t"
+ "is out of range (%d dBm-%d dBm)\n",
+ dbm, priv->min_tx_power_level,
+ priv->max_tx_power_level);
return -1;
}
}
@@ -739,14 +753,15 @@ static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv,
{
if (ie_len) {
if (ie_len > sizeof(priv->wpa_ie)) {
- dev_err(priv->adapter->dev,
- "failed to copy WPA IE, too big\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "failed to copy WPA IE, too big\n");
return -1;
}
memcpy(priv->wpa_ie, ie_data_ptr, ie_len);
priv->wpa_ie_len = (u8) ie_len;
- dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n",
- priv->wpa_ie_len, priv->wpa_ie[0]);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: Set Wpa_ie_len=%d IE=%#x\n",
+ priv->wpa_ie_len, priv->wpa_ie[0]);
if (priv->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) {
priv->sec_info.wpa_enabled = true;
@@ -759,8 +774,9 @@ static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv,
} else {
memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie));
priv->wpa_ie_len = 0;
- dev_dbg(priv->adapter->dev, "info: reset wpa_ie_len=%d IE=%#x\n",
- priv->wpa_ie_len, priv->wpa_ie[0]);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: reset wpa_ie_len=%d IE=%#x\n",
+ priv->wpa_ie_len, priv->wpa_ie[0]);
priv->sec_info.wpa_enabled = false;
priv->sec_info.wpa2_enabled = false;
}
@@ -780,23 +796,24 @@ static int mwifiex_set_wapi_ie(struct mwifiex_private *priv,
{
if (ie_len) {
if (ie_len > sizeof(priv->wapi_ie)) {
- dev_dbg(priv->adapter->dev,
- "info: failed to copy WAPI IE, too big\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "info: failed to copy WAPI IE, too big\n");
return -1;
}
memcpy(priv->wapi_ie, ie_data_ptr, ie_len);
priv->wapi_ie_len = ie_len;
- dev_dbg(priv->adapter->dev, "cmd: Set wapi_ie_len=%d IE=%#x\n",
- priv->wapi_ie_len, priv->wapi_ie[0]);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: Set wapi_ie_len=%d IE=%#x\n",
+ priv->wapi_ie_len, priv->wapi_ie[0]);
if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY)
priv->sec_info.wapi_enabled = true;
} else {
memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie));
priv->wapi_ie_len = ie_len;
- dev_dbg(priv->adapter->dev,
- "info: Reset wapi_ie_len=%d IE=%#x\n",
- priv->wapi_ie_len, priv->wapi_ie[0]);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: Reset wapi_ie_len=%d IE=%#x\n",
+ priv->wapi_ie_len, priv->wapi_ie[0]);
priv->sec_info.wapi_enabled = false;
}
return 0;
@@ -814,8 +831,8 @@ static int mwifiex_set_wps_ie(struct mwifiex_private *priv,
{
if (ie_len) {
if (ie_len > MWIFIEX_MAX_VSIE_LEN) {
- dev_dbg(priv->adapter->dev,
- "info: failed to copy WPS IE, too big\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "info: failed to copy WPS IE, too big\n");
return -1;
}
@@ -825,13 +842,14 @@ static int mwifiex_set_wps_ie(struct mwifiex_private *priv,
memcpy(priv->wps_ie, ie_data_ptr, ie_len);
priv->wps_ie_len = ie_len;
- dev_dbg(priv->adapter->dev, "cmd: Set wps_ie_len=%d IE=%#x\n",
- priv->wps_ie_len, priv->wps_ie[0]);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: Set wps_ie_len=%d IE=%#x\n",
+ priv->wps_ie_len, priv->wps_ie[0]);
} else {
kfree(priv->wps_ie);
priv->wps_ie_len = ie_len;
- dev_dbg(priv->adapter->dev,
- "info: Reset wps_ie_len=%d\n", priv->wps_ie_len);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: Reset wps_ie_len=%d\n", priv->wps_ie_len);
}
return 0;
}
@@ -875,8 +893,8 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
/* Copy the required key as the current key */
wep_key = &priv->wep_key[index];
if (!wep_key->key_length) {
- dev_err(adapter->dev,
- "key not set, so cannot enable it\n");
+ mwifiex_dbg(adapter, ERROR,
+ "key not set, so cannot enable it\n");
return -1;
}
@@ -953,7 +971,8 @@ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv,
/* Current driver only supports key length of up to 32 bytes */
if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) {
- dev_err(priv->adapter->dev, "key length too long\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "key length too long\n");
return -1;
}
@@ -1040,7 +1059,7 @@ mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
snprintf(version, max_len, driver_version, fw_ver);
- dev_dbg(adapter->dev, "info: MWIFIEX VERSION: %s\n", version);
+ mwifiex_dbg(adapter, MSG, "info: MWIFIEX VERSION: %s\n", version);
return 0;
}
@@ -1128,7 +1147,8 @@ mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
}
if (mwifiex_send_cmd(priv, HostCmd_CMD_REMAIN_ON_CHAN,
action, 0, &roc_cfg, true)) {
- dev_err(priv->adapter->dev, "failed to remain on channel\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "failed to remain on channel\n");
return -1;
}
@@ -1313,8 +1333,8 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
if ((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) &&
(!memcmp(pvendor_ie->oui, wps_oui, sizeof(wps_oui)))) {
priv->wps.session_enable = true;
- dev_dbg(priv->adapter->dev,
- "info: WPS Session Enabled.\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: WPS Session Enabled.\n");
ret = mwifiex_set_wps_ie(priv, ie_data_ptr, ie_len);
}
@@ -1361,7 +1381,8 @@ static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,
memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter));
if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) {
adapter->arp_filter_size = 0;
- dev_err(adapter->dev, "invalid ARP filter size\n");
+ mwifiex_dbg(adapter, ERROR,
+ "invalid ARP filter size\n");
return -1;
} else {
memcpy(adapter->arp_filter, gen_ie->ie_data,
@@ -1370,7 +1391,7 @@ static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,
}
break;
default:
- dev_err(adapter->dev, "invalid IE type\n");
+ mwifiex_dbg(adapter, ERROR, "invalid IE type\n");
return -1;
}
return 0;
diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c
index b8729c9394e9..d4d4cb1ce95b 100644
--- a/drivers/net/wireless/mwifiex/sta_rx.c
+++ b/drivers/net/wireless/mwifiex/sta_rx.c
@@ -141,7 +141,7 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv,
if (priv->hs2_enabled &&
mwifiex_discard_gratuitous_arp(priv, skb)) {
- dev_dbg(priv->adapter->dev, "Bypassed Gratuitous ARP\n");
+ mwifiex_dbg(priv->adapter, INFO, "Bypassed Gratuitous ARP\n");
dev_kfree_skb_any(skb);
return 0;
}
@@ -166,7 +166,8 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv,
ret = mwifiex_recv_packet(priv, skb);
if (ret == -1)
- dev_err(priv->adapter->dev, "recv packet failed\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "recv packet failed\n");
return ret;
}
@@ -203,9 +204,9 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv,
rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_offset;
if ((rx_pkt_offset + rx_pkt_length) > (u16) skb->len) {
- dev_err(adapter->dev,
- "wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n",
- skb->len, rx_pkt_offset, rx_pkt_length);
+ mwifiex_dbg(adapter, ERROR,
+ "wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n",
+ skb->len, rx_pkt_offset, rx_pkt_length);
priv->stats.rx_dropped++;
dev_kfree_skb_any(skb);
return ret;
@@ -214,7 +215,7 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv,
if (rx_pkt_type == PKT_TYPE_MGMT) {
ret = mwifiex_process_mgmt_packet(priv, skb);
if (ret)
- dev_err(adapter->dev, "Rx of mgmt packet failed");
+ mwifiex_dbg(adapter, ERROR, "Rx of mgmt packet failed");
dev_kfree_skb_any(skb);
return ret;
}
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
index 5ce2d9a4f919..355ac5904fac 100644
--- a/drivers/net/wireless/mwifiex/sta_tx.c
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -53,7 +53,8 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
INTF_HEADER_LEN;
if (!skb->len) {
- dev_err(adapter->dev, "Tx: bad packet length: %d\n", skb->len);
+ mwifiex_dbg(adapter, ERROR,
+ "Tx: bad packet length: %d\n", skb->len);
tx_info->status_code = -1;
return skb->data;
}
@@ -184,21 +185,24 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
switch (ret) {
case -EBUSY:
dev_kfree_skb_any(skb);
- dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n",
- __func__, ret);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: host_to_card failed: ret=%d\n",
+ __func__, ret);
adapter->dbg.num_tx_host_to_card_failure++;
break;
case -1:
adapter->data_sent = false;
dev_kfree_skb_any(skb);
- dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n",
- __func__, ret);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: host_to_card failed: ret=%d\n",
+ __func__, ret);
adapter->dbg.num_tx_host_to_card_failure++;
break;
case 0:
dev_kfree_skb_any(skb);
- dev_dbg(adapter->dev, "data: %s: host_to_card succeeded\n",
- __func__);
+ mwifiex_dbg(adapter, DATA,
+ "data: %s: host_to_card succeeded\n",
+ __func__);
adapter->tx_lock_flag = true;
break;
case -EINPROGRESS:
diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c
index 087d84762cd3..2faa1bc42abe 100644
--- a/drivers/net/wireless/mwifiex/tdls.c
+++ b/drivers/net/wireless/mwifiex/tdls.c
@@ -37,7 +37,7 @@ static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv,
u32 tid;
u8 tid_down;
- dev_dbg(priv->adapter->dev, "%s: %pM\n", __func__, mac);
+ mwifiex_dbg(priv->adapter, DATA, "%s: %pM\n", __func__, mac);
spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) {
@@ -94,7 +94,7 @@ static void mwifiex_hold_tdls_packets(struct mwifiex_private *priv,
unsigned long flags;
int i;
- dev_dbg(priv->adapter->dev, "%s: %pM\n", __func__, mac);
+ mwifiex_dbg(priv->adapter, DATA, "%s: %pM\n", __func__, mac);
spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
for (i = 0; i < MAX_NUM_TID; i++) {
@@ -132,8 +132,8 @@ mwifiex_tdls_append_rates_ie(struct mwifiex_private *priv,
supp_rates_size = min_t(u16, rates_size, MWIFIEX_TDLS_SUPPORTED_RATES);
if (skb_tailroom(skb) < rates_size + 4) {
- dev_err(priv->adapter->dev,
- "Insuffient space while adding rates\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Insuffient space while adding rates\n");
return -ENOMEM;
}
@@ -199,8 +199,8 @@ mwifiex_tdls_add_ht_oper(struct mwifiex_private *priv, const u8 *mac,
sta_ptr = mwifiex_get_sta_entry(priv, mac);
if (unlikely(!sta_ptr)) {
- dev_warn(priv->adapter->dev,
- "TDLS peer station not found in list\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "TDLS peer station not found in list\n");
return -1;
}
@@ -247,15 +247,16 @@ static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv,
sta_ptr = mwifiex_get_sta_entry(priv, mac);
if (unlikely(!sta_ptr)) {
- dev_warn(adapter->dev, "TDLS peer station not found in list\n");
+ mwifiex_dbg(adapter, ERROR,
+ "TDLS peer station not found in list\n");
return -1;
}
if (!mwifiex_is_bss_in_11ac_mode(priv)) {
if (sta_ptr->tdls_cap.extcap.ext_capab[7] &
WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) {
- dev_dbg(adapter->dev,
- "TDLS peer doesn't support wider bandwitdh\n");
+ mwifiex_dbg(adapter, WARN,
+ "TDLS peer doesn't support wider bandwidth\n");
return 0;
}
} else {
@@ -554,7 +555,7 @@ static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv,
tf->u.discover_req.dialog_token = dialog_token;
break;
default:
- dev_err(priv->adapter->dev, "Unknown TDLS frame type.\n");
+ mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS frame type.\n");
return -EINVAL;
}
@@ -608,8 +609,8 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer,
skb = dev_alloc_skb(skb_len);
if (!skb) {
- dev_err(priv->adapter->dev,
- "allocate skb failed for management frame\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "allocate skb failed for management frame\n");
return -ENOMEM;
}
skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
@@ -742,7 +743,7 @@ mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv,
mwifiex_tdls_add_qos_capab(skb);
break;
default:
- dev_err(priv->adapter->dev, "Unknown TDLS action frame type\n");
+ mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS action frame type\n");
return -EINVAL;
}
@@ -781,8 +782,8 @@ int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer,
skb = dev_alloc_skb(skb_len);
if (!skb) {
- dev_err(priv->adapter->dev,
- "allocate skb failed for management frame\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "allocate skb failed for management frame\n");
return -ENOMEM;
}
@@ -848,8 +849,8 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
peer = buf + ETH_ALEN;
action = *(buf + sizeof(struct ethhdr) + 2);
- dev_dbg(priv->adapter->dev,
- "rx:tdls action: peer=%pM, action=%d\n", peer, action);
+ mwifiex_dbg(priv->adapter, DATA,
+ "rx:tdls action: peer=%pM, action=%d\n", peer, action);
switch (action) {
case WLAN_TDLS_SETUP_REQUEST:
@@ -880,7 +881,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
ie_len = len - sizeof(struct ethhdr) - TDLS_CONFIRM_FIX_LEN;
break;
default:
- dev_dbg(priv->adapter->dev, "Unknown TDLS frame type.\n");
+ mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS frame type.\n");
return;
}
@@ -967,8 +968,8 @@ mwifiex_tdls_process_config_link(struct mwifiex_private *priv, const u8 *peer)
sta_ptr = mwifiex_get_sta_entry(priv, peer);
if (!sta_ptr || sta_ptr->tdls_status == TDLS_SETUP_FAILURE) {
- dev_err(priv->adapter->dev,
- "link absent for peer %pM; cannot config\n", peer);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "link absent for peer %pM; cannot config\n", peer);
return -EINVAL;
}
@@ -988,8 +989,8 @@ mwifiex_tdls_process_create_link(struct mwifiex_private *priv, const u8 *peer)
sta_ptr = mwifiex_get_sta_entry(priv, peer);
if (sta_ptr && sta_ptr->tdls_status == TDLS_SETUP_INPROGRESS) {
- dev_dbg(priv->adapter->dev,
- "Setup already in progress for peer %pM\n", peer);
+ mwifiex_dbg(priv->adapter, WARN,
+ "Setup already in progress for peer %pM\n", peer);
return 0;
}
@@ -1046,8 +1047,8 @@ mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer)
sta_ptr = mwifiex_get_sta_entry(priv, peer);
if (sta_ptr && (sta_ptr->tdls_status != TDLS_SETUP_FAILURE)) {
- dev_dbg(priv->adapter->dev,
- "tdls: enable link %pM success\n", peer);
+ mwifiex_dbg(priv->adapter, MSG,
+ "tdls: enable link %pM success\n", peer);
sta_ptr->tdls_status = TDLS_SETUP_COMPLETE;
@@ -1076,8 +1077,8 @@ mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer)
mwifiex_auto_tdls_update_peer_status(priv, peer,
TDLS_SETUP_COMPLETE);
} else {
- dev_dbg(priv->adapter->dev,
- "tdls: enable link %pM failed\n", peer);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "tdls: enable link %pM failed\n", peer);
if (sta_ptr) {
mwifiex_11n_cleanup_reorder_tbl(priv);
spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
@@ -1180,9 +1181,9 @@ void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv)
tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;
if (mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
HostCmd_ACT_GEN_SET, 0, &tdls_oper, false))
- dev_warn(priv->adapter->dev,
- "Disable link failed for TDLS peer %pM",
- sta_ptr->mac_addr);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Disable link failed for TDLS peer %pM",
+ sta_ptr->mac_addr);
}
mwifiex_del_all_sta_list(priv);
@@ -1204,9 +1205,9 @@ int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb)
(peer->failure_count <
MWIFIEX_TDLS_MAX_FAIL_COUNT)) {
peer->tdls_status = TDLS_SETUP_INPROGRESS;
- dev_dbg(priv->adapter->dev,
- "setup TDLS link, peer=%pM rssi=%d\n",
- peer->mac_addr, peer->rssi);
+ mwifiex_dbg(priv->adapter, INFO,
+ "setup TDLS link, peer=%pM rssi=%d\n",
+ peer->mac_addr, peer->rssi);
cfg80211_tdls_oper_request(priv->netdev,
peer->mac_addr,
@@ -1272,8 +1273,8 @@ void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac)
tdls_peer->rssi_jiffies = jiffies;
INIT_LIST_HEAD(&tdls_peer->list);
list_add_tail(&tdls_peer->list, &priv->auto_tdls_list);
- dev_dbg(priv->adapter->dev, "Add auto TDLS peer= %pM to list\n",
- mac);
+ mwifiex_dbg(priv->adapter, INFO,
+ "Add auto TDLS peer= %pM to list\n", mac);
}
spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
@@ -1341,8 +1342,8 @@ void mwifiex_check_auto_tdls(unsigned long context)
return;
if (!priv->auto_tdls_timer_active) {
- dev_dbg(priv->adapter->dev,
- "auto TDLS timer inactive; return");
+ mwifiex_dbg(priv->adapter, INFO,
+ "auto TDLS timer inactive; return");
return;
}
@@ -1368,9 +1369,9 @@ void mwifiex_check_auto_tdls(unsigned long context)
!tdls_peer->rssi) &&
tdls_peer->tdls_status == TDLS_SETUP_COMPLETE) {
tdls_peer->tdls_status = TDLS_LINK_TEARDOWN;
- dev_dbg(priv->adapter->dev,
- "teardown TDLS link,peer=%pM rssi=%d\n",
- tdls_peer->mac_addr, -tdls_peer->rssi);
+ mwifiex_dbg(priv->adapter, MSG,
+ "teardown TDLS link,peer=%pM rssi=%d\n",
+ tdls_peer->mac_addr, -tdls_peer->rssi);
tdls_peer->do_discover = true;
priv->check_tdls_tx = true;
cfg80211_tdls_oper_request(priv->netdev,
@@ -1384,9 +1385,10 @@ void mwifiex_check_auto_tdls(unsigned long context)
MWIFIEX_TDLS_MAX_FAIL_COUNT) {
priv->check_tdls_tx = true;
tdls_peer->do_setup = true;
- dev_dbg(priv->adapter->dev,
- "check TDLS with peer=%pM rssi=%d\n",
- tdls_peer->mac_addr, -tdls_peer->rssi);
+ mwifiex_dbg(priv->adapter, INFO,
+ "check TDLS with peer=%pM\t"
+ "rssi=%d\n", tdls_peer->mac_addr,
+ tdls_peer->rssi);
}
}
spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index a245f444aeec..5ed9b794053e 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -50,11 +50,15 @@ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
if (!priv) {
- dev_err(adapter->dev, "data: priv not found. Drop RX packet\n");
+ mwifiex_dbg(adapter, ERROR,
+ "data: priv not found. Drop RX packet\n");
dev_kfree_skb_any(skb);
return -1;
}
+ mwifiex_dbg_dump(adapter, DAT_D, "rx pkt:", skb->data,
+ min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN));
+
memset(rx_info, 0, sizeof(*rx_info));
rx_info->bss_num = priv->bss_num;
rx_info->bss_type = priv->bss_type;
@@ -84,13 +88,22 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
struct mwifiex_adapter *adapter = priv->adapter;
u8 *head_ptr;
struct txpd *local_tx_pd = NULL;
+ struct mwifiex_sta_node *dest_node;
+ struct ethhdr *hdr = (void *)skb->data;
hroom = (adapter->iface_type == MWIFIEX_USB) ? 0 : INTF_HEADER_LEN;
- if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+ if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
+ dest_node = mwifiex_get_sta_entry(priv, hdr->h_dest);
+ if (dest_node) {
+ dest_node->stats.tx_bytes += skb->len;
+ dest_node->stats.tx_packets++;
+ }
+
head_ptr = mwifiex_process_uap_txpd(priv, skb);
- else
+ } else {
head_ptr = mwifiex_process_sta_txpd(priv, skb);
+ }
if ((adapter->data_sent || adapter->tx_lock_flag) && head_ptr) {
skb_queue_tail(&adapter->tx_data_q, skb);
@@ -112,10 +125,12 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
skb, tx_param);
}
}
+ mwifiex_dbg_dump(adapter, DAT_D, "tx pkt:", skb->data,
+ min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN));
switch (ret) {
case -ENOSR:
- dev_dbg(adapter->dev, "data: -ENOSR is returned\n");
+ mwifiex_dbg(adapter, ERROR, "data: -ENOSR is returned\n");
break;
case -EBUSY:
if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
@@ -124,13 +139,14 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
if (local_tx_pd)
local_tx_pd->flags = 0;
}
- dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
+ mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
break;
case -1:
if (adapter->iface_type != MWIFIEX_PCIE)
adapter->data_sent = false;
- dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n",
- ret);
+ mwifiex_dbg(adapter, ERROR,
+ "mwifiex_write_data_async failed: 0x%X\n",
+ ret);
adapter->dbg.num_tx_host_to_card_failure++;
mwifiex_write_data_complete(adapter, skb, 0, ret);
break;
@@ -162,7 +178,8 @@ static int mwifiex_host_to_card(struct mwifiex_adapter *adapter,
priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num,
tx_info->bss_type);
if (!priv) {
- dev_err(adapter->dev, "data: priv not found. Drop TX packet\n");
+ mwifiex_dbg(adapter, ERROR,
+ "data: priv not found. Drop TX packet\n");
adapter->dbg.num_tx_host_to_card_failure++;
mwifiex_write_data_complete(adapter, skb, 0, 0);
return ret;
@@ -187,7 +204,7 @@ static int mwifiex_host_to_card(struct mwifiex_adapter *adapter,
}
switch (ret) {
case -ENOSR:
- dev_err(adapter->dev, "data: -ENOSR is returned\n");
+ mwifiex_dbg(adapter, ERROR, "data: -ENOSR is returned\n");
break;
case -EBUSY:
if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
@@ -202,13 +219,13 @@ static int mwifiex_host_to_card(struct mwifiex_adapter *adapter,
atomic_add(tx_info->aggr_num, &adapter->tx_queued);
else
atomic_inc(&adapter->tx_queued);
- dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
+ mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
break;
case -1:
if (adapter->iface_type != MWIFIEX_PCIE)
adapter->data_sent = false;
- dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n",
- ret);
+ mwifiex_dbg(adapter, ERROR,
+ "mwifiex_write_data_async failed: 0x%X\n", ret);
adapter->dbg.num_tx_host_to_card_failure++;
mwifiex_write_data_complete(adapter, skb, 0, ret);
break;
@@ -302,11 +319,11 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
priv->stats.tx_errors++;
}
- if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) {
+ if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT)
atomic_dec_return(&adapter->pending_bridged_pkts);
- if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
- goto done;
- }
+
+ if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
+ goto done;
if (aggr)
/* For skb_aggr, do not wake up tx queue */
@@ -319,7 +336,7 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
txq = netdev_get_tx_queue(priv->netdev, index);
if (netif_tx_queue_stopped(txq)) {
netif_tx_wake_queue(txq);
- dev_dbg(adapter->dev, "wake queue: %d\n", index);
+ mwifiex_dbg(adapter, DATA, "wake queue: %d\n", index);
}
}
done:
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c
index f5c2af01ba0a..b74930054b8c 100644
--- a/drivers/net/wireless/mwifiex/uap_cmd.c
+++ b/drivers/net/wireless/mwifiex/uap_cmd.c
@@ -167,7 +167,7 @@ mwifiex_set_ht_params(struct mwifiex_private *priv,
ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, params->beacon.tail,
params->beacon.tail_len);
if (ht_ie) {
- memcpy(&bss_cfg->ht_cap, ht_ie,
+ memcpy(&bss_cfg->ht_cap, ht_ie + 2,
sizeof(struct ieee80211_ht_cap));
cap_info = le16_to_cpu(bss_cfg->ht_cap.cap_info);
memset(&bss_cfg->ht_cap.mcs, 0,
@@ -184,8 +184,8 @@ mwifiex_set_ht_params(struct mwifiex_private *priv,
bss_cfg->ht_cap.mcs.rx_mask[1] = 0xff;
break;
default:
- dev_warn(priv->adapter->dev,
- "Unsupported RX-STBC, default to 2x2\n");
+ mwifiex_dbg(priv->adapter, WARN,
+ "Unsupported RX-STBC, default to 2x2\n");
bss_cfg->ht_cap.mcs.rx_mask[0] = 0xff;
bss_cfg->ht_cap.mcs.rx_mask[1] = 0xff;
break;
@@ -222,6 +222,23 @@ void mwifiex_set_vht_params(struct mwifiex_private *priv,
return;
}
+/* This function updates 11ac related parameters from IE
+ * and sets them into bss_config structure.
+ */
+void mwifiex_set_tpc_params(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_ap_settings *params)
+{
+ const u8 *tpc_ie;
+
+ tpc_ie = cfg80211_find_ie(WLAN_EID_TPC_REQUEST, params->beacon.tail,
+ params->beacon.tail_len);
+ if (tpc_ie)
+ bss_cfg->power_constraint = *(tpc_ie + 2);
+ else
+ bss_cfg->power_constraint = 0;
+}
+
/* Enable VHT only when cfg80211_ap_settings has VHT IE.
* Otherwise disable VHT.
*/
@@ -466,6 +483,7 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
struct host_cmd_tlv_auth_type *auth_type;
struct host_cmd_tlv_rates *tlv_rates;
struct host_cmd_tlv_ageout_timer *ao_timer, *ps_ao_timer;
+ struct host_cmd_tlv_power_constraint *pwr_ct;
struct mwifiex_ie_types_htcap *htcap;
struct mwifiex_ie_types_wmmcap *wmm_cap;
struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
@@ -644,6 +662,15 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
tlv += sizeof(*ao_timer);
}
+ if (bss_cfg->power_constraint) {
+ pwr_ct = (void *)tlv;
+ pwr_ct->header.type = cpu_to_le16(TLV_TYPE_PWR_CONSTRAINT);
+ pwr_ct->header.len = cpu_to_le16(sizeof(u8));
+ pwr_ct->constraint = bss_cfg->power_constraint;
+ cmd_size += sizeof(*pwr_ct);
+ tlv += sizeof(*pwr_ct);
+ }
+
if (bss_cfg->ps_sta_ao_timer) {
ps_ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
ps_ao_timer->header.type =
@@ -754,6 +781,8 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
break;
case HostCmd_CMD_UAP_BSS_START:
case HostCmd_CMD_UAP_BSS_STOP:
+ case HOST_CMD_APCMD_SYS_RESET:
+ case HOST_CMD_APCMD_STA_LIST:
cmd->command = cpu_to_le16(cmd_no);
cmd->size = cpu_to_le16(S_DS_GEN);
break;
@@ -767,19 +796,22 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
return -1;
break;
default:
- dev_err(priv->adapter->dev,
- "PREP_CMD: unknown cmd %#x\n", cmd_no);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "PREP_CMD: unknown cmd %#x\n", cmd_no);
return -1;
}
return 0;
}
-void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg,
+void mwifiex_uap_set_channel(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_chan_def chandef)
{
u8 config_bands = 0;
+ priv->bss_chandef = chandef;
+
bss_cfg->channel = ieee80211_frequency_to_channel(
chandef.chan->center_freq);
@@ -800,30 +832,53 @@ void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg,
if (chandef.width > NL80211_CHAN_WIDTH_40)
config_bands |= BAND_AAC;
}
+
+ priv->adapter->config_bands = config_bands;
}
int mwifiex_config_start_uap(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_cfg)
{
+ enum state_11d_t state_11d;
+
if (mwifiex_del_mgmt_ies(priv))
- dev_err(priv->adapter->dev, "Failed to delete mgmt IEs!\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to delete mgmt IEs!\n");
if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0, NULL, true)) {
- dev_err(priv->adapter->dev, "Failed to stop the BSS\n");
+ mwifiex_dbg(priv->adapter, ERROR, "Failed to stop the BSS\n");
+ return -1;
+ }
+
+ if (mwifiex_send_cmd(priv, HOST_CMD_APCMD_SYS_RESET,
+ HostCmd_ACT_GEN_SET, 0, NULL, true)) {
+ mwifiex_dbg(priv->adapter, ERROR, "Failed to reset BSS\n");
return -1;
}
if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
HostCmd_ACT_GEN_SET,
UAP_BSS_PARAMS_I, bss_cfg, false)) {
- dev_err(priv->adapter->dev, "Failed to set the SSID\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to set the SSID\n");
+ return -1;
+ }
+
+ /* Send cmd to FW to enable 11D function */
+ state_11d = ENABLE_11D;
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, DOT11D_I,
+ &state_11d, true)) {
+ mwifiex_dbg(priv->adapter, ERROR,
+ "11D: failed to enable 11D\n");
return -1;
}
if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START,
HostCmd_ACT_GEN_SET, 0, NULL, false)) {
- dev_err(priv->adapter->dev, "Failed to start the BSS\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to start the BSS\n");
return -1;
}
diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c
index f4794cdc36d2..7bc1f850e3b7 100644
--- a/drivers/net/wireless/mwifiex/uap_event.c
+++ b/drivers/net/wireless/mwifiex/uap_event.c
@@ -21,8 +21,70 @@
#include "main.h"
#include "11n.h"
+#define MWIFIEX_BSS_START_EVT_FIX_SIZE 12
+static int mwifiex_check_uap_capabilties(struct mwifiex_private *priv,
+ struct sk_buff *event)
+{
+ int evt_len;
+ u8 *curr;
+ u16 tlv_len;
+ struct mwifiex_ie_types_data *tlv_hdr;
+ struct ieee_types_wmm_parameter *wmm_param_ie = NULL;
+ int mask = IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK;
+
+ priv->wmm_enabled = false;
+ skb_pull(event, MWIFIEX_BSS_START_EVT_FIX_SIZE);
+ evt_len = event->len;
+ curr = event->data;
+
+ mwifiex_dbg_dump(priv->adapter, EVT_D, "uap capabilties:",
+ event->data, event->len);
+ while ((evt_len >= sizeof(tlv_hdr->header))) {
+ tlv_hdr = (struct mwifiex_ie_types_data *)curr;
+ tlv_len = le16_to_cpu(tlv_hdr->header.len);
+
+ if (evt_len < tlv_len + sizeof(tlv_hdr->header))
+ break;
+
+ switch (le16_to_cpu(tlv_hdr->header.type)) {
+ case WLAN_EID_HT_CAPABILITY:
+ priv->ap_11n_enabled = true;
+ break;
+
+ case WLAN_EID_VHT_CAPABILITY:
+ priv->ap_11ac_enabled = true;
+ break;
+
+ case WLAN_EID_VENDOR_SPECIFIC:
+ /* Point the regular IEEE IE 2 bytes into the Marvell IE
+ * and setup the IEEE IE type and length byte fields
+ */
+ wmm_param_ie = (void *)(curr + 2);
+ wmm_param_ie->vend_hdr.len = (u8)tlv_len;
+ wmm_param_ie->vend_hdr.element_id =
+ WLAN_EID_VENDOR_SPECIFIC;
+ mwifiex_dbg(priv->adapter, EVENT,
+ "info: check uap capabilities:\t"
+ "wmm parameter set count: %d\n",
+ wmm_param_ie->qos_info_bitmap & mask);
+
+ mwifiex_wmm_setup_ac_downgrade(priv);
+ priv->wmm_enabled = true;
+ mwifiex_wmm_setup_queue_priorities(priv, wmm_param_ie);
+ break;
+
+ default:
+ break;
+ }
+
+ curr += (tlv_len + sizeof(tlv_hdr->header));
+ evt_len -= (tlv_len + sizeof(tlv_hdr->header));
+ }
+
+ return 0;
+}
/*
* This function handles AP interface specific events generated by firmware.
@@ -80,8 +142,8 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
node = mwifiex_add_sta_entry(priv, event->sta_addr);
if (!node) {
- dev_warn(adapter->dev,
- "could not create station entry!\n");
+ mwifiex_dbg(adapter, ERROR,
+ "could not create station entry!\n");
return -1;
}
@@ -128,58 +190,63 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
break;
case EVENT_UAP_BSS_START:
- dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
+ mwifiex_dbg(adapter, EVENT,
+ "AP EVENT: event id: %#x\n", eventcause);
memcpy(priv->netdev->dev_addr, adapter->event_body + 2,
ETH_ALEN);
if (priv->hist_data)
mwifiex_hist_data_reset(priv);
+ mwifiex_check_uap_capabilties(priv, adapter->event_skb);
break;
case EVENT_UAP_MIC_COUNTERMEASURES:
/* For future development */
- dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
+ mwifiex_dbg(adapter, EVENT,
+ "AP EVENT: event id: %#x\n", eventcause);
break;
case EVENT_AMSDU_AGGR_CTRL:
ctrl = le16_to_cpu(*(__le16 *)adapter->event_body);
- dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", ctrl);
+ mwifiex_dbg(adapter, EVENT,
+ "event: AMSDU_AGGR_CTRL %d\n", ctrl);
if (priv->media_connected) {
adapter->tx_buf_size =
min_t(u16, adapter->curr_tx_buf_size, ctrl);
- dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
- adapter->tx_buf_size);
+ mwifiex_dbg(adapter, EVENT,
+ "event: tx_buf_size %d\n",
+ adapter->tx_buf_size);
}
break;
case EVENT_ADDBA:
- dev_dbg(adapter->dev, "event: ADDBA Request\n");
+ mwifiex_dbg(adapter, EVENT, "event: ADDBA Request\n");
if (priv->media_connected)
mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP,
HostCmd_ACT_GEN_SET, 0,
adapter->event_body, false);
break;
case EVENT_DELBA:
- dev_dbg(adapter->dev, "event: DELBA Request\n");
+ mwifiex_dbg(adapter, EVENT, "event: DELBA Request\n");
if (priv->media_connected)
mwifiex_11n_delete_ba_stream(priv, adapter->event_body);
break;
case EVENT_BA_STREAM_TIEMOUT:
- dev_dbg(adapter->dev, "event: BA Stream timeout\n");
+ mwifiex_dbg(adapter, EVENT, "event: BA Stream timeout\n");
if (priv->media_connected) {
ba_timeout = (void *)adapter->event_body;
mwifiex_11n_ba_stream_timeout(priv, ba_timeout);
}
break;
case EVENT_EXT_SCAN_REPORT:
- dev_dbg(adapter->dev, "event: EXT_SCAN Report\n");
+ mwifiex_dbg(adapter, EVENT, "event: EXT_SCAN Report\n");
if (adapter->ext_scan)
return mwifiex_handle_event_ext_scan_report(priv,
adapter->event_skb->data);
break;
case EVENT_TX_STATUS_REPORT:
- dev_dbg(adapter->dev, "event: TX_STATUS Report\n");
+ mwifiex_dbg(adapter, EVENT, "event: TX_STATUS Report\n");
mwifiex_parse_tx_status_event(priv, adapter->event_body);
break;
case EVENT_PS_SLEEP:
- dev_dbg(adapter->dev, "info: EVENT: SLEEP\n");
+ mwifiex_dbg(adapter, EVENT, "info: EVENT: SLEEP\n");
adapter->ps_state = PS_STATE_PRE_SLEEP;
@@ -187,12 +254,12 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
break;
case EVENT_PS_AWAKE:
- dev_dbg(adapter->dev, "info: EVENT: AWAKE\n");
+ mwifiex_dbg(adapter, EVENT, "info: EVENT: AWAKE\n");
if (!adapter->pps_uapsd_mode &&
priv->media_connected && adapter->sleep_period.period) {
adapter->pps_uapsd_mode = true;
- dev_dbg(adapter->dev,
- "event: PPS/UAPSD mode activated\n");
+ mwifiex_dbg(adapter, EVENT,
+ "event: PPS/UAPSD mode activated\n");
}
adapter->tx_lock_flag = false;
if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
@@ -218,16 +285,21 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
break;
case EVENT_CHANNEL_REPORT_RDY:
- dev_dbg(adapter->dev, "event: Channel Report\n");
+ mwifiex_dbg(adapter, EVENT, "event: Channel Report\n");
mwifiex_11h_handle_chanrpt_ready(priv, adapter->event_skb);
break;
case EVENT_RADAR_DETECTED:
- dev_dbg(adapter->dev, "event: Radar detected\n");
+ mwifiex_dbg(adapter, EVENT, "event: Radar detected\n");
mwifiex_11h_handle_radar_detected(priv, adapter->event_skb);
break;
+ case EVENT_BT_COEX_WLAN_PARA_CHANGE:
+ dev_err(adapter->dev, "EVENT: BT coex wlan param update\n");
+ mwifiex_bt_coex_wlan_param_update_event(priv,
+ adapter->event_skb);
+ break;
default:
- dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
- eventcause);
+ mwifiex_dbg(adapter, EVENT,
+ "event: unknown event id: %#x\n", eventcause);
break;
}
diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c
index 38ac4d74c486..87667418af5f 100644
--- a/drivers/net/wireless/mwifiex/uap_txrx.c
+++ b/drivers/net/wireless/mwifiex/uap_txrx.c
@@ -97,14 +97,15 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
struct mwifiex_txinfo *tx_info;
int hdr_chop;
struct ethhdr *p_ethhdr;
+ struct mwifiex_sta_node *src_node;
uap_rx_pd = (struct uap_rxpd *)(skb->data);
rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
if ((atomic_read(&adapter->pending_bridged_pkts) >=
MWIFIEX_BRIDGED_PKTS_THR_HIGH)) {
- dev_err(priv->adapter->dev,
- "Tx: Bridge packet limit reached. Drop packet!\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Tx: Bridge packet limit reached. Drop packet!\n");
kfree_skb(skb);
mwifiex_uap_cleanup_tx_queues(priv);
return;
@@ -153,15 +154,15 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
skb_pull(skb, hdr_chop);
if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) {
- dev_dbg(priv->adapter->dev,
- "data: Tx: insufficient skb headroom %d\n",
- skb_headroom(skb));
+ mwifiex_dbg(priv->adapter, ERROR,
+ "data: Tx: insufficient skb headroom %d\n",
+ skb_headroom(skb));
/* Insufficient skb headroom - allocate a new skb */
new_skb =
skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
if (unlikely(!new_skb)) {
- dev_err(priv->adapter->dev,
- "Tx: cannot allocate new_skb\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Tx: cannot allocate new_skb\n");
kfree_skb(skb);
priv->stats.tx_dropped++;
return;
@@ -169,8 +170,9 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
kfree_skb(skb);
skb = new_skb;
- dev_dbg(priv->adapter->dev, "info: new skb headroom %d\n",
- skb_headroom(skb));
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: new skb headroom %d\n",
+ skb_headroom(skb));
}
tx_info = MWIFIEX_SKB_TXCB(skb);
@@ -179,6 +181,15 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
tx_info->bss_type = priv->bss_type;
tx_info->flags |= MWIFIEX_BUF_FLAG_BRIDGED_PKT;
+ src_node = mwifiex_get_sta_entry(priv, rx_pkt_hdr->eth803_hdr.h_source);
+ if (src_node) {
+ src_node->stats.last_rx = jiffies;
+ src_node->stats.rx_bytes += skb->len;
+ src_node->stats.rx_packets++;
+ src_node->stats.last_tx_rate = uap_rx_pd->rx_rate;
+ src_node->stats.last_tx_htinfo = uap_rx_pd->ht_info;
+ }
+
if (is_unicast_ether_addr(rx_pkt_hdr->eth803_hdr.h_dest)) {
/* Update bridge packet statistics as the
* packet is not going to kernel/upper layer.
@@ -225,7 +236,8 @@ int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
/* don't do packet forwarding in disconnected state */
if (!priv->media_connected) {
- dev_err(adapter->dev, "drop packet in disconnected state.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "drop packet in disconnected state.\n");
dev_kfree_skb_any(skb);
return 0;
}
@@ -273,13 +285,20 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type);
rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
+ ether_addr_copy(ta, rx_pkt_hdr->eth803_hdr.h_source);
+
if ((le16_to_cpu(uap_rx_pd->rx_pkt_offset) +
le16_to_cpu(uap_rx_pd->rx_pkt_length)) > (u16) skb->len) {
- dev_err(adapter->dev,
- "wrong rx packet: len=%d, offset=%d, length=%d\n",
- skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset),
- le16_to_cpu(uap_rx_pd->rx_pkt_length));
+ mwifiex_dbg(adapter, ERROR,
+ "wrong rx packet: len=%d, offset=%d, length=%d\n",
+ skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset),
+ le16_to_cpu(uap_rx_pd->rx_pkt_length));
priv->stats.rx_dropped++;
+
+ node = mwifiex_get_sta_entry(priv, ta);
+ if (node)
+ node->stats.tx_failed++;
+
dev_kfree_skb_any(skb);
return 0;
}
@@ -287,12 +306,12 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
if (rx_pkt_type == PKT_TYPE_MGMT) {
ret = mwifiex_process_mgmt_packet(priv, skb);
if (ret)
- dev_err(adapter->dev, "Rx of mgmt packet failed");
+ mwifiex_dbg(adapter, ERROR,
+ "Rx of mgmt packet failed");
dev_kfree_skb_any(skb);
return ret;
}
- memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
if (rx_pkt_type != PKT_TYPE_BAR && uap_rx_pd->priority < MAX_NUM_TID) {
spin_lock_irqsave(&priv->sta_list_spinlock, flags);
@@ -354,7 +373,8 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv,
INTF_HEADER_LEN;
if (!skb->len) {
- dev_err(adapter->dev, "Tx: bad packet length: %d\n", skb->len);
+ mwifiex_dbg(adapter, ERROR,
+ "Tx: bad packet length: %d\n", skb->len);
tx_info->status_code = -1;
return skb->data;
}
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c
index fd8027f200a0..aada93425f80 100644
--- a/drivers/net/wireless/mwifiex/usb.c
+++ b/drivers/net/wireless/mwifiex/usb.c
@@ -60,7 +60,6 @@ static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size);
static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
struct sk_buff *skb, u8 ep)
{
- struct device *dev = adapter->dev;
u32 recv_type;
__le32 tmp;
int ret;
@@ -69,13 +68,15 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
mwifiex_process_hs_config(adapter);
if (skb->len < INTF_HEADER_LEN) {
- dev_err(dev, "%s: invalid skb->len\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: invalid skb->len\n", __func__);
return -1;
}
switch (ep) {
case MWIFIEX_USB_EP_CMD_EVENT:
- dev_dbg(dev, "%s: EP_CMD_EVENT\n", __func__);
+ mwifiex_dbg(adapter, EVENT,
+ "%s: EP_CMD_EVENT\n", __func__);
skb_copy_from_linear_data(skb, &tmp, INTF_HEADER_LEN);
recv_type = le32_to_cpu(tmp);
skb_pull(skb, INTF_HEADER_LEN);
@@ -83,11 +84,12 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
switch (recv_type) {
case MWIFIEX_USB_TYPE_CMD:
if (skb->len > MWIFIEX_SIZE_OF_CMD_BUFFER) {
- dev_err(dev, "CMD: skb->len too large\n");
+ mwifiex_dbg(adapter, ERROR,
+ "CMD: skb->len too large\n");
ret = -1;
goto exit_restore_skb;
} else if (!adapter->curr_cmd) {
- dev_dbg(dev, "CMD: no curr_cmd\n");
+ mwifiex_dbg(adapter, WARN, "CMD: no curr_cmd\n");
if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
mwifiex_process_sleep_confirm_resp(
adapter, skb->data,
@@ -104,16 +106,19 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
break;
case MWIFIEX_USB_TYPE_EVENT:
if (skb->len < sizeof(u32)) {
- dev_err(dev, "EVENT: skb->len too small\n");
+ mwifiex_dbg(adapter, ERROR,
+ "EVENT: skb->len too small\n");
ret = -1;
goto exit_restore_skb;
}
skb_copy_from_linear_data(skb, &tmp, sizeof(u32));
adapter->event_cause = le32_to_cpu(tmp);
- dev_dbg(dev, "event_cause %#x\n", adapter->event_cause);
+ mwifiex_dbg(adapter, EVENT,
+ "event_cause %#x\n", adapter->event_cause);
if (skb->len > MAX_EVENT_SIZE) {
- dev_err(dev, "EVENT: event body too large\n");
+ mwifiex_dbg(adapter, ERROR,
+ "EVENT: event body too large\n");
ret = -1;
goto exit_restore_skb;
}
@@ -125,14 +130,16 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
adapter->event_skb = skb;
break;
default:
- dev_err(dev, "unknown recv_type %#x\n", recv_type);
+ mwifiex_dbg(adapter, ERROR,
+ "unknown recv_type %#x\n", recv_type);
return -1;
}
break;
case MWIFIEX_USB_EP_DATA:
- dev_dbg(dev, "%s: EP_DATA\n", __func__);
+ mwifiex_dbg(adapter, DATA, "%s: EP_DATA\n", __func__);
if (skb->len > MWIFIEX_RX_DATA_BUF_SIZE) {
- dev_err(dev, "DATA: skb->len too large\n");
+ mwifiex_dbg(adapter, ERROR,
+ "DATA: skb->len too large\n");
return -1;
}
@@ -141,7 +148,8 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
atomic_inc(&adapter->rx_pending);
break;
default:
- dev_err(dev, "%s: unknown endport %#x\n", __func__, ep);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: unknown endport %#x\n", __func__, ep);
return -1;
}
@@ -176,8 +184,8 @@ static void mwifiex_usb_rx_complete(struct urb *urb)
if (recv_length) {
if (urb->status || (adapter->surprise_removed)) {
- dev_err(adapter->dev,
- "URB status is failed: %d\n", urb->status);
+ mwifiex_dbg(adapter, ERROR,
+ "URB status is failed: %d\n", urb->status);
/* Do not free skb in case of command ep */
if (card->rx_cmd_ep != context->ep)
dev_kfree_skb_any(skb);
@@ -190,8 +198,9 @@ static void mwifiex_usb_rx_complete(struct urb *urb)
status = mwifiex_usb_recv(adapter, skb, context->ep);
- dev_dbg(adapter->dev, "info: recv_length=%d, status=%d\n",
- recv_length, status);
+ mwifiex_dbg(adapter, INFO,
+ "info: recv_length=%d, status=%d\n",
+ recv_length, status);
if (status == -EINPROGRESS) {
mwifiex_queue_main_work(adapter);
@@ -203,8 +212,8 @@ static void mwifiex_usb_rx_complete(struct urb *urb)
return;
} else {
if (status == -1)
- dev_err(adapter->dev,
- "received data processing failed!\n");
+ mwifiex_dbg(adapter, ERROR,
+ "received data processing failed!\n");
/* Do not free skb in case of command ep */
if (card->rx_cmd_ep != context->ep)
@@ -212,8 +221,8 @@ static void mwifiex_usb_rx_complete(struct urb *urb)
}
} else if (urb->status) {
if (!adapter->is_suspended) {
- dev_warn(adapter->dev,
- "Card is removed: %d\n", urb->status);
+ mwifiex_dbg(adapter, FATAL,
+ "Card is removed: %d\n", urb->status);
adapter->surprise_removed = true;
}
dev_kfree_skb_any(skb);
@@ -249,14 +258,17 @@ static void mwifiex_usb_tx_complete(struct urb *urb)
struct mwifiex_adapter *adapter = context->adapter;
struct usb_card_rec *card = adapter->card;
- dev_dbg(adapter->dev, "%s: status: %d\n", __func__, urb->status);
+ mwifiex_dbg(adapter, INFO,
+ "%s: status: %d\n", __func__, urb->status);
if (context->ep == card->tx_cmd_ep) {
- dev_dbg(adapter->dev, "%s: CMD\n", __func__);
+ mwifiex_dbg(adapter, CMD,
+ "%s: CMD\n", __func__);
atomic_dec(&card->tx_cmd_urb_pending);
adapter->cmd_sent = false;
} else {
- dev_dbg(adapter->dev, "%s: DATA\n", __func__);
+ mwifiex_dbg(adapter, DATA,
+ "%s: DATA\n", __func__);
atomic_dec(&card->tx_data_urb_pending);
mwifiex_write_data_complete(adapter, context->skb, 0,
urb->status ? -1 : 0);
@@ -275,8 +287,8 @@ static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size)
if (card->rx_cmd_ep != ctx->ep) {
ctx->skb = dev_alloc_skb(size);
if (!ctx->skb) {
- dev_err(adapter->dev,
- "%s: dev_alloc_skb failed\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: dev_alloc_skb failed\n", __func__);
return -ENOMEM;
}
}
@@ -291,7 +303,7 @@ static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size)
atomic_inc(&card->rx_data_urb_pending);
if (usb_submit_urb(ctx->urb, GFP_ATOMIC)) {
- dev_err(adapter->dev, "usb_submit_urb failed\n");
+ mwifiex_dbg(adapter, ERROR, "usb_submit_urb failed\n");
dev_kfree_skb_any(ctx->skb);
ctx->skb = NULL;
@@ -468,7 +480,8 @@ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message)
adapter = card->adapter;
if (unlikely(adapter->is_suspended))
- dev_warn(adapter->dev, "Device already suspended\n");
+ mwifiex_dbg(adapter, WARN,
+ "Device already suspended\n");
mwifiex_enable_hs(adapter);
@@ -519,7 +532,8 @@ static int mwifiex_usb_resume(struct usb_interface *intf)
adapter = card->adapter;
if (unlikely(!adapter->is_suspended)) {
- dev_warn(adapter->dev, "Device already resumed\n");
+ mwifiex_dbg(adapter, WARN,
+ "Device already resumed\n");
return 0;
}
@@ -578,7 +592,8 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)
mwifiex_usb_free(card);
- dev_dbg(adapter->dev, "%s: removing card\n", __func__);
+ mwifiex_dbg(adapter, FATAL,
+ "%s: removing card\n", __func__);
mwifiex_remove_card(adapter, &add_remove_card_sem);
usb_set_intfdata(intf, NULL);
@@ -608,7 +623,8 @@ static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter)
card->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
if (!card->tx_cmd.urb) {
- dev_err(adapter->dev, "tx_cmd.urb allocation failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "tx_cmd.urb allocation failed\n");
return -ENOMEM;
}
@@ -620,8 +636,8 @@ static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter)
card->tx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL);
if (!card->tx_data_list[i].urb) {
- dev_err(adapter->dev,
- "tx_data_list[] urb allocation failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "tx_data_list[] urb allocation failed\n");
return -ENOMEM;
}
}
@@ -639,15 +655,13 @@ static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter)
card->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
if (!card->rx_cmd.urb) {
- dev_err(adapter->dev, "rx_cmd.urb allocation failed\n");
+ mwifiex_dbg(adapter, ERROR, "rx_cmd.urb allocation failed\n");
return -ENOMEM;
}
card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE);
- if (!card->rx_cmd.skb) {
- dev_err(adapter->dev, "rx_cmd.skb allocation failed\n");
+ if (!card->rx_cmd.skb)
return -ENOMEM;
- }
if (mwifiex_usb_submit_rx_urb(&card->rx_cmd, MWIFIEX_RX_CMD_BUF_SIZE))
return -1;
@@ -658,8 +672,8 @@ static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter)
card->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL);
if (!card->rx_data_list[i].urb) {
- dev_err(adapter->dev,
- "rx_data_list[] urb allocation failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "rx_data_list[] urb allocation failed\n");
return -1;
}
if (mwifiex_usb_submit_rx_urb(&card->rx_data_list[i],
@@ -683,7 +697,8 @@ static int mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf,
ret = usb_bulk_msg(card->udev, usb_sndbulkpipe(card->udev, ep), pbuf,
*len, &actual_length, timeout);
if (ret) {
- dev_err(adapter->dev, "usb_bulk_msg for tx failed: %d\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "usb_bulk_msg for tx failed: %d\n", ret);
return ret;
}
@@ -702,7 +717,8 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf,
ret = usb_bulk_msg(card->udev, usb_rcvbulkpipe(card->udev, ep), pbuf,
*len, &actual_length, timeout);
if (ret) {
- dev_err(adapter->dev, "usb_bulk_msg for rx failed: %d\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "usb_bulk_msg for rx failed: %d\n", ret);
return ret;
}
@@ -722,13 +738,13 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
struct urb *tx_urb;
if (adapter->is_suspended) {
- dev_err(adapter->dev,
- "%s: not allowed while suspended\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: not allowed while suspended\n", __func__);
return -1;
}
if (adapter->surprise_removed) {
- dev_err(adapter->dev, "%s: device removed\n", __func__);
+ mwifiex_dbg(adapter, ERROR, "%s: device removed\n", __func__);
return -1;
}
@@ -737,7 +753,7 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
return -EBUSY;
}
- dev_dbg(adapter->dev, "%s: ep=%d\n", __func__, ep);
+ mwifiex_dbg(adapter, INFO, "%s: ep=%d\n", __func__, ep);
if (ep == card->tx_cmd_ep) {
context = &card->tx_cmd;
@@ -764,7 +780,8 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
atomic_inc(&card->tx_data_urb_pending);
if (usb_submit_urb(tx_urb, GFP_ATOMIC)) {
- dev_err(adapter->dev, "%s: usb_submit_urb failed\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: usb_submit_urb failed\n", __func__);
if (ep == card->tx_cmd_ep) {
atomic_dec(&card->tx_cmd_urb_pending);
} else {
@@ -843,8 +860,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
u8 check_winner = 1;
if (!firmware) {
- dev_err(adapter->dev,
- "No firmware image found! Terminating download\n");
+ mwifiex_dbg(adapter, ERROR,
+ "No firmware image found! Terminating download\n");
ret = -1;
goto fw_exit;
}
@@ -889,8 +906,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
MWIFIEX_USB_EP_CMD_EVENT,
MWIFIEX_USB_TIMEOUT);
if (ret) {
- dev_err(adapter->dev,
- "write_data_sync: failed: %d\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "write_data_sync: failed: %d\n",
+ ret);
continue;
}
@@ -902,8 +920,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
MWIFIEX_USB_EP_CMD_EVENT,
MWIFIEX_USB_TIMEOUT);
if (ret) {
- dev_err(adapter->dev,
- "read_data_sync: failed: %d\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "read_data_sync: failed: %d\n",
+ ret);
continue;
}
@@ -913,17 +932,17 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
/* check 1st firmware block resp for highest bit set */
if (check_winner) {
if (le32_to_cpu(sync_fw.cmd) & 0x80000000) {
- dev_warn(adapter->dev,
- "USB is not the winner %#x\n",
- sync_fw.cmd);
+ mwifiex_dbg(adapter, WARN,
+ "USB is not the winner %#x\n",
+ sync_fw.cmd);
/* returning success */
ret = 0;
goto cleanup;
}
- dev_dbg(adapter->dev,
- "USB is the winner, start to download FW\n");
+ mwifiex_dbg(adapter, MSG,
+ "start to download FW...\n");
check_winner = 0;
break;
@@ -931,9 +950,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
/* check the firmware block response for CRC errors */
if (sync_fw.cmd) {
- dev_err(adapter->dev,
- "FW received block with CRC %#x\n",
- sync_fw.cmd);
+ mwifiex_dbg(adapter, ERROR,
+ "FW received block with CRC %#x\n",
+ sync_fw.cmd);
ret = -1;
continue;
}
@@ -945,8 +964,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
} while ((dnld_cmd != FW_HAS_LAST_BLOCK) && retries);
cleanup:
- dev_notice(adapter->dev,
- "info: FW download over, size %d bytes\n", tlen);
+ mwifiex_dbg(adapter, MSG,
+ "info: FW download over, size %d bytes\n", tlen);
kfree(recv_buff);
kfree(fwdata);
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index b8a45872354d..790e61953abf 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -26,6 +26,8 @@
#include "11n.h"
static struct mwifiex_debug_data items[] = {
+ {"debug_mask", item_size(debug_mask),
+ item_addr(debug_mask), 1},
{"int_counter", item_size(int_counter),
item_addr(int_counter), 1},
{"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]),
@@ -158,7 +160,8 @@ int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
} else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) {
cmd = HostCmd_CMD_FUNC_SHUTDOWN;
} else {
- dev_err(priv->adapter->dev, "unsupported parameter\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "unsupported parameter\n");
return -1;
}
@@ -178,6 +181,7 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv,
struct mwifiex_adapter *adapter = priv->adapter;
if (info) {
+ info->debug_mask = adapter->debug_mask;
memcpy(info->packets_out,
priv->wmm.packets_out,
sizeof(priv->wmm.packets_out));
@@ -325,7 +329,7 @@ mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len,
struct rxpd *rx_pd)
{
u16 stype;
- u8 category, action_code;
+ u8 category, action_code, *addr2;
struct ieee80211_hdr *ieee_hdr = (void *)payload;
stype = (le16_to_cpu(ieee_hdr->frame_control) & IEEE80211_FCTL_STYPE);
@@ -333,21 +337,35 @@ mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len,
switch (stype) {
case IEEE80211_STYPE_ACTION:
category = *(payload + sizeof(struct ieee80211_hdr));
- action_code = *(payload + sizeof(struct ieee80211_hdr) + 1);
- if (category == WLAN_CATEGORY_PUBLIC &&
- action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) {
- dev_dbg(priv->adapter->dev,
- "TDLS discovery response %pM nf=%d, snr=%d\n",
- ieee_hdr->addr2, rx_pd->nf, rx_pd->snr);
- mwifiex_auto_tdls_update_peer_signal(priv,
- ieee_hdr->addr2,
- rx_pd->snr,
- rx_pd->nf);
+ switch (category) {
+ case WLAN_CATEGORY_PUBLIC:
+ action_code = *(payload + sizeof(struct ieee80211_hdr)
+ + 1);
+ if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) {
+ addr2 = ieee_hdr->addr2;
+ mwifiex_dbg(priv->adapter, INFO,
+ "TDLS discovery response %pM nf=%d, snr=%d\n",
+ addr2, rx_pd->nf, rx_pd->snr);
+ mwifiex_auto_tdls_update_peer_signal(priv,
+ addr2,
+ rx_pd->snr,
+ rx_pd->nf);
+ }
+ break;
+ case WLAN_CATEGORY_BACK:
+ /*we dont indicate BACK action frames to cfg80211*/
+ mwifiex_dbg(priv->adapter, INFO,
+ "drop BACK action frames");
+ return -1;
+ default:
+ mwifiex_dbg(priv->adapter, INFO,
+ "unknown public action frame category %d\n",
+ category);
}
- break;
default:
- dev_dbg(priv->adapter->dev,
- "unknown mgmt frame subytpe %#x\n", stype);
+ mwifiex_dbg(priv->adapter, INFO,
+ "unknown mgmt frame subtype %#x\n", stype);
+ return 0;
}
return 0;
@@ -369,8 +387,8 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
if (!priv->mgmt_frame_mask ||
priv->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) {
- dev_dbg(priv->adapter->dev,
- "do not receive mgmt frames on uninitialized intf");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "do not receive mgmt frames on uninitialized intf");
return -1;
}
@@ -383,8 +401,9 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
ieee_hdr = (void *)skb->data;
if (ieee80211_is_mgmt(ieee_hdr->frame_control)) {
- mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr,
- pkt_len, rx_pd);
+ if (mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr,
+ pkt_len, rx_pd))
+ return -1;
}
/* Remove address4 */
memmove(skb->data + sizeof(struct ieee80211_hdr_3addr),
@@ -412,12 +431,25 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
*/
int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
{
+ struct mwifiex_sta_node *src_node;
+ struct ethhdr *p_ethhdr;
+
if (!skb)
return -1;
priv->stats.rx_bytes += skb->len;
priv->stats.rx_packets++;
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ p_ethhdr = (void *)skb->data;
+ src_node = mwifiex_get_sta_entry(priv, p_ethhdr->h_source);
+ if (src_node) {
+ src_node->stats.last_rx = jiffies;
+ src_node->stats.rx_bytes += skb->len;
+ src_node->stats.rx_packets++;
+ }
+ }
+
skb->dev = priv->netdev;
skb->protocol = eth_type_trans(skb, priv->netdev);
skb->ip_summed = CHECKSUM_NONE;
@@ -464,13 +496,14 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node)
{
- dev_dbg(adapter->dev, "cmd completed: status=%d\n",
- adapter->cmd_wait_q.status);
+ mwifiex_dbg(adapter, CMD,
+ "cmd completed: status=%d\n",
+ adapter->cmd_wait_q.status);
*(cmd_node->condition) = true;
if (adapter->cmd_wait_q.status == -ETIMEDOUT)
- dev_err(adapter->dev, "cmd timeout\n");
+ mwifiex_dbg(adapter, ERROR, "cmd timeout\n");
else
wake_up_interruptible(&adapter->cmd_wait_q.wait);
@@ -536,13 +569,16 @@ void
mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
int ies_len, struct mwifiex_sta_node *node)
{
+ struct ieee_types_header *ht_cap_ie;
const struct ieee80211_ht_cap *ht_cap;
if (!ies)
return;
- ht_cap = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
- if (ht_cap) {
+ ht_cap_ie = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies,
+ ies_len);
+ if (ht_cap_ie) {
+ ht_cap = (void *)(ht_cap_ie + 1);
node->is_11n_enabled = 1;
node->max_amsdu = le16_to_cpu(ht_cap->cap_info) &
IEEE80211_HT_CAP_MAX_AMSDU ?
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index b2e99569a0f8..a8ea21c3340c 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -107,7 +107,7 @@ mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, const u8 *ra)
ra_list->total_pkt_count = 0;
- dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list);
+ mwifiex_dbg(adapter, INFO, "info: allocated ra_list %p\n", ra_list);
return ra_list;
}
@@ -150,7 +150,8 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra)
for (i = 0; i < MAX_NUM_TID; ++i) {
ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra);
- dev_dbg(adapter->dev, "info: created ra_list %p\n", ra_list);
+ mwifiex_dbg(adapter, INFO,
+ "info: created ra_list %p\n", ra_list);
if (!ra_list)
break;
@@ -178,8 +179,8 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra)
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
}
- dev_dbg(adapter->dev, "data: ralist %p: is_11n_enabled=%d\n",
- ra_list, ra_list->is_11n_enabled);
+ mwifiex_dbg(adapter, DATA, "data: ralist %p: is_11n_enabled=%d\n",
+ ra_list, ra_list->is_11n_enabled);
if (ra_list->is_11n_enabled) {
ra_list->ba_pkt_count = 0;
@@ -241,11 +242,12 @@ mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
return;
}
- dev_dbg(priv->adapter->dev, "info: WMM Parameter IE: version=%d, "
- "qos_info Parameter Set Count=%d, Reserved=%#x\n",
- wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap &
- IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK,
- wmm_ie->reserved);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: WMM Parameter IE: version=%d,\t"
+ "qos_info Parameter Set Count=%d, Reserved=%#x\n",
+ wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap &
+ IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK,
+ wmm_ie->reserved);
for (num_ac = 0; num_ac < ARRAY_SIZE(wmm_ie->ac_params); num_ac++) {
u8 ecw = wmm_ie->ac_params[num_ac].ecw_bitmap;
@@ -257,10 +259,10 @@ mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
priv->wmm.queue_priority[ac_idx] = ac_idx;
tmp[ac_idx] = avg_back_off;
- dev_dbg(priv->adapter->dev,
- "info: WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
- (1 << ((ecw & MWIFIEX_ECW_MAX) >> 4)) - 1,
- cw_min, avg_back_off);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
+ (1 << ((ecw & MWIFIEX_ECW_MAX) >> 4)) - 1,
+ cw_min, avg_back_off);
mwifiex_wmm_ac_debug_print(&wmm_ie->ac_params[num_ac]);
}
@@ -333,8 +335,8 @@ mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv)
{
int ac_val;
- dev_dbg(priv->adapter->dev, "info: WMM: AC Priorities:"
- "BK(0), BE(1), VI(2), VO(3)\n");
+ mwifiex_dbg(priv->adapter, INFO, "info: WMM: AC Priorities:\t"
+ "BK(0), BE(1), VI(2), VO(3)\n");
if (!priv->wmm_enabled) {
/* WMM is not enabled, default priorities */
@@ -346,9 +348,10 @@ mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv)
priv->wmm.ac_down_graded_vals[ac_val]
= mwifiex_wmm_eval_downgrade_ac(priv,
(enum mwifiex_wmm_ac_e) ac_val);
- dev_dbg(priv->adapter->dev,
- "info: WMM: AC PRIO %d maps to %d\n",
- ac_val, priv->wmm.ac_down_graded_vals[ac_val]);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: WMM: AC PRIO %d maps to %d\n",
+ ac_val,
+ priv->wmm.ac_down_graded_vals[ac_val]);
}
}
}
@@ -428,6 +431,15 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
priv->tos_to_tid_inv[i];
}
+ priv->aggr_prio_tbl[6].amsdu
+ = priv->aggr_prio_tbl[6].ampdu_ap
+ = priv->aggr_prio_tbl[6].ampdu_user
+ = BA_STREAM_NOT_ALLOWED;
+
+ priv->aggr_prio_tbl[7].amsdu = priv->aggr_prio_tbl[7].ampdu_ap
+ = priv->aggr_prio_tbl[7].ampdu_user
+ = BA_STREAM_NOT_ALLOWED;
+
mwifiex_set_ba_params(priv);
mwifiex_reset_11n_rx_seq_num(priv);
@@ -512,8 +524,8 @@ static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv)
int i;
for (i = 0; i < MAX_NUM_TID; ++i) {
- dev_dbg(priv->adapter->dev,
- "info: ra_list: freeing buf for tid %d\n", i);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ra_list: freeing buf for tid %d\n", i);
list_for_each_entry_safe(ra_list, tmp_node,
&priv->wmm.tid_tbl_ptr[i].ra_list,
list) {
@@ -685,14 +697,15 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA &&
ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) {
if (ntohs(eth_hdr->h_proto) == ETH_P_TDLS)
- dev_dbg(adapter->dev,
- "TDLS setup packet for %pM. Don't block\n", ra);
+ mwifiex_dbg(adapter, DATA,
+ "TDLS setup packet for %pM.\t"
+ "Don't block\n", ra);
else if (memcmp(priv->cfg_bssid, ra, ETH_ALEN))
tdls_status = mwifiex_get_tdls_link_status(priv, ra);
}
if (!priv->media_connected && !mwifiex_is_skb_mgmt_frame(skb)) {
- dev_dbg(adapter->dev, "data: drop packet in disconnect\n");
+ mwifiex_dbg(adapter, DATA, "data: drop packet in disconnect\n");
mwifiex_write_data_complete(adapter, skb, 0, -1);
return;
}
@@ -773,6 +786,7 @@ int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
{
u8 *curr = (u8 *) &resp->params.get_wmm_status;
uint16_t resp_len = le16_to_cpu(resp->size), tlv_len;
+ int mask = IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK;
bool valid = true;
struct mwifiex_ie_types_data *tlv_hdr;
@@ -780,8 +794,9 @@ int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
struct ieee_types_wmm_parameter *wmm_param_ie = NULL;
struct mwifiex_wmm_ac_status *ac_status;
- dev_dbg(priv->adapter->dev, "info: WMM: WMM_GET_STATUS cmdresp received: %d\n",
- resp_len);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: WMM: WMM_GET_STATUS cmdresp received: %d\n",
+ resp_len);
while ((resp_len >= sizeof(tlv_hdr->header)) && valid) {
tlv_hdr = (struct mwifiex_ie_types_data *) curr;
@@ -795,12 +810,12 @@ int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
tlv_wmm_qstatus =
(struct mwifiex_ie_types_wmm_queue_status *)
tlv_hdr;
- dev_dbg(priv->adapter->dev,
- "info: CMD_RESP: WMM_GET_STATUS:"
- " QSTATUS TLV: %d, %d, %d\n",
- tlv_wmm_qstatus->queue_index,
- tlv_wmm_qstatus->flow_required,
- tlv_wmm_qstatus->disabled);
+ mwifiex_dbg(priv->adapter, CMD,
+ "info: CMD_RESP: WMM_GET_STATUS:\t"
+ "QSTATUS TLV: %d, %d, %d\n",
+ tlv_wmm_qstatus->queue_index,
+ tlv_wmm_qstatus->flow_required,
+ tlv_wmm_qstatus->disabled);
ac_status = &priv->wmm.ac_status[tlv_wmm_qstatus->
queue_index];
@@ -823,11 +838,10 @@ int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
wmm_param_ie->vend_hdr.element_id =
WLAN_EID_VENDOR_SPECIFIC;
- dev_dbg(priv->adapter->dev,
- "info: CMD_RESP: WMM_GET_STATUS:"
- " WMM Parameter Set Count: %d\n",
- wmm_param_ie->qos_info_bitmap &
- IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK);
+ mwifiex_dbg(priv->adapter, CMD,
+ "info: CMD_RESP: WMM_GET_STATUS:\t"
+ "WMM Parameter Set Count: %d\n",
+ wmm_param_ie->qos_info_bitmap & mask);
memcpy((u8 *) &priv->curr_bss_params.bss_descriptor.
wmm_ie, wmm_param_ie,
@@ -875,9 +889,9 @@ mwifiex_wmm_process_association_req(struct mwifiex_private *priv,
if (!wmm_ie)
return 0;
- dev_dbg(priv->adapter->dev,
- "info: WMM: process assoc req: bss->wmm_ie=%#x\n",
- wmm_ie->vend_hdr.element_id);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: WMM: process assoc req: bss->wmm_ie=%#x\n",
+ wmm_ie->vend_hdr.element_id);
if ((priv->wmm_required ||
(ht_cap && (priv->adapter->config_bands & BAND_GN ||
@@ -927,8 +941,8 @@ mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv,
*/
ret_val = (u8) (min(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1);
- dev_dbg(priv->adapter->dev, "data: WMM: Pkt Delay: %d ms,"
- " %d ms sent to FW\n", queue_delay, ret_val);
+ mwifiex_dbg(priv->adapter, DATA, "data: WMM: Pkt Delay: %d ms,\t"
+ "%d ms sent to FW\n", queue_delay, ret_val);
return ret_val;
}
@@ -1082,14 +1096,15 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
if (skb_queue_empty(&ptr->skb_head)) {
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
- dev_dbg(adapter->dev, "data: nothing to send\n");
+ mwifiex_dbg(adapter, DATA, "data: nothing to send\n");
return;
}
skb = skb_dequeue(&ptr->skb_head);
tx_info = MWIFIEX_SKB_TXCB(skb);
- dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb);
+ mwifiex_dbg(adapter, DATA,
+ "data: dequeuing the packet %p %p\n", ptr, skb);
ptr->total_pkt_count--;
@@ -1205,7 +1220,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
switch (ret) {
case -EBUSY:
- dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
+ mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
@@ -1224,7 +1239,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
case -1:
if (adapter->iface_type != MWIFIEX_PCIE)
adapter->data_sent = false;
- dev_err(adapter->dev, "host_to_card failed: %#x\n", ret);
+ mwifiex_dbg(adapter, ERROR, "host_to_card failed: %#x\n", ret);
adapter->dbg.num_tx_host_to_card_failure++;
mwifiex_write_data_complete(adapter, skb, 0, ret);
break;
@@ -1263,7 +1278,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
tid = mwifiex_get_tid(ptr);
- dev_dbg(adapter->dev, "data: tid=%d\n", tid);
+ mwifiex_dbg(adapter, DATA, "data: tid=%d\n", tid);
spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 95921167b53f..77361af68b18 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2380,7 +2380,7 @@ mwl8k_set_ht_caps(struct ieee80211_hw *hw,
if (cap & MWL8K_CAP_GREENFIELD)
band->ht_cap.cap |= IEEE80211_HT_CAP_GRN_FLD;
if (cap & MWL8K_CAP_AMPDU) {
- hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
}
@@ -5192,7 +5192,7 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw,
priv->sniffer_enabled = true;
}
- *total_flags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI |
+ *total_flags &= FIF_ALLMULTI |
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL |
FIF_OTHER_BSS;
@@ -5431,7 +5431,7 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u8 *addr = sta->addr, idx;
struct mwl8k_sta *sta_info = MWL8K_STA(sta);
- if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
+ if (!ieee80211_hw_check(hw, AMPDU_AGGREGATION))
return -ENOTSUPP;
spin_lock(&priv->stream_lock);
@@ -6076,14 +6076,15 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
hw->queues = MWL8K_TX_WMM_QUEUES;
/* Set rssi values to dBm */
- hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL;
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, HAS_RATE_CONTROL);
/*
* Ask mac80211 to not to trigger PS mode
* based on PM bit of incoming frames.
*/
if (priv->ap_fw)
- hw->flags |= IEEE80211_HW_AP_LINK_PS;
+ ieee80211_hw_set(hw, AP_LINK_PS);
hw->vif_data_size = sizeof(struct mwl8k_vif);
hw->sta_data_size = sizeof(struct mwl8k_sta);
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index 275408eaf95e..257a9eadd595 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -351,8 +351,7 @@ int p54_setup_mac(struct p54_common *priv)
* "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)) &&
+ if (priv->filter_flags & FIF_OTHER_BSS &&
(mode != P54_FILTER_TYPE_PROMISCUOUS))
mode |= P54_FILTER_TYPE_TRANSPARENT;
} else {
diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c
index 1f6fd5ff5531..9a8fedd3c0f5 100644
--- a/drivers/net/wireless/p54/led.c
+++ b/drivers/net/wireless/p54/led.c
@@ -83,7 +83,7 @@ static void p54_led_brightness_set(struct led_classdev *led_dev,
static int p54_register_led(struct p54_common *priv,
unsigned int led_index,
- char *name, char *trigger)
+ char *name, const char *trigger)
{
struct p54_led_dev *led = &priv->leds[led_index];
int err;
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index e79674f73dc5..7805864e76f9 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -395,13 +395,11 @@ static void p54_configure_filter(struct ieee80211_hw *dev,
{
struct p54_common *priv = dev->priv;
- *total_flags &= FIF_PROMISC_IN_BSS |
- FIF_ALLMULTI |
- FIF_OTHER_BSS;
+ *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS;
priv->filter_flags = *total_flags;
- if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
+ if (changed_flags & FIF_OTHER_BSS)
p54_setup_mac(priv);
if (changed_flags & FIF_ALLMULTI || multicast)
@@ -748,12 +746,12 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
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_MFP_CAPABLE |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+ ieee80211_hw_set(dev, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(dev, MFP_CAPABLE);
+ ieee80211_hw_set(dev, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(dev, SUPPORTS_PS);
+ ieee80211_hw_set(dev, RX_INCLUDES_FCS);
+ ieee80211_hw_set(dev, SIGNAL_DBM);
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 477f86354dc5..0881ba8535f4 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -143,7 +143,7 @@ static int psm;
static char *essid;
/* Default to encapsulation unless translation requested */
-static bool translate = 1;
+static bool translate = true;
static int country = USA;
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index d72ff8e7125d..71a825c750cf 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -356,9 +356,9 @@ struct ndis_80211_pmkid {
#define CAP_MODE_80211G 4
#define CAP_MODE_MASK 7
-#define WORK_LINK_UP (1<<0)
-#define WORK_LINK_DOWN (1<<1)
-#define WORK_SET_MULTICAST_LIST (1<<2)
+#define WORK_LINK_UP 0
+#define WORK_LINK_DOWN 1
+#define WORK_SET_MULTICAST_LIST 2
#define RNDIS_WLAN_ALG_NONE 0
#define RNDIS_WLAN_ALG_WEP (1<<0)
@@ -2861,7 +2861,7 @@ static void rndis_wlan_do_link_down_work(struct usbnet *usbdev)
deauthenticate(usbdev);
- cfg80211_disconnected(usbdev->net, 0, NULL, 0, GFP_KERNEL);
+ cfg80211_disconnected(usbdev->net, 0, NULL, 0, true, GFP_KERNEL);
}
netif_carrier_off(usbdev->net);
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index aeaf87bb5518..7e804324bfa7 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -1062,10 +1062,9 @@ int rsi_mac80211_attach(struct rsi_common *common)
hw->priv = adapter;
adapter->hw = hw;
- hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_HAS_RATE_CONTROL |
- IEEE80211_HW_AMPDU_AGGREGATION |
- 0;
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
hw->queues = MAX_HW_QUEUES;
hw->extra_tx_headroom = RSI_NEEDED_HEADROOM;
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index bdf5590ba304..9a3966cd6fbe 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -273,10 +273,8 @@ static void rt2400pci_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_PLCPFAIL));
rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
!(filter_flags & FIF_CONTROL));
- rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
- !(filter_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME, 1);
rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
- !(filter_flags & FIF_PROMISC_IN_BSS) &&
!rt2x00dev->intf_ap_count);
rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg);
@@ -1576,10 +1574,10 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all hw fields.
*/
- rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK;
+ ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS);
+ ieee80211_hw_set(rt2x00dev->hw, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM);
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 79f4fe65a119..1a6740b4d396 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -274,10 +274,8 @@ static void rt2500pci_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_PLCPFAIL));
rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
!(filter_flags & FIF_CONTROL));
- rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
- !(filter_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME, 1);
rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
- !(filter_flags & FIF_PROMISC_IN_BSS) &&
!rt2x00dev->intf_ap_count);
rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
rt2x00_set_field32(&reg, RXCSR0_DROP_MCAST,
@@ -1871,10 +1869,10 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all hw fields.
*/
- rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK;
+ ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS);
+ ieee80211_hw_set(rt2x00dev->hw, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM);
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 05c64597838d..b50d873145d5 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -434,10 +434,8 @@ static void rt2500usb_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_PLCPFAIL));
rt2x00_set_field16(&reg, TXRX_CSR2_DROP_CONTROL,
!(filter_flags & FIF_CONTROL));
- rt2x00_set_field16(&reg, TXRX_CSR2_DROP_NOT_TO_ME,
- !(filter_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_NOT_TO_ME, 1);
rt2x00_set_field16(&reg, TXRX_CSR2_DROP_TODS,
- !(filter_flags & FIF_PROMISC_IN_BSS) &&
!rt2x00dev->intf_ap_count);
rt2x00_set_field16(&reg, TXRX_CSR2_DROP_VERSION_ERROR, 1);
rt2x00_set_field16(&reg, TXRX_CSR2_DROP_MULTICAST,
@@ -1698,11 +1696,10 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
* multicast and broadcast traffic immediately instead of buffering it
* infinitly and thus dropping it after some time.
*/
- rt2x00dev->hw->flags =
- IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK;
+ ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS);
+ ieee80211_hw_set(rt2x00dev->hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM);
/*
* Disable powersaving as default.
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index ebd5625d13f1..95c1d7c0a2f3 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -2961,6 +2961,15 @@ enum rt2800_eeprom_word {
#define BCN_TBTT_OFFSET 64
/*
+ * Hardware has 255 WCID table entries. First 32 entries are reserved for
+ * shared keys. Since parts of the pairwise key table might be shared with
+ * the beacon frame buffers 6 & 7 we could only use the first 222 entries.
+ */
+#define WCID_START 33
+#define WCID_END 222
+#define STA_IDS_SIZE (WCID_END - WCID_START + 2)
+
+/*
* RT2800 driver data structure
*/
struct rt2800_drv_data {
@@ -2971,6 +2980,7 @@ struct rt2800_drv_data {
u8 txmixer_gain_24g;
u8 txmixer_gain_5g;
unsigned int tbtt_tick;
+ DECLARE_BITMAP(sta_ids, STA_IDS_SIZE);
};
#endif /* RT2800_H */
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index be2d54f257b1..9524564f873b 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -1381,38 +1381,6 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
}
EXPORT_SYMBOL_GPL(rt2800_config_shared_key);
-static inline int rt2800_find_wcid(struct rt2x00_dev *rt2x00dev)
-{
- struct mac_wcid_entry wcid_entry;
- int idx;
- u32 offset;
-
- /*
- * Search for the first free WCID entry and return the corresponding
- * index.
- *
- * Make sure the WCID starts _after_ the last possible shared key
- * entry (>32).
- *
- * Since parts of the pairwise key table might be shared with
- * the beacon frame buffers 6 & 7 we should only write into the
- * first 222 entries.
- */
- for (idx = 33; idx <= 222; idx++) {
- offset = MAC_WCID_ENTRY(idx);
- rt2800_register_multiread(rt2x00dev, offset, &wcid_entry,
- sizeof(wcid_entry));
- if (is_broadcast_ether_addr(wcid_entry.mac))
- return idx;
- }
-
- /*
- * Use -1 to indicate that we don't have any more space in the WCID
- * table.
- */
- return -1;
-}
-
int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_crypto *crypto,
struct ieee80211_key_conf *key)
@@ -1425,7 +1393,7 @@ int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
* Allow key configuration only for STAs that are
* known by the hw.
*/
- if (crypto->wcid < 0)
+ if (crypto->wcid > WCID_END)
return -ENOSPC;
key->hw_key_idx = crypto->wcid;
@@ -1455,11 +1423,13 @@ int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif,
{
int wcid;
struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta);
+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
/*
- * Find next free WCID.
+ * Search for the first free WCID entry and return the corresponding
+ * index.
*/
- wcid = rt2800_find_wcid(rt2x00dev);
+ wcid = find_first_zero_bit(drv_data->sta_ids, STA_IDS_SIZE) + WCID_START;
/*
* Store selected wcid even if it is invalid so that we can
@@ -1471,9 +1441,11 @@ int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif,
* No space left in the device, however, we can still communicate
* with the STA -> No error.
*/
- if (wcid < 0)
+ if (wcid > WCID_END)
return 0;
+ __set_bit(wcid - WCID_START, drv_data->sta_ids);
+
/*
* Clean up WCID attributes and write STA address to the device.
*/
@@ -1487,11 +1459,16 @@ EXPORT_SYMBOL_GPL(rt2800_sta_add);
int rt2800_sta_remove(struct rt2x00_dev *rt2x00dev, int wcid)
{
+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
+
+ if (wcid > WCID_END)
+ return 0;
/*
* Remove WCID entry, no need to clean the attributes as they will
* get renewed when the WCID is reused.
*/
rt2800_config_wcid(rt2x00dev, NULL, wcid);
+ __clear_bit(wcid - WCID_START, drv_data->sta_ids);
return 0;
}
@@ -1513,8 +1490,7 @@ void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_FCSFAIL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PHY_ERROR,
!(filter_flags & FIF_PLCPFAIL));
- rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_TO_ME,
- !(filter_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_TO_ME, 1);
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0);
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_VER_ERROR, 1);
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_MULTICAST,
@@ -7498,13 +7474,12 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all hw fields.
*/
- rt2x00dev->hw->flags =
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
+ ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_HT_CCK_RATES);
+ ieee80211_hw_set(rt2x00dev->hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(rt2x00dev->hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM);
+ ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS);
/*
* Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices
@@ -7514,8 +7489,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
* infinitly and thus dropping it after some time.
*/
if (!rt2x00_is_usb(rt2x00dev))
- rt2x00dev->hw->flags |=
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ ieee80211_hw_set(rt2x00dev->hw, HOST_BROADCAST_PS_BUFFERING);
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@@ -7818,21 +7792,25 @@ EXPORT_SYMBOL_GPL(rt2800_probe_hw);
/*
* IEEE80211 stack callback functions.
*/
-void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
- u16 *iv16)
+void rt2800_get_key_seq(struct ieee80211_hw *hw,
+ struct ieee80211_key_conf *key,
+ struct ieee80211_key_seq *seq)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct mac_iveiv_entry iveiv_entry;
u32 offset;
- offset = MAC_IVEIV_ENTRY(hw_key_idx);
+ if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
+ return;
+
+ offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
rt2800_register_multiread(rt2x00dev, offset,
&iveiv_entry, sizeof(iveiv_entry));
- memcpy(iv16, &iveiv_entry.iv[0], sizeof(*iv16));
- memcpy(iv32, &iveiv_entry.iv[4], sizeof(*iv32));
+ memcpy(&seq->tkip.iv16, &iveiv_entry.iv[0], 2);
+ memcpy(&seq->tkip.iv32, &iveiv_entry.iv[4], 4);
}
-EXPORT_SYMBOL_GPL(rt2800_get_tkip_seq);
+EXPORT_SYMBOL_GPL(rt2800_get_key_seq);
int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
@@ -7967,11 +7945,11 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
/*
* Don't allow aggregation for stations the hardware isn't aware
* of because tx status reports for frames to an unknown station
- * always contain wcid=255 and thus we can't distinguish between
- * multiple stations which leads to unwanted situations when the
- * hw reorders frames due to aggregation.
+ * always contain wcid=WCID_END+1 and thus we can't distinguish
+ * between multiple stations which leads to unwanted situations
+ * when the hw reorders frames due to aggregation.
*/
- if (sta_priv->wcid < 0)
+ if (sta_priv->wcid > WCID_END)
return 1;
switch (action) {
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 3019db637a4b..1609b8a7f7eb 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -209,8 +209,9 @@ int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev);
-void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
- u16 *iv16);
+void rt2800_get_key_seq(struct ieee80211_hw *hw,
+ struct ieee80211_key_conf *key,
+ struct ieee80211_key_seq *seq);
int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
int rt2800_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue_idx,
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index cc1b3cc73c5a..0af22573a2eb 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -309,7 +309,7 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = {
.sw_scan_start = rt2x00mac_sw_scan_start,
.sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
- .get_tkip_seq = rt2800_get_tkip_seq,
+ .get_key_seq = rt2800_get_key_seq,
.set_rts_threshold = rt2800_set_rts_threshold,
.sta_add = rt2x00mac_sta_add,
.sta_remove = rt2x00mac_sta_remove,
diff --git a/drivers/net/wireless/rt2x00/rt2800soc.c b/drivers/net/wireless/rt2x00/rt2800soc.c
index aaa7aa4cad9d..a985a5a7945e 100644
--- a/drivers/net/wireless/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/rt2x00/rt2800soc.c
@@ -148,7 +148,7 @@ static const struct ieee80211_ops rt2800soc_mac80211_ops = {
.sw_scan_start = rt2x00mac_sw_scan_start,
.sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
- .get_tkip_seq = rt2800_get_tkip_seq,
+ .get_key_seq = rt2800_get_key_seq,
.set_rts_threshold = rt2800_set_rts_threshold,
.sta_add = rt2x00mac_sta_add,
.sta_remove = rt2x00mac_sta_remove,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 6ec2466b52b6..5932306084fd 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -835,7 +835,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.sw_scan_start = rt2x00mac_sw_scan_start,
.sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
- .get_tkip_seq = rt2800_get_tkip_seq,
+ .get_key_seq = rt2800_get_key_seq,
.set_rts_threshold = rt2800_set_rts_threshold,
.sta_add = rt2x00mac_sta_add,
.sta_remove = rt2x00mac_sta_remove,
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 300876df056f..3c26ee65a415 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -359,8 +359,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
FIF_PLCPFAIL |
FIF_CONTROL |
FIF_PSPOLL |
- FIF_OTHER_BSS |
- FIF_PROMISC_IN_BSS;
+ FIF_OTHER_BSS;
/*
* Apply some rules to the filters:
@@ -369,9 +368,6 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
* - Multicast filter seems to kill broadcast traffic so never use it.
*/
*total_flags |= FIF_ALLMULTI;
- if (*total_flags & FIF_OTHER_BSS ||
- *total_flags & FIF_PROMISC_IN_BSS)
- *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
/*
* If the device has a single filter for all control frames,
@@ -539,16 +535,8 @@ int rt2x00mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta);
- /*
- * If there's no space left in the device table store
- * -1 as wcid but tell mac80211 everything went ok.
- */
- if (rt2x00dev->ops->lib->sta_add(rt2x00dev, vif, sta))
- sta_priv->wcid = -1;
-
- return 0;
+ return rt2x00dev->ops->lib->sta_add(rt2x00dev, vif, sta);
}
EXPORT_SYMBOL_GPL(rt2x00mac_sta_add);
@@ -558,12 +546,6 @@ int rt2x00mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta);
- /*
- * If we never sent the STA to the device no need to clean it up.
- */
- if (sta_priv->wcid < 0)
- return 0;
-
return rt2x00dev->ops->lib->sta_remove(rt2x00dev, sta_priv->wcid);
}
EXPORT_SYMBOL_GPL(rt2x00mac_sta_remove);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 819455009fe4..c0e730ea1b69 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -530,10 +530,8 @@ static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_PLCPFAIL));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
!(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
- rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
- !(filter_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME, 1);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
- !(filter_flags & FIF_PROMISC_IN_BSS) &&
!rt2x00dev->intf_ap_count);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
@@ -2760,11 +2758,10 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all hw fields.
*/
- rt2x00dev->hw->flags =
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK;
+ ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS);
+ ieee80211_hw_set(rt2x00dev->hw, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM);
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index a5458cf01fb2..7081e13b4fd6 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -480,10 +480,8 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_PLCPFAIL));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
!(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
- rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
- !(filter_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME, 1);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
- !(filter_flags & FIF_PROMISC_IN_BSS) &&
!rt2x00dev->intf_ap_count);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
@@ -2107,16 +2105,15 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all hw fields.
*
- * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING unless we are
+ * Don't set IEEE80211_HOST_BROADCAST_PS_BUFFERING unless we are
* capable of sending the buffered frames out after the DTIM
* transmission using rt2x00lib_beacondone. This will send out
* multicast and broadcast traffic immediately instead of buffering it
* infinitly and thus dropping it after some time.
*/
- rt2x00dev->hw->flags =
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK;
+ ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM);
+ ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS);
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c
index 706b844bce00..a43a16fde59d 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c
@@ -1802,8 +1802,9 @@ static int rtl8180_probe(struct pci_dev *pdev,
priv->band.n_bitrates = 4;
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
- dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_RX_INCLUDES_FCS;
+ ieee80211_hw_set(dev, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(dev, RX_INCLUDES_FCS);
+
dev->vif_data_size = sizeof(struct rtl8180_vif);
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
@@ -1868,9 +1869,9 @@ static int rtl8180_probe(struct pci_dev *pdev,
}
if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180)
- dev->flags |= IEEE80211_HW_SIGNAL_DBM;
+ ieee80211_hw_set(dev, SIGNAL_DBM);
else
- dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC;
+ ieee80211_hw_set(dev, SIGNAL_UNSPEC);
rtl8180_eeprom_read(priv);
diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c
index 629ad8cfa17b..b7f72f9c7988 100644
--- a/drivers/net/wireless/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c
@@ -1478,9 +1478,9 @@ static int rtl8187_probe(struct usb_interface *intf,
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
- dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_RX_INCLUDES_FCS;
+ ieee80211_hw_set(dev, RX_INCLUDES_FCS);
+ ieee80211_hw_set(dev, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(dev, SIGNAL_DBM);
/* Initialize rate-control variables */
dev->max_rates = 1;
dev->max_rate_tries = RETRY_COUNT;
diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig
index 5cf509d346e8..73067cac289c 100644
--- a/drivers/net/wireless/rtlwifi/Kconfig
+++ b/drivers/net/wireless/rtlwifi/Kconfig
@@ -100,7 +100,7 @@ config RTL8821AE
select RTLWIFI_PCI
select RTLBTCOEXIST
---help---
- This is the driver for Realtek RTL8i821AE/RTL8812AE 802.11av PCIe
+ This is the driver for Realtek RTL8821AE/RTL8812AE 802.11ac PCIe
wireless network adapters.
If you choose to build it as a module, it will be called rtl8821ae
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 01f56c7df8b5..0517a4f2d3f2 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -394,20 +394,18 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
}
}
/* <5> set hw caps */
- hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_CONNECTION_MONITOR |
- /* IEEE80211_HW_SUPPORTS_CQM_RSSI | */
- IEEE80211_HW_MFP_CAPABLE |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0;
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, CONNECTION_MONITOR);
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
/* swlps or hwlps has been set in diff chip in init_sw_vars */
- if (rtlpriv->psc.swctrl_lps)
- hw->flags |= IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK |
- /* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */
- 0;
+ if (rtlpriv->psc.swctrl_lps) {
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+ ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
+ }
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
index cefe26991421..f2b9d11adc9e 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
@@ -1286,8 +1286,11 @@ static void btc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec,
0x12, 0xe1, 0x90);
break;
case 3:
- btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c,
- 0x3, 0xf1, 0x90);
+ /* This call breaks BT when wireless is active -
+ * comment it out for now until a better fix is found:
+ * btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c,
+ * 0x3, 0xf1, 0x90);
+ */
break;
case 4:
btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x10,
diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h
index 82733c6b8c46..782ac2fc4b28 100644
--- a/drivers/net/wireless/rtlwifi/core.h
+++ b/drivers/net/wireless/rtlwifi/core.h
@@ -27,8 +27,7 @@
#define __RTL_CORE_H__
#define RTL_SUPPORTED_FILTERS \
- (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | FIF_CONTROL | \
+ (FIF_ALLMULTI | FIF_CONTROL | \
FIF_OTHER_BSS | \
FIF_FCSFAIL | \
FIF_BCN_PRBRESP_PROMISC)
diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c
index 1893d01b9e78..a62bf0a65c32 100644
--- a/drivers/net/wireless/rtlwifi/regd.c
+++ b/drivers/net/wireless/rtlwifi/regd.c
@@ -40,6 +40,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{COUNTRY_CODE_GLOBAL_DOMAIN, "JP"},
{COUNTRY_CODE_WORLD_WIDE_13, "EC"},
{COUNTRY_CODE_TELEC_NETGEAR, "EC"},
+ {COUNTRY_CODE_WORLD_WIDE_13_5G_ALL, "US"},
};
/*
@@ -124,6 +125,17 @@ static const struct ieee80211_regdomain rtl_regdom_14_60_64 = {
}
};
+static const struct ieee80211_regdomain rtl_regdom_12_13_5g_all = {
+ .n_reg_rules = 4,
+ .alpha2 = "99",
+ .reg_rules = {
+ RTL819x_2GHZ_CH01_11,
+ RTL819x_2GHZ_CH12_13,
+ RTL819x_5GHZ_5150_5350,
+ RTL819x_5GHZ_5470_5850,
+ }
+};
+
static const struct ieee80211_regdomain rtl_regdom_14 = {
.n_reg_rules = 3,
.alpha2 = "99",
@@ -348,6 +360,8 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select(
return &rtl_regdom_14_60_64;
case COUNTRY_CODE_GLOBAL_DOMAIN:
return &rtl_regdom_14;
+ case COUNTRY_CODE_WORLD_WIDE_13_5G_ALL:
+ return &rtl_regdom_12_13_5g_all;
default:
return &rtl_regdom_no_midband;
}
@@ -384,6 +398,25 @@ static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode)
return NULL;
}
+static u8 channel_plan_to_country_code(u8 channelplan)
+{
+ switch (channelplan) {
+ case 0x20:
+ case 0x21:
+ return COUNTRY_CODE_WORLD_WIDE_13;
+ case 0x22:
+ return COUNTRY_CODE_IC;
+ case 0x32:
+ return COUNTRY_CODE_TELEC_NETGEAR;
+ case 0x41:
+ return COUNTRY_CODE_GLOBAL_DOMAIN;
+ case 0x7f:
+ return COUNTRY_CODE_WORLD_WIDE_13_5G_ALL;
+ default:
+ return COUNTRY_CODE_MAX; /*Error*/
+ }
+}
+
int rtl_regd_init(struct ieee80211_hw *hw,
void (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request))
@@ -396,11 +429,12 @@ int rtl_regd_init(struct ieee80211_hw *hw,
return -EINVAL;
/* init country_code from efuse channel plan */
- rtlpriv->regd.country_code = rtlpriv->efuse.channel_plan;
+ rtlpriv->regd.country_code =
+ channel_plan_to_country_code(rtlpriv->efuse.channel_plan);
- RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE,
- "rtl: EEPROM regdomain: 0x%0x\n",
- rtlpriv->regd.country_code);
+ RT_TRACE(rtlpriv, COMP_REGD, DBG_DMESG,
+ "rtl: EEPROM regdomain: 0x%0x conuntry code: %d\n",
+ rtlpriv->efuse.channel_plan, rtlpriv->regd.country_code);
if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) {
RT_TRACE(rtlpriv, COMP_REGD, DBG_DMESG,
diff --git a/drivers/net/wireless/rtlwifi/regd.h b/drivers/net/wireless/rtlwifi/regd.h
index 3bbbaaa68530..f7f15bce35dd 100644
--- a/drivers/net/wireless/rtlwifi/regd.h
+++ b/drivers/net/wireless/rtlwifi/regd.h
@@ -49,6 +49,7 @@ enum country_code_type_t {
COUNTRY_CODE_GLOBAL_DOMAIN = 10,
COUNTRY_CODE_WORLD_WIDE_13 = 11,
COUNTRY_CODE_TELEC_NETGEAR = 12,
+ COUNTRY_CODE_WORLD_WIDE_13_5G_ALL = 13,
/*add new channel plan above this line */
COUNTRY_CODE_MAX
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
index d930c1f78721..ce4da9d79fbd 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
@@ -1123,23 +1123,22 @@ static void rtl88e_dm_init_txpower_tracking(struct ieee80211_hw *hw)
void rtl88e_dm_check_txpower_tracking(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- static u8 tm_trigger;
if (!rtlpriv->dm.txpower_tracking)
return;
- if (!tm_trigger) {
+ if (!rtlpriv->dm.tm_trigger) {
rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17)|BIT(16),
0x03);
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Trigger 88E Thermal Meter!!\n");
- tm_trigger = 1;
+ rtlpriv->dm.tm_trigger = 1;
return;
} else {
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Schedule TxPowerTracking !!\n");
dm_txpower_track_cb_therm(hw);
- tm_trigger = 0;
+ rtlpriv->dm.tm_trigger = 0;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
index 86ce5b1930e6..8ee83b093c0d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
@@ -1354,27 +1354,11 @@ void rtl88ee_set_qos(struct ieee80211_hw *hw, int aci)
}
}
-static void rtl88ee_clear_interrupt(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 tmp;
-
- tmp = rtl_read_dword(rtlpriv, REG_HISR);
- rtl_write_dword(rtlpriv, REG_HISR, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HISRE);
- rtl_write_dword(rtlpriv, REG_HISRE, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HSISR);
- rtl_write_dword(rtlpriv, REG_HSISR, tmp);
-}
-
void rtl88ee_enable_interrupt(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- rtl88ee_clear_interrupt(hw);/*clear it here first*/
rtl_write_dword(rtlpriv, REG_HIMR,
rtlpci->irq_mask[0] & 0xFFFFFFFF);
rtl_write_dword(rtlpriv, REG_HIMRE,
@@ -1919,8 +1903,8 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw)
"dev_addr: %pM\n", rtlefuse->dev_addr);
/*channel plan */
rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN];
- /* set channel paln to world wide 13 */
- rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+ /* set channel plan from efuse */
+ rtlefuse->channel_plan = rtlefuse->eeprom_channelplan;
/*tx power*/
_rtl88ee_read_txpower_info_from_hwpg(hw,
rtlefuse->autoload_failflag,
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c
index ef28c8ea1e84..02013df968a0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c
@@ -23,7 +23,7 @@
*
*****************************************************************************/
-#include "pwrseqcmd.h"
+#include "../pwrseqcmd.h"
#include "pwrseq.h"
/* drivers should parse below arrays and do the corresponding actions */
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
index 79103347d967..f2d9c6116e5c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
@@ -26,7 +26,7 @@
#ifndef __RTL8723E_PWRSEQ_H__
#define __RTL8723E_PWRSEQ_H__
-#include "pwrseqcmd.h"
+#include "../pwrseqcmd.h"
/* Check document WM-20110607-Paul-RTL8188EE_Power_Architecture-R02.vsd
* There are 6 HW Power States:
* 0: POFF--Power Off
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
index f5ee67cda73a..0aca6f47487c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
@@ -1169,23 +1169,22 @@ static void rtl92c_dm_check_txpower_tracking_thermal_meter(
struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- static u8 tm_trigger;
if (!rtlpriv->dm.txpower_tracking)
return;
- if (!tm_trigger) {
+ if (!rtlpriv->dm.tm_trigger) {
rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, RFREG_OFFSET_MASK,
0x60);
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Trigger 92S Thermal Meter!!\n");
- tm_trigger = 1;
+ rtlpriv->dm.tm_trigger = 1;
return;
} else {
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Schedule TxPowerTracking direct call!!\n");
rtl92c_dm_txpower_tracking_directcall(hw);
- tm_trigger = 0;
+ rtlpriv->dm.tm_trigger = 0;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
index 29983bc96a89..14b819ea8b71 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
@@ -233,13 +233,14 @@ int rtl92c_download_fw(struct ieee80211_hw *hw)
pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
pfwdata = (u8 *)rtlhal->pfirmware;
fwsize = rtlhal->fwsize;
-
if (IS_FW_HEADER_EXIST(pfwheader)) {
RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
"Firmware Version(%d), Signature(%#x),Size(%d)\n",
pfwheader->version, pfwheader->signature,
(int)sizeof(struct rtl92c_firmware_header));
+ rtlhal->fw_version = pfwheader->version;
+ rtlhal->fw_subversion = pfwheader->subversion;
pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
index d310d55d800e..767358a553fb 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
@@ -840,6 +840,26 @@ static void _rtl92cu_init_wmac_setting(struct ieee80211_hw *hw)
rtl92c_set_data_filter(hw, value16);
}
+static void _rtl92cu_init_beacon_parameters(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+
+ rtl_write_word(rtlpriv, REG_BCN_CTRL, 0x1010);
+
+ /* TODO: Remove these magic number */
+ rtl_write_word(rtlpriv, REG_TBTT_PROHIBIT, 0x6404);
+ rtl_write_byte(rtlpriv, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);
+ rtl_write_byte(rtlpriv, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME);
+ /* Change beacon AIFS to the largest number
+ * beacause test chip does not contension before sending beacon.
+ */
+ if (IS_NORMAL_CHIP(rtlhal->version))
+ rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660F);
+ else
+ rtl_write_word(rtlpriv, REG_BCNTCFG, 0x66FF);
+}
+
static int _rtl92cu_init_mac(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -887,9 +907,9 @@ static int _rtl92cu_init_mac(struct ieee80211_hw *hw)
_rtl92cu_init_usb_aggregation(hw);
rtlpriv->cfg->ops->set_bw_mode(hw, NL80211_CHAN_HT20);
rtl92c_set_min_space(hw, IS_92C_SERIAL(rtlhal->version));
- rtl92c_init_beacon_parameters(hw, rtlhal->version);
+ _rtl92cu_init_beacon_parameters(hw);
rtl92c_init_ampdu_aggregation(hw);
- rtl92c_init_beacon_max_error(hw, true);
+ rtl92c_init_beacon_max_error(hw);
return err;
}
@@ -987,7 +1007,6 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
struct rtl_phy *rtlphy = &(rtlpriv->phy);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
int err = 0;
- static bool iqk_initialized;
unsigned long flags;
/* As this function can take a very long time (up to 350 ms)
@@ -1038,11 +1057,11 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
if (ppsc->rfpwr_state == ERFON) {
rtl92c_phy_set_rfpath_switch(hw, 1);
- if (iqk_initialized) {
+ if (rtlphy->iqk_initialized) {
rtl92c_phy_iq_calibrate(hw, true);
} else {
rtl92c_phy_iq_calibrate(hw, false);
- iqk_initialized = true;
+ rtlphy->iqk_initialized = true;
}
rtl92c_dm_check_txpower_tracking(hw);
rtl92c_phy_lc_calibrate(hw);
@@ -1323,7 +1342,6 @@ static int _rtl92cu_set_media_status(struct ieee80211_hw *hw,
enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
bt_msr &= 0xfc;
- rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0xFF);
if (type == NL80211_IFTYPE_UNSPECIFIED || type ==
NL80211_IFTYPE_STATION) {
_rtl92cu_stop_tx_beacon(hw);
@@ -1392,6 +1410,9 @@ void rtl92cu_card_disable(struct ieee80211_hw *hw)
_CardDisableHWSM(hw);
else
_CardDisableWithoutHWSM(hw);
+
+ /* after power off we should do iqk again */
+ rtlpriv->phy.iqk_initialized = false;
}
void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
@@ -1452,25 +1473,6 @@ int rtl92cu_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)
return 0;
}
-static void _InitBeaconParameters(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-
- rtl_write_word(rtlpriv, REG_BCN_CTRL, 0x1010);
-
- /* TODO: Remove these magic number */
- rtl_write_word(rtlpriv, REG_TBTT_PROHIBIT, 0x6404);
- rtl_write_byte(rtlpriv, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);
- rtl_write_byte(rtlpriv, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME);
- /* Change beacon AIFS to the largest number
- * beacause test chip does not contension before sending beacon. */
- if (IS_NORMAL_CHIP(rtlhal->version))
- rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660F);
- else
- rtl_write_word(rtlpriv, REG_BCNTCFG, 0x66FF);
-}
-
static void _beacon_function_enable(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1491,7 +1493,7 @@ void rtl92cu_set_beacon_related_registers(struct ieee80211_hw *hw)
atim_window = 2; /*FIX MERGE */
rtl_write_word(rtlpriv, REG_ATIMWND, atim_window);
rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
- _InitBeaconParameters(hw);
+ _rtl92cu_init_beacon_parameters(hw);
rtl_write_byte(rtlpriv, REG_SLOT, 0x09);
/*
* Force beacon frame transmission even after receiving beacon frame
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
index adb810794eef..490a7cf7c702 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
@@ -613,7 +613,7 @@ void rtl92c_init_ampdu_aggregation(struct ieee80211_hw *hw)
rtl_write_word(rtlpriv, 0x4CA, 0x0708);
}
-void rtl92c_init_beacon_max_error(struct ieee80211_hw *hw, bool infra_mode)
+void rtl92c_init_beacon_max_error(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -641,21 +641,6 @@ void rtl92c_init_retry_function(struct ieee80211_hw *hw)
rtl_write_byte(rtlpriv, REG_ACKTO, 0x40);
}
-void rtl92c_init_beacon_parameters(struct ieee80211_hw *hw,
- enum version_8192c version)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-
- rtl_write_word(rtlpriv, REG_TBTT_PROHIBIT, 0x6404);/* ms */
- rtl_write_byte(rtlpriv, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);/*ms*/
- rtl_write_byte(rtlpriv, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME);
- if (IS_NORMAL_CHIP(rtlhal->version))
- rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660F);
- else
- rtl_write_word(rtlpriv, REG_BCNTCFG, 0x66FF);
-}
-
void rtl92c_disable_fast_edca(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h
index bf53652e4edd..e34f0f14ccd7 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h
@@ -66,13 +66,10 @@ void rtl92c_init_edca_param(struct ieee80211_hw *hw,
void rtl92c_init_edca(struct ieee80211_hw *hw);
void rtl92c_init_ampdu_aggregation(struct ieee80211_hw *hw);
-void rtl92c_init_beacon_max_error(struct ieee80211_hw *hw, bool infra_mode);
+void rtl92c_init_beacon_max_error(struct ieee80211_hw *hw);
void rtl92c_init_rdg_setting(struct ieee80211_hw *hw);
void rtl92c_init_retry_function(struct ieee80211_hw *hw);
-void rtl92c_init_beacon_parameters(struct ieee80211_hw *hw,
- enum version_8192c version);
-
void rtl92c_disable_fast_edca(struct ieee80211_hw *hw);
void rtl92c_set_min_space(struct ieee80211_hw *hw, bool is2T);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
index 12f6d474b492..c972fa50926d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
@@ -108,13 +108,8 @@ void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw,
bool rtl92cu_phy_mac_config(struct ieee80211_hw *hw)
{
bool rtstatus;
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- bool is92c = IS_92C_SERIAL(rtlhal->version);
rtstatus = _rtl92cu_phy_config_mac_with_headerfile(hw);
- if (is92c && IS_HARDWARE_TYPE_8192CE(rtlhal))
- rtl_write_byte(rtlpriv, 0x14, 0x71);
return rtstatus;
}
@@ -122,7 +117,6 @@ bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw)
{
bool rtstatus = true;
struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u16 regval;
u32 regval32;
u8 b_reg_hwparafile = 1;
@@ -134,17 +128,11 @@ bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw)
rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83);
rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb);
rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB);
- if (IS_HARDWARE_TYPE_8192CE(rtlhal)) {
- rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, FEN_PPLL | FEN_PCIEA |
- FEN_DIO_PCIE | FEN_BB_GLB_RSTn | FEN_BBRSTB);
- } else if (IS_HARDWARE_TYPE_8192CU(rtlhal)) {
- rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD |
- FEN_BB_GLB_RSTn | FEN_BBRSTB);
- }
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD |
+ FEN_BB_GLB_RSTn | FEN_BBRSTB);
regval32 = rtl_read_dword(rtlpriv, 0x87c);
rtl_write_dword(rtlpriv, 0x87c, regval32 & (~BIT(31)));
- if (IS_HARDWARE_TYPE_8192CU(rtlhal))
- rtl_write_byte(rtlpriv, REG_LDOHCI12_CTRL, 0x0f);
+ rtl_write_byte(rtlpriv, REG_LDOHCI12_CTRL, 0x0f);
rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80);
if (b_reg_hwparafile == 1)
rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw);
@@ -162,7 +150,7 @@ bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read Rtl819XMACPHY_Array\n");
arraylength = rtlphy->hwparam_tables[MAC_REG].length ;
ptrarray = rtlphy->hwparam_tables[MAC_REG].pdata;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Img:RTL8192CEMAC_2T_ARRAY\n");
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Img:RTL8192CUMAC_2T_ARRAY\n");
for (i = 0; i < arraylength; i = i + 2)
rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]);
return true;
@@ -259,18 +247,18 @@ bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
radiob_arraylen = rtlphy->hwparam_tables[RADIOB_2T].length;
radiob_array_table = rtlphy->hwparam_tables[RADIOB_2T].pdata;
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "Radio_A:RTL8192CERADIOA_2TARRAY\n");
+ "Radio_A:RTL8192CURADIOA_2TARRAY\n");
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "Radio_B:RTL8192CE_RADIOB_2TARRAY\n");
+ "Radio_B:RTL8192CU_RADIOB_2TARRAY\n");
} else {
radioa_arraylen = rtlphy->hwparam_tables[RADIOA_1T].length;
radioa_array_table = rtlphy->hwparam_tables[RADIOA_1T].pdata;
radiob_arraylen = rtlphy->hwparam_tables[RADIOB_1T].length;
radiob_array_table = rtlphy->hwparam_tables[RADIOB_1T].pdata;
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "Radio_A:RTL8192CE_RADIOA_1TARRAY\n");
+ "Radio_A:RTL8192CU_RADIOA_1TARRAY\n");
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "Radio_B:RTL8192CE_RADIOB_1TARRAY\n");
+ "Radio_B:RTL8192CU_RADIOB_1TARRAY\n");
}
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Radio No %x\n", rfpath);
switch (rfpath) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
index b878d56d2f4d..5624ade92cc0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
@@ -66,7 +66,6 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
- struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
u32 tx_agc[2] = { 0, 0 }, tmpval = 0;
@@ -74,14 +73,8 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
u8 idx1, idx2;
u8 *ptr;
- if (rtlhal->interface == INTF_PCI) {
- if (rtlefuse->eeprom_regulatory != 0)
- turbo_scanoff = true;
- } else {
- if ((rtlefuse->eeprom_regulatory != 0) ||
- (rtlefuse->external_pa))
- turbo_scanoff = true;
- }
+ if ((rtlefuse->eeprom_regulatory != 0) || (rtlefuse->external_pa))
+ turbo_scanoff = true;
if (mac->act_scanning) {
tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
@@ -90,11 +83,8 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
(ppowerlevel[idx1] << 8) |
(ppowerlevel[idx1] << 16) |
(ppowerlevel[idx1] << 24);
- if (rtlhal->interface == INTF_USB) {
- if (tx_agc[idx1] > 0x20 &&
- rtlefuse->external_pa)
- tx_agc[idx1] = 0x20;
- }
+ if (tx_agc[idx1] > 0x20 && rtlefuse->external_pa)
+ tx_agc[idx1] = 0x20;
}
} else {
if (rtlpriv->dm.dynamic_txhighpower_lvl ==
@@ -452,9 +442,6 @@ static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
udelay(1);
switch (rfpath) {
case RF90_PATH_A:
- rtstatus = rtl92cu_phy_config_rf_with_headerfile(hw,
- (enum radio_path) rfpath);
- break;
case RF90_PATH_B:
rtstatus = rtl92cu_phy_config_rf_with_headerfile(hw,
(enum radio_path) rfpath);
@@ -483,7 +470,6 @@ static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
}
}
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "<---\n");
- return rtstatus;
phy_rf_cfg_fail:
return rtstatus;
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index cbead007171f..95880fe4106e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -321,7 +321,7 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw,
stats->rate = (u8) GET_RX_DESC_RX_MCS(pdesc);
stats->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc);
stats->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
- stats->isampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1)
+ stats->isfirst_ampdu = (bool)((GET_RX_DESC_PAGGR(pdesc) == 1)
&& (GET_RX_DESC_FAGGR(pdesc) == 1));
stats->timestamp_low = GET_RX_DESC_TSFL(pdesc);
stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
index a1be5a68edfb..587b8c505a76 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
@@ -1240,23 +1240,22 @@ static void rtl92d_dm_initialize_txpower_tracking(struct ieee80211_hw *hw)
void rtl92d_dm_check_txpower_tracking_thermal_meter(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- static u8 tm_trigger;
if (!rtlpriv->dm.txpower_tracking)
return;
- if (!tm_trigger) {
+ if (!rtlpriv->dm.tm_trigger) {
rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17) |
BIT(16), 0x03);
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Trigger 92S Thermal Meter!!\n");
- tm_trigger = 1;
+ rtlpriv->dm.tm_trigger = 1;
return;
} else {
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Schedule TxPowerTracking direct call!!\n");
rtl92d_dm_txpower_tracking_callback_thermalmeter(hw);
- tm_trigger = 0;
+ rtlpriv->dm.tm_trigger = 0;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c
index c5d4b8013cde..232865cc3ffd 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c
@@ -875,7 +875,7 @@ static void _rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id,
break;
default:
RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
- "[C2H], Unkown packet!! CmdId(%#X)!\n", c2h_cmd_id);
+ "[C2H], Unknown packet!! CmdId(%#X)!\n", c2h_cmd_id);
break;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c
index da0a6125f314..5f14308e8eb3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c
@@ -1584,28 +1584,11 @@ void rtl92ee_set_qos(struct ieee80211_hw *hw, int aci)
}
}
-static void rtl92ee_clear_interrupt(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 tmp;
-
- tmp = rtl_read_dword(rtlpriv, REG_HISR);
- rtl_write_dword(rtlpriv, REG_HISR, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HISRE);
- rtl_write_dword(rtlpriv, REG_HISRE, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HSISR);
- rtl_write_dword(rtlpriv, REG_HSISR, tmp);
-}
-
void rtl92ee_enable_interrupt(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- rtl92ee_clear_interrupt(hw);/*clear it here first*/
-
rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
rtlpci->irq_enabled = true;
@@ -2194,8 +2177,8 @@ static void _rtl92ee_read_adapter_info(struct ieee80211_hw *hw)
"dev_addr: %pM\n", rtlefuse->dev_addr);
/*channel plan */
rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
- /* set channel paln to world wide 13 */
- rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+ /* set channel plan from efuse */
+ rtlefuse->channel_plan = rtlefuse->eeprom_channelplan;
/*tx power*/
_rtl92ee_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag,
hwinfo);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
index 575980b88658..9bae5a92e30f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
@@ -200,7 +200,6 @@ static void _rtl92s_dm_check_txpowertracking_thermalmeter(
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
- static u8 tm_trigger;
u8 tx_power_checkcnt = 5;
/* 2T2R TP issue */
@@ -215,13 +214,13 @@ static void _rtl92s_dm_check_txpowertracking_thermalmeter(
return;
}
- if (!tm_trigger) {
+ if (!rtlpriv->dm.tm_trigger) {
rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER,
RFREG_OFFSET_MASK, 0x60);
- tm_trigger = 1;
+ rtlpriv->dm.tm_trigger = 1;
} else {
_rtl92s_dm_txpowertracking_callback_thermalmeter(hw);
- tm_trigger = 0;
+ rtlpriv->dm.tm_trigger = 0;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
index 67bb47d77b68..a4b7eac6856f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
@@ -1258,18 +1258,6 @@ void rtl8723e_set_qos(struct ieee80211_hw *hw, int aci)
}
}
-static void rtl8723e_clear_interrupt(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 tmp;
-
- tmp = rtl_read_dword(rtlpriv, REG_HISR);
- rtl_write_dword(rtlpriv, REG_HISR, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HISRE);
- rtl_write_dword(rtlpriv, REG_HISRE, tmp);
-}
-
void rtl8723e_enable_interrupt(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1284,7 +1272,6 @@ void rtl8723e_disable_interrupt(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- rtl8723e_clear_interrupt(hw);/*clear it here first*/
rtl_write_dword(rtlpriv, 0x3a8, IMR8190_DISABLED);
rtl_write_dword(rtlpriv, 0x3ac, IMR8190_DISABLED);
rtlpci->irq_enabled = false;
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c
index e77c3a46c94a..3a81cdba8ca3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c
@@ -909,23 +909,22 @@ static void rtl8723be_dm_txpower_tracking_callback_thermalmeter(
void rtl8723be_dm_check_txpower_tracking(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- static u8 tm_trigger;
if (!rtlpriv->dm.txpower_tracking)
return;
- if (!tm_trigger) {
+ if (!rtlpriv->dm.tm_trigger) {
rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17) | BIT(16),
0x03);
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Trigger 8723be Thermal Meter!!\n");
- tm_trigger = 1;
+ rtlpriv->dm.tm_trigger = 1;
return;
} else {
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Schedule TxPowerTracking !!\n");
rtl8723be_dm_txpower_tracking_callback_thermalmeter(hw);
- tm_trigger = 0;
+ rtlpriv->dm.tm_trigger = 0;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/rtlwifi/rtl8723be/fw.c
index 69d4f0fc1af1..d5da0f3c1217 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/fw.c
@@ -613,7 +613,7 @@ static void _rtl8723be_c2h_content_parsing(struct ieee80211_hw *hw,
break;
default:
RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
- "[C2H], Unkown packet!! CmdId(%#X)!\n", c2h_cmd_id);
+ "[C2H], Unknown packet!! CmdId(%#X)!\n", c2h_cmd_id);
break;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c
index b681af3c7a35..c983d2fe147f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c
@@ -1634,28 +1634,11 @@ void rtl8723be_set_qos(struct ieee80211_hw *hw, int aci)
}
}
-static void rtl8723be_clear_interrupt(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 tmp;
-
- tmp = rtl_read_dword(rtlpriv, REG_HISR);
- rtl_write_dword(rtlpriv, REG_HISR, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HISRE);
- rtl_write_dword(rtlpriv, REG_HISRE, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HSISR);
- rtl_write_dword(rtlpriv, REG_HSISR, tmp);
-}
-
void rtl8723be_enable_interrupt(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- rtl8723be_clear_interrupt(hw);/*clear it here first*/
-
rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
rtlpci->irq_enabled = true;
@@ -2139,8 +2122,8 @@ static void _rtl8723be_read_adapter_info(struct ieee80211_hw *hw,
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
"EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);
- /* set channel plan to world wide 13 */
- rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+ /* set channel plan from efuse */
+ rtlefuse->channel_plan = rtlefuse->eeprom_channelplan;
if (rtlhal->oem_id == RT_CID_DEFAULT) {
/* Does this one have a Toshiba SMID from group 1? */
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c
index 342678d2ed42..b57cfd965196 100644
--- a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c
@@ -1068,20 +1068,18 @@ static void rtl8812ae_dm_check_txpower_tracking_thermalmeter(
struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- static u8 tm_trigger;
- if (!tm_trigger) {
+ if (!rtlpriv->dm.tm_trigger) {
rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER_88E,
BIT(17) | BIT(16), 0x03);
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Trigger 8812 Thermal Meter!!\n");
- tm_trigger = 1;
+ rtlpriv->dm.tm_trigger = 1;
return;
}
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Schedule TxPowerTracking direct call!!\n");
rtl8812ae_dm_txpower_tracking_callback_thermalmeter(hw);
- tm_trigger = 0;
}
static void rtl8821ae_dm_iq_calibrate(struct ieee80211_hw *hw)
@@ -2519,21 +2517,19 @@ void rtl8821ae_dm_txpower_tracking_callback_thermalmeter(
void rtl8821ae_dm_check_txpower_tracking_thermalmeter(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- static u8 tm_trigger;
-
- if (!tm_trigger) {
+ if (!rtlpriv->dm.tm_trigger) {
rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER_88E, BIT(17)|BIT(16),
0x03);
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Trigger 8821ae Thermal Meter!!\n");
- tm_trigger = 1;
+ rtlpriv->dm.tm_trigger = 1;
return;
} else {
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Schedule TxPowerTracking !!\n");
rtl8821ae_dm_txpower_tracking_callback_thermalmeter(hw);
- tm_trigger = 0;
+ rtlpriv->dm.tm_trigger = 0;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c
index 8704eee9f3a4..3236d44b459d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c
@@ -2253,31 +2253,11 @@ void rtl8821ae_set_qos(struct ieee80211_hw *hw, int aci)
}
}
-static void rtl8821ae_clear_interrupt(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 tmp;
- tmp = rtl_read_dword(rtlpriv, REG_HISR);
- /*printk("clear interrupt first:\n");
- printk("0x%x = 0x%08x\n",REG_HISR, tmp);*/
- rtl_write_dword(rtlpriv, REG_HISR, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HISRE);
- /*printk("0x%x = 0x%08x\n",REG_HISRE, tmp);*/
- rtl_write_dword(rtlpriv, REG_HISRE, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HSISR);
- /*printk("0x%x = 0x%08x\n",REG_HSISR, tmp);*/
- rtl_write_dword(rtlpriv, REG_HSISR, tmp);
-}
-
void rtl8821ae_enable_interrupt(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- rtl8821ae_clear_interrupt(hw);/*clear it here first*/
-
rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
rtlpci->irq_enabled = true;
@@ -3232,8 +3212,8 @@ static void _rtl8821ae_read_adapter_info(struct ieee80211_hw *hw, bool b_pseudo_
if (rtlefuse->eeprom_channelplan == 0xff)
rtlefuse->eeprom_channelplan = 0x7F;
- /* set channel paln to world wide 13 */
- /* rtlefuse->channel_plan = (u8)rtlefuse->eeprom_channelplan; */
+ /* set channel plan from efuse */
+ rtlefuse->channel_plan = rtlefuse->eeprom_channelplan;
/*parse xtal*/
rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_8821AE];
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 51572912c53d..2b770b5e2620 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -1665,6 +1665,7 @@ struct rtl_dm {
u8 last_dtp_lvl;
u8 thermalvalue_avg[AVG_THERMAL_NUM];
u8 thermalvalue_avg_index;
+ u8 tm_trigger;
bool done_txpower;
u8 dynamic_txhighpower_lvl; /*Tx high power level */
u8 dm_flag; /*Indicate each dynamic mechanism's status. */
diff --git a/drivers/net/wireless/ti/wl1251/acx.c b/drivers/net/wireless/ti/wl1251/acx.c
index 5695628757ee..d6fbdda2cba3 100644
--- a/drivers/net/wireless/ti/wl1251/acx.c
+++ b/drivers/net/wireless/ti/wl1251/acx.c
@@ -53,10 +53,7 @@ int wl1251_acx_station_id(struct wl1251 *wl)
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;
}
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 5d54d16a59e7..cd4777954f87 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -763,8 +763,7 @@ static u64 wl1251_op_prepare_multicast(struct ieee80211_hw *hw,
return (u64)(unsigned long)fp;
}
-#define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | \
+#define WL1251_SUPPORTED_FILTERS (FIF_ALLMULTI | \
FIF_FCSFAIL | \
FIF_BCN_PRBRESP_PROMISC | \
FIF_CONTROL | \
@@ -795,10 +794,6 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
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;
- wl->rx_config |= CFG_RX_ALL_GOOD;
- }
if (*total & FIF_ALLMULTI)
/*
* CFG_MC_FILTER_EN in rx_config needs to be 0 to receive
@@ -825,7 +820,7 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- if (*total & FIF_ALLMULTI || *total & FIF_PROMISC_IN_BSS)
+ if (*total & FIF_ALLMULTI)
ret = wl1251_acx_group_address_tbl(wl, false, NULL, 0);
else if (fp)
ret = wl1251_acx_group_address_tbl(wl, fp->enabled,
@@ -1481,7 +1476,8 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
/* unit us */
/* FIXME: find a proper value */
- wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS;
+ ieee80211_hw_set(wl->hw, SIGNAL_DBM);
+ ieee80211_hw_set(wl->hw, SUPPORTS_PS);
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 717c4f5a02c2..49aca2cf7605 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -24,6 +24,7 @@
#include <linux/ip.h>
#include <linux/firmware.h>
#include <linux/etherdevice.h>
+#include <linux/irq.h>
#include "../wlcore/wlcore.h"
#include "../wlcore/debug.h"
@@ -578,7 +579,7 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = {
[PART_TOP_PRCM_ELP_SOC] = {
- .mem = { .start = 0x00A02000, .size = 0x00010000 },
+ .mem = { .start = 0x00A00000, .size = 0x00012000 },
.reg = { .start = 0x00807000, .size = 0x00005000 },
.mem2 = { .start = 0x00800000, .size = 0x0000B000 },
.mem3 = { .start = 0x00000000, .size = 0x00000000 },
@@ -862,6 +863,7 @@ static int wl18xx_pre_upload(struct wl1271 *wl)
{
u32 tmp;
int ret;
+ u16 irq_invert;
BUILD_BUG_ON(sizeof(struct wl18xx_mac_and_phy_params) >
WL18XX_PHY_INIT_MEM_SIZE);
@@ -911,6 +913,28 @@ static int wl18xx_pre_upload(struct wl1271 *wl)
/* re-enable FDSP clock */
ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
MEM_FDSP_CLK_120_ENABLE);
+ if (ret < 0)
+ goto out;
+
+ ret = irq_get_trigger_type(wl->irq);
+ if ((ret == IRQ_TYPE_LEVEL_LOW) || (ret == IRQ_TYPE_EDGE_FALLING)) {
+ wl1271_info("using inverted interrupt logic: %d", ret);
+ ret = wlcore_set_partition(wl,
+ &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
+ if (ret < 0)
+ goto out;
+
+ ret = wl18xx_top_reg_read(wl, TOP_FN0_CCCR_REG_32, &irq_invert);
+ if (ret < 0)
+ goto out;
+
+ irq_invert |= BIT(1);
+ ret = wl18xx_top_reg_write(wl, TOP_FN0_CCCR_REG_32, irq_invert);
+ if (ret < 0)
+ goto out;
+
+ ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
+ }
out:
return ret;
@@ -1351,9 +1375,10 @@ out:
}
#define WL18XX_CONF_FILE_NAME "ti-connectivity/wl18xx-conf.bin"
-static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
+
+static int wl18xx_load_conf_file(struct device *dev, struct wlcore_conf *conf,
+ struct wl18xx_priv_conf *priv_conf)
{
- struct wl18xx_priv *priv = wl->priv;
struct wlcore_conf_file *conf_file;
const struct firmware *fw;
int ret;
@@ -1362,14 +1387,14 @@ static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
if (ret < 0) {
wl1271_error("could not get configuration binary %s: %d",
WL18XX_CONF_FILE_NAME, ret);
- goto out_fallback;
+ return ret;
}
if (fw->size != WL18XX_CONF_SIZE) {
wl1271_error("configuration binary file size is wrong, expected %zu got %zu",
WL18XX_CONF_SIZE, fw->size);
ret = -EINVAL;
- goto out;
+ goto out_release;
}
conf_file = (struct wlcore_conf_file *) fw->data;
@@ -1379,7 +1404,7 @@ static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
"expected 0x%0x got 0x%0x", WL18XX_CONF_MAGIC,
conf_file->header.magic);
ret = -EINVAL;
- goto out;
+ goto out_release;
}
if (conf_file->header.version != cpu_to_le32(WL18XX_CONF_VERSION)) {
@@ -1387,28 +1412,32 @@ static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
"expected 0x%08x got 0x%08x",
WL18XX_CONF_VERSION, conf_file->header.version);
ret = -EINVAL;
- goto out;
+ goto out_release;
}
- memcpy(&wl->conf, &conf_file->core, sizeof(wl18xx_conf));
- memcpy(&priv->conf, &conf_file->priv, sizeof(priv->conf));
+ memcpy(conf, &conf_file->core, sizeof(*conf));
+ memcpy(priv_conf, &conf_file->priv, sizeof(*priv_conf));
+
+out_release:
+ release_firmware(fw);
+ return ret;
+}
- goto out;
+static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
+{
+ struct wl18xx_priv *priv = wl->priv;
-out_fallback:
- wl1271_warning("falling back to default config");
+ if (wl18xx_load_conf_file(dev, &wl->conf, &priv->conf) < 0) {
+ wl1271_warning("falling back to default config");
- /* apply driver default configuration */
- memcpy(&wl->conf, &wl18xx_conf, sizeof(wl18xx_conf));
- /* apply default private configuration */
- memcpy(&priv->conf, &wl18xx_default_priv_conf, sizeof(priv->conf));
+ /* apply driver default configuration */
+ memcpy(&wl->conf, &wl18xx_conf, sizeof(wl->conf));
+ /* apply default private configuration */
+ memcpy(&priv->conf, &wl18xx_default_priv_conf,
+ sizeof(priv->conf));
+ }
- /* For now we just fallback */
return 0;
-
-out:
- release_firmware(fw);
- return ret;
}
static int wl18xx_plt_init(struct wl1271 *wl)
diff --git a/drivers/net/wireless/ti/wl18xx/reg.h b/drivers/net/wireless/ti/wl18xx/reg.h
index a433a75f3cd7..bac2364c8e72 100644
--- a/drivers/net/wireless/ti/wl18xx/reg.h
+++ b/drivers/net/wireless/ti/wl18xx/reg.h
@@ -109,6 +109,7 @@
#define WL18XX_WELP_ARM_COMMAND (WL18XX_REGISTERS_BASE + 0x7100)
#define WL18XX_ENABLE (WL18XX_REGISTERS_BASE + 0x01543C)
+#define TOP_FN0_CCCR_REG_32 (WL18XX_TOP_OCP_BASE + 0x64)
/* PRCM registers */
#define PLATFORM_DETECTION 0xA0E3E0
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 0be807951afe..337223b9f6f8 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -3175,8 +3175,7 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
return (u64)(unsigned long)fp;
}
-#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | \
+#define WL1271_SUPPORTED_FILTERS (FIF_ALLMULTI | \
FIF_FCSFAIL | \
FIF_BCN_PRBRESP_PROMISC | \
FIF_CONTROL | \
@@ -5966,10 +5965,6 @@ static int wl12xx_get_hw_info(struct wl1271 *wl)
{
int ret;
- ret = wl12xx_set_power_on(wl);
- if (ret < 0)
- return ret;
-
ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &wl->chip.id);
if (ret < 0)
goto out;
@@ -5985,7 +5980,6 @@ static int wl12xx_get_hw_info(struct wl1271 *wl)
ret = wl->ops->get_mac(wl);
out:
- wl1271_power_off(wl);
return ret;
}
@@ -6066,18 +6060,19 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
/* FIXME: find a proper value */
wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
- wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_HAS_RATE_CONTROL |
- IEEE80211_HW_CONNECTION_MONITOR |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_AP_LINK_PS |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
- IEEE80211_HW_QUEUE_CONTROL |
- IEEE80211_HW_CHANCTX_STA_CSA;
+ ieee80211_hw_set(wl->hw, SUPPORT_FAST_XMIT);
+ ieee80211_hw_set(wl->hw, CHANCTX_STA_CSA);
+ ieee80211_hw_set(wl->hw, QUEUE_CONTROL);
+ ieee80211_hw_set(wl->hw, TX_AMPDU_SETUP_IN_HW);
+ ieee80211_hw_set(wl->hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(wl->hw, AP_LINK_PS);
+ ieee80211_hw_set(wl->hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(wl->hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(wl->hw, CONNECTION_MONITOR);
+ ieee80211_hw_set(wl->hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(wl->hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(wl->hw, SIGNAL_DBM);
+ ieee80211_hw_set(wl->hw, SUPPORTS_PS);
wl->hw->wiphy->cipher_suites = cipher_suites;
wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
@@ -6432,10 +6427,22 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
else
wl->irq_flags |= IRQF_ONESHOT;
+ ret = wl12xx_set_power_on(wl);
+ if (ret < 0)
+ goto out_free_nvs;
+
+ ret = wl12xx_get_hw_info(wl);
+ if (ret < 0) {
+ wl1271_error("couldn't get hw info");
+ wl1271_power_off(wl);
+ goto out_free_nvs;
+ }
+
ret = request_threaded_irq(wl->irq, hardirq_fn, wlcore_irq,
wl->irq_flags, pdev->name, wl);
if (ret < 0) {
- wl1271_error("request_irq() failed: %d", ret);
+ wl1271_error("interrupt configuration failed");
+ wl1271_power_off(wl);
goto out_free_nvs;
}
@@ -6449,12 +6456,7 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
}
#endif
disable_irq(wl->irq);
-
- ret = wl12xx_get_hw_info(wl);
- if (ret < 0) {
- wl1271_error("couldn't get hw info");
- goto out_irq;
- }
+ wl1271_power_off(wl);
ret = wl->ops->identify_chip(wl);
if (ret < 0)
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index e7af261e9198..e539d9b1b562 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -1230,7 +1230,7 @@ static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw,
}
#define SUPPORTED_FIF_FLAGS \
- (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \
+ (FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \
FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)
static void zd_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
@@ -1256,7 +1256,7 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw,
* we will have some issue with IPv6 which uses multicast for link
* layer address resolution.
*/
- if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI))
+ if (*new_flags & FIF_ALLMULTI)
zd_mc_add_all(&hash);
spin_lock_irqsave(&mac->lock, flags);
@@ -1397,10 +1397,10 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band;
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_UNSPEC |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_MFP_CAPABLE;
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+ ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, SIGNAL_UNSPEC);
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_MESH_POINT) |
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 0d2594395ffb..5485f91294e7 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -52,7 +52,7 @@
* event channels are limited resource. Split event channels are
* enabled by default.
*/
-bool separate_tx_rx_irq = 1;
+bool separate_tx_rx_irq = true;
module_param(separate_tx_rx_irq, bool, 0644);
/* The time that packets can stay on the guest Rx internal queue
@@ -515,14 +515,9 @@ static void xenvif_rx_action(struct xenvif_queue *queue)
while (xenvif_rx_ring_slots_available(queue, XEN_NETBK_RX_SLOTS_MAX)
&& (skb = xenvif_rx_dequeue(queue)) != NULL) {
- RING_IDX old_req_cons;
- RING_IDX ring_slots_used;
-
queue->last_rx_time = jiffies;
- old_req_cons = queue->rx.req_cons;
XENVIF_RX_CB(skb)->meta_slots_used = xenvif_gop_skb(skb, &npo, queue);
- ring_slots_used = queue->rx.req_cons - old_req_cons;
__skb_queue_tail(&rxq, skb);
}
@@ -753,7 +748,7 @@ static int xenvif_count_requests(struct xenvif_queue *queue,
slots++;
if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
- netdev_err(queue->vif->dev, "Cross page boundary, txp->offset: %x, size: %u\n",
+ netdev_err(queue->vif->dev, "Cross page boundary, txp->offset: %u, size: %u\n",
txp->offset, txp->size);
xenvif_fatal_tx_err(queue->vif);
return -EINVAL;
@@ -879,7 +874,7 @@ static inline void xenvif_grant_handle_set(struct xenvif_queue *queue,
if (unlikely(queue->grant_tx_handle[pending_idx] !=
NETBACK_INVALID_HANDLE)) {
netdev_err(queue->vif->dev,
- "Trying to overwrite active handle! pending_idx: %x\n",
+ "Trying to overwrite active handle! pending_idx: 0x%x\n",
pending_idx);
BUG();
}
@@ -892,7 +887,7 @@ static inline void xenvif_grant_handle_reset(struct xenvif_queue *queue,
if (unlikely(queue->grant_tx_handle[pending_idx] ==
NETBACK_INVALID_HANDLE)) {
netdev_err(queue->vif->dev,
- "Trying to unmap invalid handle! pending_idx: %x\n",
+ "Trying to unmap invalid handle! pending_idx: 0x%x\n",
pending_idx);
BUG();
}
@@ -1248,7 +1243,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
/* No crossing a page as the payload mustn't fragment. */
if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
netdev_err(queue->vif->dev,
- "txreq.offset: %x, size: %u, end: %lu\n",
+ "txreq.offset: %u, size: %u, end: %lu\n",
txreq.offset, txreq.size,
(unsigned long)(txreq.offset&~PAGE_MASK) + txreq.size);
xenvif_fatal_tx_err(queue->vif);
@@ -1598,12 +1593,12 @@ static inline void xenvif_tx_dealloc_action(struct xenvif_queue *queue)
queue->pages_to_unmap,
gop - queue->tx_unmap_ops);
if (ret) {
- netdev_err(queue->vif->dev, "Unmap fail: nr_ops %tx ret %d\n",
+ netdev_err(queue->vif->dev, "Unmap fail: nr_ops %tu ret %d\n",
gop - queue->tx_unmap_ops, ret);
for (i = 0; i < gop - queue->tx_unmap_ops; ++i) {
if (gop[i].status != GNTST_okay)
netdev_err(queue->vif->dev,
- " host_addr: %llx handle: %x status: %d\n",
+ " host_addr: 0x%llx handle: 0x%x status: %d\n",
gop[i].host_addr,
gop[i].handle,
gop[i].status);
@@ -1736,7 +1731,7 @@ void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx)
&queue->mmap_pages[pending_idx], 1);
if (ret) {
netdev_err(queue->vif->dev,
- "Unmap fail: ret: %d pending_idx: %d host_addr: %llx handle: %x status: %d\n",
+ "Unmap fail: ret: %d pending_idx: %d host_addr: %llx handle: 0x%x status: %d\n",
ret,
pending_idx,
tx_unmap_op.host_addr,
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
index 968787abf78d..ec383b0f5443 100644
--- a/drivers/net/xen-netback/xenbus.c
+++ b/drivers/net/xen-netback/xenbus.c
@@ -681,6 +681,9 @@ static int xen_register_watchers(struct xenbus_device *dev, struct xenvif *vif)
char *node;
unsigned maxlen = strlen(dev->nodename) + sizeof("/rate");
+ if (vif->credit_watch.node)
+ return -EADDRINUSE;
+
node = kmalloc(maxlen, GFP_KERNEL);
if (!node)
return -ENOMEM;
@@ -770,6 +773,7 @@ static void connect(struct backend_info *be)
}
xen_net_read_rate(dev, &credit_bytes, &credit_usec);
+ xen_unregister_watchers(be->vif);
xen_register_watchers(dev, be->vif);
read_xenbus_vif_flags(be);
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index e031c943286e..56d8afd11077 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -733,7 +733,7 @@ static int xennet_get_responses(struct netfront_queue *queue,
if (unlikely(rx->status < 0 ||
rx->offset + rx->status > PAGE_SIZE)) {
if (net_ratelimit())
- dev_warn(dev, "rx->offset: %x, size: %u\n",
+ dev_warn(dev, "rx->offset: %u, size: %d\n",
rx->offset, rx->status);
xennet_move_rx_slot(queue, skb, ref);
err = -EINVAL;
@@ -1560,9 +1560,8 @@ static int xennet_init_queue(struct netfront_queue *queue)
spin_lock_init(&queue->tx_lock);
spin_lock_init(&queue->rx_lock);
- init_timer(&queue->rx_refill_timer);
- queue->rx_refill_timer.data = (unsigned long)queue;
- queue->rx_refill_timer.function = rx_refill_timeout;
+ setup_timer(&queue->rx_refill_timer, rx_refill_timeout,
+ (unsigned long)queue);
snprintf(queue->name, sizeof(queue->name), "%s-q%u",
queue->info->netdev->name, queue->id);
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index 107714e4405f..722673cb785b 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -72,6 +72,6 @@ source "drivers/nfc/pn544/Kconfig"
source "drivers/nfc/microread/Kconfig"
source "drivers/nfc/nfcmrvl/Kconfig"
source "drivers/nfc/st21nfca/Kconfig"
-source "drivers/nfc/st21nfcb/Kconfig"
+source "drivers/nfc/st-nci/Kconfig"
source "drivers/nfc/nxp-nci/Kconfig"
endmenu
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index a4292d790f9b..368b6dfe71b3 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -12,7 +12,5 @@ obj-$(CONFIG_NFC_PORT100) += port100.o
obj-$(CONFIG_NFC_MRVL) += nfcmrvl/
obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o
obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/
-obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb/
+obj-$(CONFIG_NFC_ST_NCI) += st-nci/
obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci/
-
-ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/microread/i2c.c b/drivers/nfc/microread/i2c.c
index 661e2c8143c4..daf352597ef8 100644
--- a/drivers/nfc/microread/i2c.c
+++ b/drivers/nfc/microread/i2c.c
@@ -211,7 +211,6 @@ flush:
static irqreturn_t microread_i2c_irq_thread_fn(int irq, void *phy_id)
{
struct microread_i2c_phy *phy = phy_id;
- struct i2c_client *client;
struct sk_buff *skb = NULL;
int r;
@@ -220,8 +219,6 @@ static irqreturn_t microread_i2c_irq_thread_fn(int irq, void *phy_id)
return IRQ_NONE;
}
- client = phy->i2c_dev;
-
if (phy->hard_fault != 0)
return IRQ_HANDLED;
diff --git a/drivers/nfc/nfcmrvl/Kconfig b/drivers/nfc/nfcmrvl/Kconfig
index 5e18afd9abe2..796be2411440 100644
--- a/drivers/nfc/nfcmrvl/Kconfig
+++ b/drivers/nfc/nfcmrvl/Kconfig
@@ -21,3 +21,14 @@ config NFC_MRVL_USB
Say Y here to compile support for Marvell NFC-over-USB driver
into the kernel or say M to compile it as module.
+
+config NFC_MRVL_UART
+ tristate "Marvell NFC-over-UART driver"
+ depends on NFC_MRVL && NFC_NCI_UART
+ help
+ Marvell NFC-over-UART driver.
+
+ This driver provides support for Marvell NFC-over-UART devices
+
+ Say Y here to compile support for Marvell NFC-over-UART driver
+ into the kernel or say M to compile it as module.
diff --git a/drivers/nfc/nfcmrvl/Makefile b/drivers/nfc/nfcmrvl/Makefile
index 97a0de72dc01..775196274d1f 100644
--- a/drivers/nfc/nfcmrvl/Makefile
+++ b/drivers/nfc/nfcmrvl/Makefile
@@ -7,3 +7,6 @@ obj-$(CONFIG_NFC_MRVL) += nfcmrvl.o
nfcmrvl_usb-y += usb.o
obj-$(CONFIG_NFC_MRVL_USB) += nfcmrvl_usb.o
+
+nfcmrvl_uart-y += uart.o
+obj-$(CONFIG_NFC_MRVL_UART) += nfcmrvl_uart.o
diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c
index ad4933cefbd1..4a8866d62941 100644
--- a/drivers/nfc/nfcmrvl/main.c
+++ b/drivers/nfc/nfcmrvl/main.c
@@ -17,6 +17,9 @@
*/
#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/of_gpio.h>
#include <linux/nfc.h>
#include <net/nfc/nci.h>
#include <net/nfc/nci_core.h>
@@ -63,20 +66,25 @@ static int nfcmrvl_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
if (!test_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
return -EBUSY;
+ if (priv->config.hci_muxed) {
+ unsigned char *hdr;
+ unsigned char len = skb->len;
+
+ hdr = (char *) skb_push(skb, NFCMRVL_HCI_EVENT_HEADER_SIZE);
+ hdr[0] = NFCMRVL_HCI_COMMAND_CODE;
+ hdr[1] = NFCMRVL_HCI_OGF;
+ hdr[2] = NFCMRVL_HCI_OCF;
+ hdr[3] = len;
+ }
+
return priv->if_ops->nci_send(priv, skb);
}
static int nfcmrvl_nci_setup(struct nci_dev *ndev)
{
- __u8 val;
-
- val = NFCMRVL_GPIO_PIN_NFC_NOT_ALLOWED;
- nci_set_config(ndev, NFCMRVL_NOT_ALLOWED_ID, 1, &val);
- val = NFCMRVL_GPIO_PIN_NFC_ACTIVE;
- nci_set_config(ndev, NFCMRVL_ACTIVE_ID, 1, &val);
- val = NFCMRVL_EXT_COEX_ENABLE;
- nci_set_config(ndev, NFCMRVL_EXT_COEX_ID, 1, &val);
+ __u8 val = 1;
+ nci_set_config(ndev, NFCMRVL_PB_BAIL_OUT, 1, &val);
return 0;
}
@@ -88,11 +96,13 @@ static struct nci_ops nfcmrvl_nci_ops = {
};
struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
- struct nfcmrvl_if_ops *ops,
- struct device *dev)
+ struct nfcmrvl_if_ops *ops,
+ struct device *dev,
+ struct nfcmrvl_platform_data *pdata)
{
struct nfcmrvl_private *priv;
int rc;
+ int headroom = 0;
u32 protocols;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -103,13 +113,30 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
priv->if_ops = ops;
priv->dev = dev;
+ memcpy(&priv->config, pdata, sizeof(*pdata));
+
+ if (priv->config.reset_n_io) {
+ rc = devm_gpio_request_one(dev,
+ priv->config.reset_n_io,
+ GPIOF_OUT_INIT_LOW,
+ "nfcmrvl_reset_n");
+ if (rc < 0)
+ nfc_err(dev, "failed to request reset_n io\n");
+ }
+
+ if (priv->config.hci_muxed)
+ headroom = NFCMRVL_HCI_EVENT_HEADER_SIZE;
+
protocols = NFC_PROTO_JEWEL_MASK
- | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
+ | NFC_PROTO_MIFARE_MASK
+ | NFC_PROTO_FELICA_MASK
| NFC_PROTO_ISO14443_MASK
| NFC_PROTO_ISO14443_B_MASK
+ | NFC_PROTO_ISO15693_MASK
| NFC_PROTO_NFC_DEP_MASK;
- priv->ndev = nci_allocate_device(&nfcmrvl_nci_ops, protocols, 0, 0);
+ priv->ndev = nci_allocate_device(&nfcmrvl_nci_ops, protocols,
+ headroom, 0);
if (!priv->ndev) {
nfc_err(dev, "nci_allocate_device failed\n");
rc = -ENOMEM;
@@ -118,6 +145,8 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
nci_set_drvdata(priv->ndev, priv);
+ nfcmrvl_chip_reset(priv);
+
rc = nci_register_device(priv->ndev);
if (rc) {
nfc_err(dev, "nci_register_device failed %d\n", rc);
@@ -144,21 +173,84 @@ void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv)
}
EXPORT_SYMBOL_GPL(nfcmrvl_nci_unregister_dev);
-int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, void *data, int count)
+int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, struct sk_buff *skb)
{
- struct sk_buff *skb;
-
- skb = nci_skb_alloc(priv->ndev, count, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
+ if (priv->config.hci_muxed) {
+ if (skb->data[0] == NFCMRVL_HCI_EVENT_CODE &&
+ skb->data[1] == NFCMRVL_HCI_NFC_EVENT_CODE) {
+ /* Data packet, let's extract NCI payload */
+ skb_pull(skb, NFCMRVL_HCI_EVENT_HEADER_SIZE);
+ } else {
+ /* Skip this packet */
+ kfree_skb(skb);
+ return 0;
+ }
+ }
- memcpy(skb_put(skb, count), data, count);
- nci_recv_frame(priv->ndev, skb);
+ if (test_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
+ nci_recv_frame(priv->ndev, skb);
+ else {
+ /* Drop this packet since nobody wants it */
+ kfree_skb(skb);
+ return 0;
+ }
- return count;
+ return 0;
}
EXPORT_SYMBOL_GPL(nfcmrvl_nci_recv_frame);
+void nfcmrvl_chip_reset(struct nfcmrvl_private *priv)
+{
+ /*
+ * This function does not take care if someone is using the device.
+ * To be improved.
+ */
+
+ if (priv->config.reset_n_io) {
+ nfc_info(priv->dev, "reset the chip\n");
+ gpio_set_value(priv->config.reset_n_io, 0);
+ usleep_range(5000, 10000);
+ gpio_set_value(priv->config.reset_n_io, 1);
+ } else
+ nfc_info(priv->dev, "no reset available on this interface\n");
+}
+
+#ifdef CONFIG_OF
+
+int nfcmrvl_parse_dt(struct device_node *node,
+ struct nfcmrvl_platform_data *pdata)
+{
+ int reset_n_io;
+
+ reset_n_io = of_get_named_gpio(node, "reset-n-io", 0);
+ if (reset_n_io < 0) {
+ pr_info("no reset-n-io config\n");
+ reset_n_io = 0;
+ } else if (!gpio_is_valid(reset_n_io)) {
+ pr_err("invalid reset-n-io GPIO\n");
+ return reset_n_io;
+ }
+ pdata->reset_n_io = reset_n_io;
+
+ if (of_find_property(node, "hci-muxed", NULL))
+ pdata->hci_muxed = 1;
+ else
+ pdata->hci_muxed = 0;
+
+ return 0;
+}
+
+#else
+
+int nfcmrvl_parse_dt(struct device_node *node,
+ struct nfcmrvl_platform_data *pdata)
+{
+ return -ENODEV;
+}
+
+#endif
+EXPORT_SYMBOL_GPL(nfcmrvl_parse_dt);
+
MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell NFC driver ver " VERSION);
MODULE_VERSION(VERSION);
diff --git a/drivers/nfc/nfcmrvl/nfcmrvl.h b/drivers/nfc/nfcmrvl/nfcmrvl.h
index 54c4a956bd45..e5a7e5464f2e 100644
--- a/drivers/nfc/nfcmrvl/nfcmrvl.h
+++ b/drivers/nfc/nfcmrvl/nfcmrvl.h
@@ -16,6 +16,11 @@
* this warranty disclaimer.
**/
+#ifndef _NFCMRVL_H_
+#define _NFCMRVL_H_
+
+#include <linux/platform_data/nfcmrvl.h>
+
/* Define private flags: */
#define NFCMRVL_NCI_RUNNING 1
@@ -27,11 +32,49 @@
#define NFCMRVL_GPIO_PIN_NFC_ACTIVE 0xB
#define NFCMRVL_NCI_MAX_EVENT_SIZE 260
+/*
+** NCI FW Parmaters
+*/
+
+#define NFCMRVL_PB_BAIL_OUT 0x11
+
+/*
+** HCI defines
+*/
+
+#define NFCMRVL_HCI_EVENT_HEADER_SIZE 0x04
+#define NFCMRVL_HCI_EVENT_CODE 0x04
+#define NFCMRVL_HCI_NFC_EVENT_CODE 0xFF
+#define NFCMRVL_HCI_COMMAND_CODE 0x01
+#define NFCMRVL_HCI_OGF 0x81
+#define NFCMRVL_HCI_OCF 0xFE
+
+enum nfcmrvl_phy {
+ NFCMRVL_PHY_USB = 0,
+ NFCMRVL_PHY_UART = 1,
+};
+
+
struct nfcmrvl_private {
- struct nci_dev *ndev;
+
unsigned long flags;
+
+ /* Platform configuration */
+ struct nfcmrvl_platform_data config;
+
+ struct nci_dev *ndev;
+
+ /*
+ ** PHY related information
+ */
+
+ /* PHY driver context */
void *drv_data;
+ /* PHY device */
struct device *dev;
+ /* PHY type */
+ enum nfcmrvl_phy phy;
+ /* Low level driver ops */
struct nfcmrvl_if_ops *if_ops;
};
@@ -42,7 +85,16 @@ struct nfcmrvl_if_ops {
};
void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv);
-int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, void *data, int count);
+int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, struct sk_buff *skb);
struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
- struct nfcmrvl_if_ops *ops,
- struct device *dev);
+ struct nfcmrvl_if_ops *ops,
+ struct device *dev,
+ struct nfcmrvl_platform_data *pdata);
+
+
+void nfcmrvl_chip_reset(struct nfcmrvl_private *priv);
+
+int nfcmrvl_parse_dt(struct device_node *node,
+ struct nfcmrvl_platform_data *pdata);
+
+#endif
diff --git a/drivers/nfc/nfcmrvl/uart.c b/drivers/nfc/nfcmrvl/uart.c
new file mode 100644
index 000000000000..61442d6528a6
--- /dev/null
+++ b/drivers/nfc/nfcmrvl/uart.c
@@ -0,0 +1,225 @@
+/**
+ * Marvell NFC-over-UART driver
+ *
+ * Copyright (C) 2015, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available on the worldwide web at
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/of_gpio.h>
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#include "nfcmrvl.h"
+
+static unsigned int hci_muxed;
+static unsigned int flow_control;
+static unsigned int break_control;
+static unsigned int reset_n_io;
+
+/*
+** NFCMRVL NCI OPS
+*/
+
+static int nfcmrvl_uart_nci_open(struct nfcmrvl_private *priv)
+{
+ return 0;
+}
+
+static int nfcmrvl_uart_nci_close(struct nfcmrvl_private *priv)
+{
+ return 0;
+}
+
+static int nfcmrvl_uart_nci_send(struct nfcmrvl_private *priv,
+ struct sk_buff *skb)
+{
+ struct nci_uart *nu = priv->drv_data;
+
+ return nu->ops.send(nu, skb);
+}
+
+static struct nfcmrvl_if_ops uart_ops = {
+ .nci_open = nfcmrvl_uart_nci_open,
+ .nci_close = nfcmrvl_uart_nci_close,
+ .nci_send = nfcmrvl_uart_nci_send,
+};
+
+#ifdef CONFIG_OF
+
+static int nfcmrvl_uart_parse_dt(struct device_node *node,
+ struct nfcmrvl_platform_data *pdata)
+{
+ struct device_node *matched_node;
+ int ret;
+
+ matched_node = of_find_compatible_node(node, NULL, "mrvl,nfc-uart");
+ if (!matched_node)
+ return -ENODEV;
+
+ ret = nfcmrvl_parse_dt(matched_node, pdata);
+ if (ret < 0) {
+ pr_err("Failed to get generic entries\n");
+ return ret;
+ }
+
+ if (of_find_property(matched_node, "flow-control", NULL))
+ pdata->flow_control = 1;
+ else
+ pdata->flow_control = 0;
+
+ if (of_find_property(matched_node, "break-control", NULL))
+ pdata->break_control = 1;
+ else
+ pdata->break_control = 0;
+
+ return 0;
+}
+
+#else
+
+static int nfcmrvl_uart_parse_dt(struct device_node *node,
+ struct nfcmrvl_platform_data *pdata)
+{
+ return -ENODEV;
+}
+
+#endif
+
+/*
+** NCI UART OPS
+*/
+
+static int nfcmrvl_nci_uart_open(struct nci_uart *nu)
+{
+ struct nfcmrvl_private *priv;
+ struct nfcmrvl_platform_data *pdata = NULL;
+ struct nfcmrvl_platform_data config;
+
+ /*
+ * Platform data cannot be used here since usually it is already used
+ * by low level serial driver. We can try to retrieve serial device
+ * and check if DT entries were added.
+ */
+
+ if (nu->tty->dev->parent && nu->tty->dev->parent->of_node)
+ if (nfcmrvl_uart_parse_dt(nu->tty->dev->parent->of_node,
+ &config) == 0)
+ pdata = &config;
+
+ if (!pdata) {
+ pr_info("No platform data / DT -> fallback to module params\n");
+ config.hci_muxed = hci_muxed;
+ config.reset_n_io = reset_n_io;
+ config.flow_control = flow_control;
+ config.break_control = break_control;
+ pdata = &config;
+ }
+
+ priv = nfcmrvl_nci_register_dev(nu, &uart_ops, nu->tty->dev, pdata);
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
+
+ priv->phy = NFCMRVL_PHY_UART;
+
+ nu->drv_data = priv;
+ nu->ndev = priv->ndev;
+
+ /* Set BREAK */
+ if (priv->config.break_control && nu->tty->ops->break_ctl)
+ nu->tty->ops->break_ctl(nu->tty, -1);
+
+ return 0;
+}
+
+static void nfcmrvl_nci_uart_close(struct nci_uart *nu)
+{
+ nfcmrvl_nci_unregister_dev((struct nfcmrvl_private *)nu->drv_data);
+}
+
+static int nfcmrvl_nci_uart_recv(struct nci_uart *nu, struct sk_buff *skb)
+{
+ return nfcmrvl_nci_recv_frame((struct nfcmrvl_private *)nu->drv_data,
+ skb);
+}
+
+static void nfcmrvl_nci_uart_tx_start(struct nci_uart *nu)
+{
+ struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data;
+
+ /* Remove BREAK to wake up the NFCC */
+ if (priv->config.break_control && nu->tty->ops->break_ctl) {
+ nu->tty->ops->break_ctl(nu->tty, 0);
+ usleep_range(3000, 5000);
+ }
+}
+
+static void nfcmrvl_nci_uart_tx_done(struct nci_uart *nu)
+{
+ struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data;
+
+ /*
+ ** To ensure that if the NFCC goes in DEEP SLEEP sate we can wake him
+ ** up. we set BREAK. Once we will be ready to send again we will remove
+ ** it.
+ */
+ if (priv->config.break_control && nu->tty->ops->break_ctl)
+ nu->tty->ops->break_ctl(nu->tty, -1);
+}
+
+static struct nci_uart nfcmrvl_nci_uart = {
+ .owner = THIS_MODULE,
+ .name = "nfcmrvl_uart",
+ .driver = NCI_UART_DRIVER_MARVELL,
+ .ops = {
+ .open = nfcmrvl_nci_uart_open,
+ .close = nfcmrvl_nci_uart_close,
+ .recv = nfcmrvl_nci_uart_recv,
+ .tx_start = nfcmrvl_nci_uart_tx_start,
+ .tx_done = nfcmrvl_nci_uart_tx_done,
+ }
+};
+
+/*
+** Module init
+*/
+
+static int nfcmrvl_uart_init_module(void)
+{
+ return nci_uart_register(&nfcmrvl_nci_uart);
+}
+
+static void nfcmrvl_uart_exit_module(void)
+{
+ nci_uart_unregister(&nfcmrvl_nci_uart);
+}
+
+module_init(nfcmrvl_uart_init_module);
+module_exit(nfcmrvl_uart_exit_module);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell NFC-over-UART");
+MODULE_LICENSE("GPL v2");
+
+module_param(flow_control, uint, 0);
+MODULE_PARM_DESC(flow_control, "Tell if UART needs flow control at init.");
+
+module_param(break_control, uint, 0);
+MODULE_PARM_DESC(break_control, "Tell if UART driver must drive break signal.");
+
+module_param(hci_muxed, uint, 0);
+MODULE_PARM_DESC(hci_muxed, "Tell if transport is muxed in HCI one.");
+
+module_param(reset_n_io, uint, 0);
+MODULE_PARM_DESC(reset_n_io, "GPIO that is wired to RESET_N signal.");
diff --git a/drivers/nfc/nfcmrvl/usb.c b/drivers/nfc/nfcmrvl/usb.c
index 6cf15c1a2618..7d1fe436c9f6 100644
--- a/drivers/nfc/nfcmrvl/usb.c
+++ b/drivers/nfc/nfcmrvl/usb.c
@@ -26,7 +26,8 @@
#define VERSION "1.0"
static struct usb_device_id nfcmrvl_table[] = {
- { USB_DEVICE_INTERFACE_CLASS(0x1286, 0x2046, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x1286, 0x2046,
+ USB_CLASS_VENDOR_SPEC, 4, 1) },
{ } /* Terminating entry */
};
@@ -69,18 +70,27 @@ static int nfcmrvl_inc_tx(struct nfcmrvl_usb_drv_data *drv_data)
static void nfcmrvl_bulk_complete(struct urb *urb)
{
struct nfcmrvl_usb_drv_data *drv_data = urb->context;
+ struct sk_buff *skb;
int err;
- dev_dbg(&drv_data->udev->dev, "urb %p status %d count %d",
+ dev_dbg(&drv_data->udev->dev, "urb %p status %d count %d\n",
urb, urb->status, urb->actual_length);
if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags))
return;
if (!urb->status) {
- if (nfcmrvl_nci_recv_frame(drv_data->priv, urb->transfer_buffer,
- urb->actual_length) < 0)
- nfc_err(&drv_data->udev->dev, "corrupted Rx packet\n");
+ skb = nci_skb_alloc(drv_data->priv->ndev, urb->actual_length,
+ GFP_ATOMIC);
+ if (!skb) {
+ nfc_err(&drv_data->udev->dev, "failed to alloc mem\n");
+ } else {
+ memcpy(skb_put(skb, urb->actual_length),
+ urb->transfer_buffer, urb->actual_length);
+ if (nfcmrvl_nci_recv_frame(drv_data->priv, skb) < 0)
+ nfc_err(&drv_data->udev->dev,
+ "corrupted Rx packet\n");
+ }
}
if (!test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags))
@@ -292,6 +302,10 @@ static int nfcmrvl_probe(struct usb_interface *intf,
struct nfcmrvl_private *priv;
int i;
struct usb_device *udev = interface_to_usbdev(intf);
+ struct nfcmrvl_platform_data config;
+
+ /* No configuration for USB */
+ memset(&config, 0, sizeof(config));
nfc_info(&udev->dev, "intf %p id %p\n", intf, id);
@@ -329,11 +343,12 @@ static int nfcmrvl_probe(struct usb_interface *intf,
init_usb_anchor(&drv_data->deferred);
priv = nfcmrvl_nci_register_dev(drv_data, &usb_ops,
- &drv_data->udev->dev);
+ &drv_data->udev->dev, &config);
if (IS_ERR(priv))
return PTR_ERR(priv);
drv_data->priv = priv;
+ drv_data->priv->phy = NFCMRVL_PHY_USB;
priv->dev = &drv_data->udev->dev;
usb_set_intfdata(intf, drv_data);
diff --git a/drivers/nfc/nxp-nci/Makefile b/drivers/nfc/nxp-nci/Makefile
index c008be30bb18..c9ec7869dbd2 100644
--- a/drivers/nfc/nxp-nci/Makefile
+++ b/drivers/nfc/nxp-nci/Makefile
@@ -7,5 +7,3 @@ nxp-nci_i2c-objs = i2c.o
obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci.o
obj-$(CONFIG_NFC_NXP_NCI_I2C) += nxp-nci_i2c.o
-
-ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c
index 17bd67dbebf0..2f77f1d03638 100644
--- a/drivers/nfc/nxp-nci/i2c.c
+++ b/drivers/nfc/nxp-nci/i2c.c
@@ -2,8 +2,10 @@
* I2C link layer for the NXP NCI driver
*
* Copyright (C) 2014 NXP Semiconductors All rights reserved.
+ * Copyright (C) 2012-2015 Intel Corporation. All rights reserved.
*
* Authors: Clément Perrochaud <clement.perrochaud@nxp.com>
+ * Authors: Oleg Zhurakivskyy <oleg.zhurakivskyy@intel.com>
*
* Derived from PN544 device driver:
* Copyright (C) 2012 Intel Corporation. All rights reserved.
@@ -23,12 +25,14 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/nfc.h>
+#include <linux/gpio/consumer.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/platform_data/nxp-nci.h>
@@ -48,6 +52,7 @@ struct nxp_nci_i2c_phy {
unsigned int gpio_en;
unsigned int gpio_fw;
+ unsigned int gpio_irq;
int hard_fault; /*
* < 0 if hardware error occurred (e.g. i2c err)
@@ -308,6 +313,37 @@ static int nxp_nci_i2c_parse_devtree(struct i2c_client *client)
#endif
+static int nxp_nci_i2c_acpi_config(struct nxp_nci_i2c_phy *phy)
+{
+ struct i2c_client *client = phy->i2c_dev;
+ struct gpio_desc *gpiod_en, *gpiod_fw, *gpiod_irq;
+
+ gpiod_en = devm_gpiod_get_index(&client->dev, NULL, 2);
+ gpiod_fw = devm_gpiod_get_index(&client->dev, NULL, 1);
+ gpiod_irq = devm_gpiod_get_index(&client->dev, NULL, 0);
+
+ if (IS_ERR(gpiod_en) || IS_ERR(gpiod_fw) || IS_ERR(gpiod_irq)) {
+ nfc_err(&client->dev, "No GPIOs\n");
+ return -EINVAL;
+ }
+
+ gpiod_direction_output(gpiod_en, 0);
+ gpiod_direction_output(gpiod_fw, 0);
+ gpiod_direction_input(gpiod_irq);
+
+ client->irq = gpiod_to_irq(gpiod_irq);
+ if (client->irq < 0) {
+ nfc_err(&client->dev, "No IRQ\n");
+ return -EINVAL;
+ }
+
+ phy->gpio_en = desc_to_gpio(gpiod_en);
+ phy->gpio_fw = desc_to_gpio(gpiod_fw);
+ phy->gpio_irq = desc_to_gpio(gpiod_irq);
+
+ return 0;
+}
+
static int nxp_nci_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -343,6 +379,11 @@ static int nxp_nci_i2c_probe(struct i2c_client *client,
phy->gpio_en = pdata->gpio_en;
phy->gpio_fw = pdata->gpio_fw;
client->irq = pdata->irq;
+ } else if (ACPI_HANDLE(&client->dev)) {
+ r = nxp_nci_i2c_acpi_config(phy);
+ if (r < 0)
+ goto probe_exit;
+ goto nci_probe;
} else {
nfc_err(&client->dev, "No platform data\n");
r = -EINVAL;
@@ -359,6 +400,7 @@ static int nxp_nci_i2c_probe(struct i2c_client *client,
if (r < 0)
goto probe_exit;
+nci_probe:
r = nxp_nci_probe(phy, &client->dev, &i2c_phy_ops,
NXP_NCI_I2C_MAX_PAYLOAD, &phy->ndev);
if (r < 0)
@@ -397,10 +439,19 @@ static const struct of_device_id of_nxp_nci_i2c_match[] = {
};
MODULE_DEVICE_TABLE(of, of_nxp_nci_i2c_match);
+#ifdef CONFIG_ACPI
+static struct acpi_device_id acpi_id[] = {
+ { "NXP7471" },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, acpi_id);
+#endif
+
static struct i2c_driver nxp_nci_i2c_driver = {
.driver = {
.name = NXP_NCI_I2C_DRIVER_NAME,
.owner = THIS_MODULE,
+ .acpi_match_table = ACPI_PTR(acpi_id),
.of_match_table = of_match_ptr(of_nxp_nci_i2c_match),
},
.probe = nxp_nci_i2c_probe,
@@ -413,3 +464,4 @@ module_i2c_driver(nxp_nci_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("I2C driver for NXP NCI NFC controllers");
MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>");
+MODULE_AUTHOR("Oleg Zhurakivskyy <oleg.zhurakivskyy@intel.com>");
diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c
index 6fd986f5ac3e..fa75c53f3fa5 100644
--- a/drivers/nfc/pn544/i2c.c
+++ b/drivers/nfc/pn544/i2c.c
@@ -895,56 +895,35 @@ static int pn544_hci_i2c_acpi_request_resources(struct i2c_client *client)
return -ENODEV;
/* Get EN GPIO from ACPI */
- gpiod_en = devm_gpiod_get_index(dev, PN544_GPIO_NAME_EN, 1);
+ gpiod_en = devm_gpiod_get_index(dev, PN544_GPIO_NAME_EN, 1,
+ GPIOD_OUT_LOW);
if (IS_ERR(gpiod_en)) {
- nfc_err(dev,
- "Unable to get EN GPIO\n");
+ nfc_err(dev, "Unable to get EN GPIO\n");
return -ENODEV;
}
- phy->gpio_en = desc_to_gpio(gpiod_en);
-
- /* Configuration EN GPIO */
- ret = gpiod_direction_output(gpiod_en, 0);
- if (ret) {
- nfc_err(dev, "Fail EN pin direction\n");
- return ret;
- }
+ phy->gpio_en = desc_to_gpio(gpiod_en);
/* Get FW GPIO from ACPI */
- gpiod_fw = devm_gpiod_get_index(dev, PN544_GPIO_NAME_FW, 2);
+ gpiod_fw = devm_gpiod_get_index(dev, PN544_GPIO_NAME_FW, 2,
+ GPIOD_OUT_LOW);
if (IS_ERR(gpiod_fw)) {
- nfc_err(dev,
- "Unable to get FW GPIO\n");
+ nfc_err(dev, "Unable to get FW GPIO\n");
return -ENODEV;
}
- phy->gpio_fw = desc_to_gpio(gpiod_fw);
-
- /* Configuration FW GPIO */
- ret = gpiod_direction_output(gpiod_fw, 0);
- if (ret) {
- nfc_err(dev, "Fail FW pin direction\n");
- return ret;
- }
+ phy->gpio_fw = desc_to_gpio(gpiod_fw);
/* Get IRQ GPIO */
- gpiod_irq = devm_gpiod_get_index(dev, PN544_GPIO_NAME_IRQ, 0);
+ gpiod_irq = devm_gpiod_get_index(dev, PN544_GPIO_NAME_IRQ, 0,
+ GPIOD_IN);
if (IS_ERR(gpiod_irq)) {
- nfc_err(dev,
- "Unable to get IRQ GPIO\n");
+ nfc_err(dev, "Unable to get IRQ GPIO\n");
return -ENODEV;
}
phy->gpio_irq = desc_to_gpio(gpiod_irq);
- /* Configure IRQ GPIO */
- ret = gpiod_direction_input(gpiod_irq);
- if (ret) {
- nfc_err(dev, "Fail IRQ pin direction\n");
- return ret;
- }
-
/* Map the pin to an IRQ */
ret = gpiod_to_irq(gpiod_irq);
if (ret < 0) {
diff --git a/drivers/nfc/st-nci/Kconfig b/drivers/nfc/st-nci/Kconfig
new file mode 100644
index 000000000000..fc3904c946ee
--- /dev/null
+++ b/drivers/nfc/st-nci/Kconfig
@@ -0,0 +1,23 @@
+config NFC_ST_NCI
+ tristate "STMicroelectronics ST NCI NFC driver"
+ depends on NFC_NCI
+ default n
+ ---help---
+ STMicroelectronics NFC NCI chips core driver. It implements the chipset
+ NCI logic and hooks into the NFC kernel APIs. Physical layers will
+ register against it.
+
+ To compile this driver as a module, choose m here. The module will
+ be called st-nci.
+ Say N if unsure.
+
+config NFC_ST_NCI_I2C
+ tristate "NFC ST NCI i2c support"
+ depends on NFC_ST_NCI && I2C
+ ---help---
+ This module adds support for an I2C interface to the
+ STMicroelectronics NFC NCI chips familly.
+ Select this if your platform is using the i2c bus.
+
+ If you choose to build a module, it'll be called st-nci_i2c.
+ Say N if unsure.
diff --git a/drivers/nfc/st-nci/Makefile b/drivers/nfc/st-nci/Makefile
new file mode 100644
index 000000000000..0df157df3a94
--- /dev/null
+++ b/drivers/nfc/st-nci/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for ST21NFCB NCI based NFC driver
+#
+
+st-nci-objs = ndlc.o core.o st-nci_se.o
+obj-$(CONFIG_NFC_ST_NCI) += st-nci.o
+
+st-nci_i2c-objs = i2c.o
+obj-$(CONFIG_NFC_ST_NCI_I2C) += st-nci_i2c.o
diff --git a/drivers/nfc/st-nci/core.c b/drivers/nfc/st-nci/core.c
new file mode 100644
index 000000000000..c419d3943973
--- /dev/null
+++ b/drivers/nfc/st-nci/core.c
@@ -0,0 +1,179 @@
+/*
+ * NCI based Driver for STMicroelectronics NFC Chip
+ *
+ * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved.
+ *
+ * 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 that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/nfc.h>
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "st-nci.h"
+#include "st-nci_se.h"
+
+#define DRIVER_DESC "NCI NFC driver for ST_NCI"
+
+#define ST_NCI1_X_PROPRIETARY_ISO15693 0x83
+
+static int st_nci_init(struct nci_dev *ndev)
+{
+ struct nci_mode_set_cmd cmd;
+
+ cmd.cmd_type = ST_NCI_SET_NFC_MODE;
+ cmd.mode = 1;
+
+ return nci_prop_cmd(ndev, ST_NCI_CORE_PROP,
+ sizeof(struct nci_mode_set_cmd), (__u8 *)&cmd);
+}
+
+static int st_nci_open(struct nci_dev *ndev)
+{
+ struct st_nci_info *info = nci_get_drvdata(ndev);
+ int r;
+
+ if (test_and_set_bit(ST_NCI_RUNNING, &info->flags))
+ return 0;
+
+ r = ndlc_open(info->ndlc);
+ if (r)
+ clear_bit(ST_NCI_RUNNING, &info->flags);
+
+ return r;
+}
+
+static int st_nci_close(struct nci_dev *ndev)
+{
+ struct st_nci_info *info = nci_get_drvdata(ndev);
+
+ if (!test_bit(ST_NCI_RUNNING, &info->flags))
+ return 0;
+
+ ndlc_close(info->ndlc);
+
+ clear_bit(ST_NCI_RUNNING, &info->flags);
+
+ return 0;
+}
+
+static int st_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
+{
+ struct st_nci_info *info = nci_get_drvdata(ndev);
+
+ skb->dev = (void *)ndev;
+
+ if (!test_bit(ST_NCI_RUNNING, &info->flags))
+ return -EBUSY;
+
+ return ndlc_send(info->ndlc, skb);
+}
+
+static __u32 st_nci_get_rfprotocol(struct nci_dev *ndev,
+ __u8 rf_protocol)
+{
+ return rf_protocol == ST_NCI1_X_PROPRIETARY_ISO15693 ?
+ NFC_PROTO_ISO15693_MASK : 0;
+}
+
+static int st_nci_prop_rsp_packet(struct nci_dev *ndev,
+ struct sk_buff *skb)
+{
+ __u8 status = skb->data[0];
+
+ nci_req_complete(ndev, status);
+ return 0;
+}
+
+static struct nci_prop_ops st_nci_prop_ops[] = {
+ {
+ .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
+ ST_NCI_CORE_PROP),
+ .rsp = st_nci_prop_rsp_packet,
+ },
+};
+
+static struct nci_ops st_nci_ops = {
+ .init = st_nci_init,
+ .open = st_nci_open,
+ .close = st_nci_close,
+ .send = st_nci_send,
+ .get_rfprotocol = st_nci_get_rfprotocol,
+ .discover_se = st_nci_discover_se,
+ .enable_se = st_nci_enable_se,
+ .disable_se = st_nci_disable_se,
+ .se_io = st_nci_se_io,
+ .hci_load_session = st_nci_hci_load_session,
+ .hci_event_received = st_nci_hci_event_received,
+ .hci_cmd_received = st_nci_hci_cmd_received,
+ .prop_ops = st_nci_prop_ops,
+ .n_prop_ops = ARRAY_SIZE(st_nci_prop_ops),
+};
+
+int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
+ int phy_tailroom)
+{
+ struct st_nci_info *info;
+ int r;
+ u32 protocols;
+
+ info = devm_kzalloc(ndlc->dev,
+ sizeof(struct st_nci_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ protocols = NFC_PROTO_JEWEL_MASK
+ | NFC_PROTO_MIFARE_MASK
+ | NFC_PROTO_FELICA_MASK
+ | NFC_PROTO_ISO14443_MASK
+ | NFC_PROTO_ISO14443_B_MASK
+ | NFC_PROTO_ISO15693_MASK
+ | NFC_PROTO_NFC_DEP_MASK;
+
+ ndlc->ndev = nci_allocate_device(&st_nci_ops, protocols,
+ phy_headroom, phy_tailroom);
+ if (!ndlc->ndev) {
+ pr_err("Cannot allocate nfc ndev\n");
+ return -ENOMEM;
+ }
+ info->ndlc = ndlc;
+
+ nci_set_drvdata(ndlc->ndev, info);
+
+ r = nci_register_device(ndlc->ndev);
+ if (r) {
+ pr_err("Cannot register nfc device to nci core\n");
+ nci_free_device(ndlc->ndev);
+ return r;
+ }
+
+ return st_nci_se_init(ndlc->ndev);
+}
+EXPORT_SYMBOL_GPL(st_nci_probe);
+
+void st_nci_remove(struct nci_dev *ndev)
+{
+ struct st_nci_info *info = nci_get_drvdata(ndev);
+
+ ndlc_close(info->ndlc);
+
+ nci_unregister_device(ndev);
+ nci_free_device(ndev);
+}
+EXPORT_SYMBOL_GPL(st_nci_remove);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/st21nfcb/i2c.c b/drivers/nfc/st-nci/i2c.c
index 76a4cad41cec..06175ce769bb 100644
--- a/drivers/nfc/st21nfcb/i2c.c
+++ b/drivers/nfc/st-nci/i2c.c
@@ -1,6 +1,6 @@
/*
- * I2C Link Layer for ST21NFCB NCI based Driver
- * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
+ * I2C Link Layer for ST NCI NFC controller familly based Driver
+ * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -25,7 +25,7 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/nfc.h>
-#include <linux/platform_data/st21nfcb.h>
+#include <linux/platform_data/st_nci.h>
#include "ndlc.h"
@@ -35,25 +35,23 @@
#define ST21NFCB_FRAME_HEADROOM 1
#define ST21NFCB_FRAME_TAILROOM 0
-#define ST21NFCB_NCI_I2C_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */
-#define ST21NFCB_NCI_I2C_MAX_SIZE 250 /* req 4.2.1 */
+#define ST_NCI_I2C_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */
+#define ST_NCI_I2C_MAX_SIZE 250 /* req 4.2.1 */
-#define ST21NFCB_NCI_I2C_DRIVER_NAME "st21nfcb_nci_i2c"
+#define ST_NCI_I2C_DRIVER_NAME "st_nci_i2c"
-static struct i2c_device_id st21nfcb_nci_i2c_id_table[] = {
- {ST21NFCB_NCI_DRIVER_NAME, 0},
+static struct i2c_device_id st_nci_i2c_id_table[] = {
+ {ST_NCI_DRIVER_NAME, 0},
{}
};
-MODULE_DEVICE_TABLE(i2c, st21nfcb_nci_i2c_id_table);
+MODULE_DEVICE_TABLE(i2c, st_nci_i2c_id_table);
-struct st21nfcb_i2c_phy {
+struct st_nci_i2c_phy {
struct i2c_client *i2c_dev;
struct llt_ndlc *ndlc;
unsigned int gpio_reset;
unsigned int irq_polarity;
-
- int powered;
};
#define I2C_DUMP_SKB(info, skb) \
@@ -63,33 +61,26 @@ do { \
16, 1, (skb)->data, (skb)->len, 0); \
} while (0)
-static int st21nfcb_nci_i2c_enable(void *phy_id)
+static int st_nci_i2c_enable(void *phy_id)
{
- struct st21nfcb_i2c_phy *phy = phy_id;
+ struct st_nci_i2c_phy *phy = phy_id;
gpio_set_value(phy->gpio_reset, 0);
usleep_range(10000, 15000);
gpio_set_value(phy->gpio_reset, 1);
- phy->powered = 1;
usleep_range(80000, 85000);
+ if (phy->ndlc->powered == 0)
+ enable_irq(phy->i2c_dev->irq);
+
return 0;
}
-static void st21nfcb_nci_i2c_disable(void *phy_id)
+static void st_nci_i2c_disable(void *phy_id)
{
- struct st21nfcb_i2c_phy *phy = phy_id;
-
- phy->powered = 0;
- /* reset chip in order to flush clf */
- gpio_set_value(phy->gpio_reset, 0);
- usleep_range(10000, 15000);
- gpio_set_value(phy->gpio_reset, 1);
-}
+ struct st_nci_i2c_phy *phy = phy_id;
-static void st21nfcb_nci_remove_header(struct sk_buff *skb)
-{
- skb_pull(skb, ST21NFCB_FRAME_HEADROOM);
+ disable_irq_nosync(phy->i2c_dev->irq);
}
/*
@@ -97,13 +88,13 @@ static void st21nfcb_nci_remove_header(struct sk_buff *skb)
* It must return either zero for success, or <0 for error.
* In addition, it must not alter the skb
*/
-static int st21nfcb_nci_i2c_write(void *phy_id, struct sk_buff *skb)
+static int st_nci_i2c_write(void *phy_id, struct sk_buff *skb)
{
int r = -1;
- struct st21nfcb_i2c_phy *phy = phy_id;
+ struct st_nci_i2c_phy *phy = phy_id;
struct i2c_client *client = phy->i2c_dev;
- I2C_DUMP_SKB("st21nfcb_nci_i2c_write", skb);
+ I2C_DUMP_SKB("st_nci_i2c_write", skb);
if (phy->ndlc->hard_fault != 0)
return phy->ndlc->hard_fault;
@@ -121,8 +112,6 @@ static int st21nfcb_nci_i2c_write(void *phy_id, struct sk_buff *skb)
r = 0;
}
- st21nfcb_nci_remove_header(skb);
-
return r;
}
@@ -135,40 +124,40 @@ static int st21nfcb_nci_i2c_write(void *phy_id, struct sk_buff *skb)
* at end of read)
* -EREMOTEIO : i2c read error (fatal)
* -EBADMSG : frame was incorrect and discarded
- * (value returned from st21nfcb_nci_i2c_repack)
+ * (value returned from st_nci_i2c_repack)
* -EIO : if no ST21NFCB_SOF_EOF is found after reaching
* the read length end sequence
*/
-static int st21nfcb_nci_i2c_read(struct st21nfcb_i2c_phy *phy,
+static int st_nci_i2c_read(struct st_nci_i2c_phy *phy,
struct sk_buff **skb)
{
int r;
u8 len;
- u8 buf[ST21NFCB_NCI_I2C_MAX_SIZE];
+ u8 buf[ST_NCI_I2C_MAX_SIZE];
struct i2c_client *client = phy->i2c_dev;
- r = i2c_master_recv(client, buf, ST21NFCB_NCI_I2C_MIN_SIZE);
+ r = i2c_master_recv(client, buf, ST_NCI_I2C_MIN_SIZE);
if (r < 0) { /* Retry, chip was in standby */
usleep_range(1000, 4000);
- r = i2c_master_recv(client, buf, ST21NFCB_NCI_I2C_MIN_SIZE);
+ r = i2c_master_recv(client, buf, ST_NCI_I2C_MIN_SIZE);
}
- if (r != ST21NFCB_NCI_I2C_MIN_SIZE)
+ if (r != ST_NCI_I2C_MIN_SIZE)
return -EREMOTEIO;
len = be16_to_cpu(*(__be16 *) (buf + 2));
- if (len > ST21NFCB_NCI_I2C_MAX_SIZE) {
+ if (len > ST_NCI_I2C_MAX_SIZE) {
nfc_err(&client->dev, "invalid frame len\n");
return -EBADMSG;
}
- *skb = alloc_skb(ST21NFCB_NCI_I2C_MIN_SIZE + len, GFP_KERNEL);
+ *skb = alloc_skb(ST_NCI_I2C_MIN_SIZE + len, GFP_KERNEL);
if (*skb == NULL)
return -ENOMEM;
- skb_reserve(*skb, ST21NFCB_NCI_I2C_MIN_SIZE);
- skb_put(*skb, ST21NFCB_NCI_I2C_MIN_SIZE);
- memcpy((*skb)->data, buf, ST21NFCB_NCI_I2C_MIN_SIZE);
+ skb_reserve(*skb, ST_NCI_I2C_MIN_SIZE);
+ skb_put(*skb, ST_NCI_I2C_MIN_SIZE);
+ memcpy((*skb)->data, buf, ST_NCI_I2C_MIN_SIZE);
if (!len)
return 0;
@@ -180,7 +169,7 @@ static int st21nfcb_nci_i2c_read(struct st21nfcb_i2c_phy *phy,
}
skb_put(*skb, len);
- memcpy((*skb)->data + ST21NFCB_NCI_I2C_MIN_SIZE, buf, len);
+ memcpy((*skb)->data + ST_NCI_I2C_MIN_SIZE, buf, len);
I2C_DUMP_SKB("i2c frame read", *skb);
@@ -192,9 +181,9 @@ static int st21nfcb_nci_i2c_read(struct st21nfcb_i2c_phy *phy,
*
* On ST21NFCB, IRQ goes in idle state when read starts.
*/
-static irqreturn_t st21nfcb_nci_irq_thread_fn(int irq, void *phy_id)
+static irqreturn_t st_nci_irq_thread_fn(int irq, void *phy_id)
{
- struct st21nfcb_i2c_phy *phy = phy_id;
+ struct st_nci_i2c_phy *phy = phy_id;
struct i2c_client *client;
struct sk_buff *skb = NULL;
int r;
@@ -210,12 +199,12 @@ static irqreturn_t st21nfcb_nci_irq_thread_fn(int irq, void *phy_id)
if (phy->ndlc->hard_fault)
return IRQ_HANDLED;
- if (!phy->powered) {
- st21nfcb_nci_i2c_disable(phy);
+ if (!phy->ndlc->powered) {
+ st_nci_i2c_disable(phy);
return IRQ_HANDLED;
}
- r = st21nfcb_nci_i2c_read(phy, &skb);
+ r = st_nci_i2c_read(phy, &skb);
if (r == -EREMOTEIO || r == -ENOMEM || r == -EBADMSG)
return IRQ_HANDLED;
@@ -225,15 +214,15 @@ static irqreturn_t st21nfcb_nci_irq_thread_fn(int irq, void *phy_id)
}
static struct nfc_phy_ops i2c_phy_ops = {
- .write = st21nfcb_nci_i2c_write,
- .enable = st21nfcb_nci_i2c_enable,
- .disable = st21nfcb_nci_i2c_disable,
+ .write = st_nci_i2c_write,
+ .enable = st_nci_i2c_enable,
+ .disable = st_nci_i2c_disable,
};
#ifdef CONFIG_OF
-static int st21nfcb_nci_i2c_of_request_resources(struct i2c_client *client)
+static int st_nci_i2c_of_request_resources(struct i2c_client *client)
{
- struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client);
+ struct st_nci_i2c_phy *phy = i2c_get_clientdata(client);
struct device_node *pp;
int gpio;
int r;
@@ -264,16 +253,16 @@ static int st21nfcb_nci_i2c_of_request_resources(struct i2c_client *client)
return 0;
}
#else
-static int st21nfcb_nci_i2c_of_request_resources(struct i2c_client *client)
+static int st_nci_i2c_of_request_resources(struct i2c_client *client)
{
return -ENODEV;
}
#endif
-static int st21nfcb_nci_i2c_request_resources(struct i2c_client *client)
+static int st_nci_i2c_request_resources(struct i2c_client *client)
{
- struct st21nfcb_nfc_platform_data *pdata;
- struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client);
+ struct st_nci_nfc_platform_data *pdata;
+ struct st_nci_i2c_phy *phy = i2c_get_clientdata(client);
int r;
pdata = client->dev.platform_data;
@@ -296,11 +285,11 @@ static int st21nfcb_nci_i2c_request_resources(struct i2c_client *client)
return 0;
}
-static int st21nfcb_nci_i2c_probe(struct i2c_client *client,
+static int st_nci_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct st21nfcb_i2c_phy *phy;
- struct st21nfcb_nfc_platform_data *pdata;
+ struct st_nci_i2c_phy *phy;
+ struct st_nci_nfc_platform_data *pdata;
int r;
dev_dbg(&client->dev, "%s\n", __func__);
@@ -311,7 +300,7 @@ static int st21nfcb_nci_i2c_probe(struct i2c_client *client,
return -ENODEV;
}
- phy = devm_kzalloc(&client->dev, sizeof(struct st21nfcb_i2c_phy),
+ phy = devm_kzalloc(&client->dev, sizeof(struct st_nci_i2c_phy),
GFP_KERNEL);
if (!phy)
return -ENOMEM;
@@ -322,13 +311,13 @@ static int st21nfcb_nci_i2c_probe(struct i2c_client *client,
pdata = client->dev.platform_data;
if (!pdata && client->dev.of_node) {
- r = st21nfcb_nci_i2c_of_request_resources(client);
+ r = st_nci_i2c_of_request_resources(client);
if (r) {
nfc_err(&client->dev, "No platform data\n");
return r;
}
} else if (pdata) {
- r = st21nfcb_nci_i2c_request_resources(client);
+ r = st_nci_i2c_request_resources(client);
if (r) {
nfc_err(&client->dev,
"Cannot get platform resources\n");
@@ -349,50 +338,48 @@ static int st21nfcb_nci_i2c_probe(struct i2c_client *client,
}
r = devm_request_threaded_irq(&client->dev, client->irq, NULL,
- st21nfcb_nci_irq_thread_fn,
+ st_nci_irq_thread_fn,
phy->irq_polarity | IRQF_ONESHOT,
- ST21NFCB_NCI_DRIVER_NAME, phy);
+ ST_NCI_DRIVER_NAME, phy);
if (r < 0)
nfc_err(&client->dev, "Unable to register IRQ handler\n");
return r;
}
-static int st21nfcb_nci_i2c_remove(struct i2c_client *client)
+static int st_nci_i2c_remove(struct i2c_client *client)
{
- struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client);
+ struct st_nci_i2c_phy *phy = i2c_get_clientdata(client);
dev_dbg(&client->dev, "%s\n", __func__);
ndlc_remove(phy->ndlc);
- if (phy->powered)
- st21nfcb_nci_i2c_disable(phy);
-
return 0;
}
#ifdef CONFIG_OF
-static const struct of_device_id of_st21nfcb_i2c_match[] = {
+static const struct of_device_id of_st_nci_i2c_match[] = {
{ .compatible = "st,st21nfcb-i2c", },
{ .compatible = "st,st21nfcb_i2c", },
+ { .compatible = "st,st21nfcc-i2c", },
{}
};
-MODULE_DEVICE_TABLE(of, of_st21nfcb_i2c_match);
+MODULE_DEVICE_TABLE(of, of_st_nci_i2c_match);
#endif
-static struct i2c_driver st21nfcb_nci_i2c_driver = {
+static struct i2c_driver st_nci_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
- .name = ST21NFCB_NCI_I2C_DRIVER_NAME,
- .of_match_table = of_match_ptr(of_st21nfcb_i2c_match),
+ .name = ST_NCI_I2C_DRIVER_NAME,
+ .of_match_table = of_match_ptr(of_st_nci_i2c_match),
},
- .probe = st21nfcb_nci_i2c_probe,
- .id_table = st21nfcb_nci_i2c_id_table,
- .remove = st21nfcb_nci_i2c_remove,
+ .probe = st_nci_i2c_probe,
+ .id_table = st_nci_i2c_id_table,
+ .remove = st_nci_i2c_remove,
};
-module_i2c_driver(st21nfcb_nci_i2c_driver);
+module_i2c_driver(st_nci_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/st21nfcb/ndlc.c b/drivers/nfc/st-nci/ndlc.c
index 6014b5859465..56c6a4cb4c96 100644
--- a/drivers/nfc/st21nfcb/ndlc.c
+++ b/drivers/nfc/st-nci/ndlc.c
@@ -1,7 +1,7 @@
/*
* Low Level Transport (NDLC) Driver for STMicroelectronics NFC Chip
*
- * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
+ * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -20,7 +20,7 @@
#include <net/nfc/nci_core.h>
#include "ndlc.h"
-#include "st21nfcb.h"
+#include "st-nci.h"
#define NDLC_TIMER_T1 100
#define NDLC_TIMER_T1_WAIT 400
@@ -59,13 +59,25 @@ int ndlc_open(struct llt_ndlc *ndlc)
{
/* toggle reset pin */
ndlc->ops->enable(ndlc->phy_id);
+ ndlc->powered = 1;
return 0;
}
EXPORT_SYMBOL(ndlc_open);
void ndlc_close(struct llt_ndlc *ndlc)
{
+ struct nci_mode_set_cmd cmd;
+
+ cmd.cmd_type = ST_NCI_SET_NFC_MODE;
+ cmd.mode = 0;
+
/* toggle reset pin */
+ ndlc->ops->enable(ndlc->phy_id);
+
+ nci_prop_cmd(ndlc->ndev, ST_NCI_CORE_PROP,
+ sizeof(struct nci_mode_set_cmd), (__u8 *)&cmd);
+
+ ndlc->powered = 0;
ndlc->ops->disable(ndlc->phy_id);
}
EXPORT_SYMBOL(ndlc_close);
@@ -262,6 +274,7 @@ int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
ndlc->ops = phy_ops;
ndlc->phy_id = phy_id;
ndlc->dev = dev;
+ ndlc->powered = 0;
*ndlc_id = ndlc;
@@ -280,12 +293,14 @@ int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
INIT_WORK(&ndlc->sm_work, llt_ndlc_sm_work);
- return st21nfcb_nci_probe(ndlc, phy_headroom, phy_tailroom);
+ return st_nci_probe(ndlc, phy_headroom, phy_tailroom);
}
EXPORT_SYMBOL(ndlc_probe);
void ndlc_remove(struct llt_ndlc *ndlc)
{
+ st_nci_remove(ndlc->ndev);
+
/* cancel timers */
del_timer_sync(&ndlc->t1_timer);
del_timer_sync(&ndlc->t2_timer);
@@ -294,7 +309,5 @@ void ndlc_remove(struct llt_ndlc *ndlc)
skb_queue_purge(&ndlc->rcv_q);
skb_queue_purge(&ndlc->send_q);
-
- st21nfcb_nci_remove(ndlc->ndev);
}
EXPORT_SYMBOL(ndlc_remove);
diff --git a/drivers/nfc/st21nfcb/ndlc.h b/drivers/nfc/st-nci/ndlc.h
index b28140e0cd78..6361005ef003 100644
--- a/drivers/nfc/st21nfcb/ndlc.h
+++ b/drivers/nfc/st-nci/ndlc.h
@@ -1,7 +1,7 @@
/*
* NCI based Driver for STMicroelectronics NFC Chip
*
- * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
+ * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -43,10 +43,11 @@ struct llt_ndlc {
struct device *dev;
/*
- * < 0 if hardware error occured
+ * < 0 if hardware error occurred
* and prevents normal operation.
*/
int hard_fault;
+ int powered;
};
int ndlc_open(struct llt_ndlc *ndlc);
diff --git a/drivers/nfc/st21nfcb/st21nfcb.h b/drivers/nfc/st-nci/st-nci.h
index 5ef8a58c9839..850a2395deb7 100644
--- a/drivers/nfc/st21nfcb/st21nfcb.h
+++ b/drivers/nfc/st-nci/st-nci.h
@@ -16,23 +16,35 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef __LOCAL_ST21NFCB_H_
-#define __LOCAL_ST21NFCB_H_
+#ifndef __LOCAL_ST_NCI_H_
+#define __LOCAL_ST_NCI_H_
-#include "st21nfcb_se.h"
+#include "st-nci_se.h"
#include "ndlc.h"
/* Define private flags: */
-#define ST21NFCB_NCI_RUNNING 1
+#define ST_NCI_RUNNING 1
-struct st21nfcb_nci_info {
+#define ST_NCI_CORE_PROP 0x01
+#define ST_NCI_SET_NFC_MODE 0x02
+
+struct nci_mode_set_cmd {
+ u8 cmd_type;
+ u8 mode;
+} __packed;
+
+struct nci_mode_set_rsp {
+ u8 status;
+} __packed;
+
+struct st_nci_info {
struct llt_ndlc *ndlc;
unsigned long flags;
- struct st21nfcb_se_info se_info;
+ struct st_nci_se_info se_info;
};
-void st21nfcb_nci_remove(struct nci_dev *ndev);
-int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
+void st_nci_remove(struct nci_dev *ndev);
+int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
int phy_tailroom);
-#endif /* __LOCAL_ST21NFCB_H_ */
+#endif /* __LOCAL_ST_NCI_H_ */
diff --git a/drivers/nfc/st21nfcb/st21nfcb_se.c b/drivers/nfc/st-nci/st-nci_se.c
index 24862a525fb5..97addfa96c6f 100644
--- a/drivers/nfc/st21nfcb/st21nfcb_se.c
+++ b/drivers/nfc/st-nci/st-nci_se.c
@@ -1,7 +1,7 @@
/*
- * NCI based Driver for STMicroelectronics NFC Chip
+ * Secure Element driver for STMicroelectronics NFC NCI chip
*
- * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
+ * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -22,10 +22,10 @@
#include <net/nfc/nci.h>
#include <net/nfc/nci_core.h>
-#include "st21nfcb.h"
-#include "st21nfcb_se.h"
+#include "st-nci.h"
+#include "st-nci_se.h"
-struct st21nfcb_pipe_info {
+struct st_nci_pipe_info {
u8 pipe_state;
u8 src_host_id;
u8 src_gate_id;
@@ -34,166 +34,166 @@ struct st21nfcb_pipe_info {
} __packed;
/* Hosts */
-#define ST21NFCB_HOST_CONTROLLER_ID 0x00
-#define ST21NFCB_TERMINAL_HOST_ID 0x01
-#define ST21NFCB_UICC_HOST_ID 0x02
-#define ST21NFCB_ESE_HOST_ID 0xc0
+#define ST_NCI_HOST_CONTROLLER_ID 0x00
+#define ST_NCI_TERMINAL_HOST_ID 0x01
+#define ST_NCI_UICC_HOST_ID 0x02
+#define ST_NCI_ESE_HOST_ID 0xc0
/* Gates */
-#define ST21NFCB_DEVICE_MGNT_GATE 0x01
-#define ST21NFCB_APDU_READER_GATE 0xf0
-#define ST21NFCB_CONNECTIVITY_GATE 0x41
+#define ST_NCI_DEVICE_MGNT_GATE 0x01
+#define ST_NCI_APDU_READER_GATE 0xf0
+#define ST_NCI_CONNECTIVITY_GATE 0x41
/* Pipes */
-#define ST21NFCB_DEVICE_MGNT_PIPE 0x02
+#define ST_NCI_DEVICE_MGNT_PIPE 0x02
/* Connectivity pipe only */
-#define ST21NFCB_SE_COUNT_PIPE_UICC 0x01
+#define ST_NCI_SE_COUNT_PIPE_UICC 0x01
/* Connectivity + APDU Reader pipe */
-#define ST21NFCB_SE_COUNT_PIPE_EMBEDDED 0x02
+#define ST_NCI_SE_COUNT_PIPE_EMBEDDED 0x02
-#define ST21NFCB_SE_TO_HOT_PLUG 1000 /* msecs */
-#define ST21NFCB_SE_TO_PIPES 2000
+#define ST_NCI_SE_TO_HOT_PLUG 1000 /* msecs */
+#define ST_NCI_SE_TO_PIPES 2000
-#define ST21NFCB_EVT_HOT_PLUG_IS_INHIBITED(x) (x->data[0] & 0x80)
+#define ST_NCI_EVT_HOT_PLUG_IS_INHIBITED(x) (x->data[0] & 0x80)
#define NCI_HCI_APDU_PARAM_ATR 0x01
#define NCI_HCI_ADMIN_PARAM_SESSION_IDENTITY 0x01
#define NCI_HCI_ADMIN_PARAM_WHITELIST 0x03
#define NCI_HCI_ADMIN_PARAM_HOST_LIST 0x04
-#define ST21NFCB_EVT_SE_HARD_RESET 0x20
-#define ST21NFCB_EVT_TRANSMIT_DATA 0x10
-#define ST21NFCB_EVT_WTX_REQUEST 0x11
-#define ST21NFCB_EVT_SE_SOFT_RESET 0x11
-#define ST21NFCB_EVT_SE_END_OF_APDU_TRANSFER 0x21
-#define ST21NFCB_EVT_HOT_PLUG 0x03
+#define ST_NCI_EVT_SE_HARD_RESET 0x20
+#define ST_NCI_EVT_TRANSMIT_DATA 0x10
+#define ST_NCI_EVT_WTX_REQUEST 0x11
+#define ST_NCI_EVT_SE_SOFT_RESET 0x11
+#define ST_NCI_EVT_SE_END_OF_APDU_TRANSFER 0x21
+#define ST_NCI_EVT_HOT_PLUG 0x03
-#define ST21NFCB_SE_MODE_OFF 0x00
-#define ST21NFCB_SE_MODE_ON 0x01
+#define ST_NCI_SE_MODE_OFF 0x00
+#define ST_NCI_SE_MODE_ON 0x01
-#define ST21NFCB_EVT_CONNECTIVITY 0x10
-#define ST21NFCB_EVT_TRANSACTION 0x12
+#define ST_NCI_EVT_CONNECTIVITY 0x10
+#define ST_NCI_EVT_TRANSACTION 0x12
-#define ST21NFCB_DM_GETINFO 0x13
-#define ST21NFCB_DM_GETINFO_PIPE_LIST 0x02
-#define ST21NFCB_DM_GETINFO_PIPE_INFO 0x01
-#define ST21NFCB_DM_PIPE_CREATED 0x02
-#define ST21NFCB_DM_PIPE_OPEN 0x04
-#define ST21NFCB_DM_RF_ACTIVE 0x80
-#define ST21NFCB_DM_DISCONNECT 0x30
+#define ST_NCI_DM_GETINFO 0x13
+#define ST_NCI_DM_GETINFO_PIPE_LIST 0x02
+#define ST_NCI_DM_GETINFO_PIPE_INFO 0x01
+#define ST_NCI_DM_PIPE_CREATED 0x02
+#define ST_NCI_DM_PIPE_OPEN 0x04
+#define ST_NCI_DM_RF_ACTIVE 0x80
+#define ST_NCI_DM_DISCONNECT 0x30
-#define ST21NFCB_DM_IS_PIPE_OPEN(p) \
- ((p & 0x0f) == (ST21NFCB_DM_PIPE_CREATED | ST21NFCB_DM_PIPE_OPEN))
+#define ST_NCI_DM_IS_PIPE_OPEN(p) \
+ ((p & 0x0f) == (ST_NCI_DM_PIPE_CREATED | ST_NCI_DM_PIPE_OPEN))
-#define ST21NFCB_ATR_DEFAULT_BWI 0x04
+#define ST_NCI_ATR_DEFAULT_BWI 0x04
/*
* WT = 2^BWI/10[s], convert into msecs and add a secure
* room by increasing by 2 this timeout
*/
-#define ST21NFCB_BWI_TO_TIMEOUT(x) ((1 << x) * 200)
-#define ST21NFCB_ATR_GET_Y_FROM_TD(x) (x >> 4)
+#define ST_NCI_BWI_TO_TIMEOUT(x) ((1 << x) * 200)
+#define ST_NCI_ATR_GET_Y_FROM_TD(x) (x >> 4)
/* If TA is present bit 0 is set */
-#define ST21NFCB_ATR_TA_PRESENT(x) (x & 0x01)
+#define ST_NCI_ATR_TA_PRESENT(x) (x & 0x01)
/* If TB is present bit 1 is set */
-#define ST21NFCB_ATR_TB_PRESENT(x) (x & 0x02)
+#define ST_NCI_ATR_TB_PRESENT(x) (x & 0x02)
-#define ST21NFCB_NUM_DEVICES 256
+#define ST_NCI_NUM_DEVICES 256
-static DECLARE_BITMAP(dev_mask, ST21NFCB_NUM_DEVICES);
+static DECLARE_BITMAP(dev_mask, ST_NCI_NUM_DEVICES);
-/* Here are the mandatory pipe for st21nfcb */
-static struct nci_hci_gate st21nfcb_gates[] = {
+/* Here are the mandatory pipe for st_nci */
+static struct nci_hci_gate st_nci_gates[] = {
{NCI_HCI_ADMIN_GATE, NCI_HCI_ADMIN_PIPE,
- ST21NFCB_HOST_CONTROLLER_ID},
+ ST_NCI_HOST_CONTROLLER_ID},
{NCI_HCI_LINK_MGMT_GATE, NCI_HCI_LINK_MGMT_PIPE,
- ST21NFCB_HOST_CONTROLLER_ID},
- {ST21NFCB_DEVICE_MGNT_GATE, ST21NFCB_DEVICE_MGNT_PIPE,
- ST21NFCB_HOST_CONTROLLER_ID},
+ ST_NCI_HOST_CONTROLLER_ID},
+ {ST_NCI_DEVICE_MGNT_GATE, ST_NCI_DEVICE_MGNT_PIPE,
+ ST_NCI_HOST_CONTROLLER_ID},
/* Secure element pipes are created by secure element host */
- {ST21NFCB_CONNECTIVITY_GATE, NCI_HCI_DO_NOT_OPEN_PIPE,
- ST21NFCB_HOST_CONTROLLER_ID},
- {ST21NFCB_APDU_READER_GATE, NCI_HCI_DO_NOT_OPEN_PIPE,
- ST21NFCB_HOST_CONTROLLER_ID},
+ {ST_NCI_CONNECTIVITY_GATE, NCI_HCI_DO_NOT_OPEN_PIPE,
+ ST_NCI_HOST_CONTROLLER_ID},
+ {ST_NCI_APDU_READER_GATE, NCI_HCI_DO_NOT_OPEN_PIPE,
+ ST_NCI_HOST_CONTROLLER_ID},
};
-static u8 st21nfcb_se_get_bwi(struct nci_dev *ndev)
+static u8 st_nci_se_get_bwi(struct nci_dev *ndev)
{
int i;
u8 td;
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
/* Bits 8 to 5 of the first TB for T=1 encode BWI from zero to nine */
- for (i = 1; i < ST21NFCB_ESE_MAX_LENGTH; i++) {
- td = ST21NFCB_ATR_GET_Y_FROM_TD(info->se_info.atr[i]);
- if (ST21NFCB_ATR_TA_PRESENT(td))
+ for (i = 1; i < ST_NCI_ESE_MAX_LENGTH; i++) {
+ td = ST_NCI_ATR_GET_Y_FROM_TD(info->se_info.atr[i]);
+ if (ST_NCI_ATR_TA_PRESENT(td))
i++;
- if (ST21NFCB_ATR_TB_PRESENT(td)) {
+ if (ST_NCI_ATR_TB_PRESENT(td)) {
i++;
return info->se_info.atr[i] >> 4;
}
}
- return ST21NFCB_ATR_DEFAULT_BWI;
+ return ST_NCI_ATR_DEFAULT_BWI;
}
-static void st21nfcb_se_get_atr(struct nci_dev *ndev)
+static void st_nci_se_get_atr(struct nci_dev *ndev)
{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
int r;
struct sk_buff *skb;
- r = nci_hci_get_param(ndev, ST21NFCB_APDU_READER_GATE,
+ r = nci_hci_get_param(ndev, ST_NCI_APDU_READER_GATE,
NCI_HCI_APDU_PARAM_ATR, &skb);
if (r < 0)
return;
- if (skb->len <= ST21NFCB_ESE_MAX_LENGTH) {
+ if (skb->len <= ST_NCI_ESE_MAX_LENGTH) {
memcpy(info->se_info.atr, skb->data, skb->len);
info->se_info.wt_timeout =
- ST21NFCB_BWI_TO_TIMEOUT(st21nfcb_se_get_bwi(ndev));
+ ST_NCI_BWI_TO_TIMEOUT(st_nci_se_get_bwi(ndev));
}
kfree_skb(skb);
}
-int st21nfcb_hci_load_session(struct nci_dev *ndev)
+int st_nci_hci_load_session(struct nci_dev *ndev)
{
int i, j, r;
struct sk_buff *skb_pipe_list, *skb_pipe_info;
- struct st21nfcb_pipe_info *dm_pipe_info;
- u8 pipe_list[] = { ST21NFCB_DM_GETINFO_PIPE_LIST,
- ST21NFCB_TERMINAL_HOST_ID};
- u8 pipe_info[] = { ST21NFCB_DM_GETINFO_PIPE_INFO,
- ST21NFCB_TERMINAL_HOST_ID, 0};
+ struct st_nci_pipe_info *dm_pipe_info;
+ u8 pipe_list[] = { ST_NCI_DM_GETINFO_PIPE_LIST,
+ ST_NCI_TERMINAL_HOST_ID};
+ u8 pipe_info[] = { ST_NCI_DM_GETINFO_PIPE_INFO,
+ ST_NCI_TERMINAL_HOST_ID, 0};
- /* On ST21NFCB device pipes number are dynamics
+ /* On ST_NCI device pipes number are dynamics
* If pipes are already created, hci_dev_up will fail.
* Doing a clear all pipe is a bad idea because:
* - It does useless EEPROM cycling
* - It might cause issue for secure elements support
* (such as removing connectivity or APDU reader pipe)
- * A better approach on ST21NFCB is to:
+ * A better approach on ST_NCI is to:
* - get a pipe list for each host.
- * (eg: ST21NFCB_HOST_CONTROLLER_ID for now).
+ * (eg: ST_NCI_HOST_CONTROLLER_ID for now).
* (TODO Later on UICC HOST and eSE HOST)
* - get pipe information
- * - match retrieved pipe list in st21nfcb_gates
- * ST21NFCB_DEVICE_MGNT_GATE is a proprietary gate
- * with ST21NFCB_DEVICE_MGNT_PIPE.
+ * - match retrieved pipe list in st_nci_gates
+ * ST_NCI_DEVICE_MGNT_GATE is a proprietary gate
+ * with ST_NCI_DEVICE_MGNT_PIPE.
* Pipe can be closed and need to be open.
*/
- r = nci_hci_connect_gate(ndev, ST21NFCB_HOST_CONTROLLER_ID,
- ST21NFCB_DEVICE_MGNT_GATE,
- ST21NFCB_DEVICE_MGNT_PIPE);
+ r = nci_hci_connect_gate(ndev, ST_NCI_HOST_CONTROLLER_ID,
+ ST_NCI_DEVICE_MGNT_GATE,
+ ST_NCI_DEVICE_MGNT_PIPE);
if (r < 0)
goto free_info;
/* Get pipe list */
- r = nci_hci_send_cmd(ndev, ST21NFCB_DEVICE_MGNT_GATE,
- ST21NFCB_DM_GETINFO, pipe_list, sizeof(pipe_list),
+ r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
+ ST_NCI_DM_GETINFO, pipe_list, sizeof(pipe_list),
&skb_pipe_list);
if (r < 0)
goto free_info;
@@ -201,8 +201,8 @@ int st21nfcb_hci_load_session(struct nci_dev *ndev)
/* Complete the existing gate_pipe table */
for (i = 0; i < skb_pipe_list->len; i++) {
pipe_info[2] = skb_pipe_list->data[i];
- r = nci_hci_send_cmd(ndev, ST21NFCB_DEVICE_MGNT_GATE,
- ST21NFCB_DM_GETINFO, pipe_info,
+ r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
+ ST_NCI_DM_GETINFO, pipe_info,
sizeof(pipe_info), &skb_pipe_info);
if (r)
@@ -217,81 +217,81 @@ int st21nfcb_hci_load_session(struct nci_dev *ndev)
* - destination hid (1byte)
* - destination gid (1byte)
*/
- dm_pipe_info = (struct st21nfcb_pipe_info *)skb_pipe_info->data;
- if (dm_pipe_info->dst_gate_id == ST21NFCB_APDU_READER_GATE &&
- dm_pipe_info->src_host_id != ST21NFCB_ESE_HOST_ID) {
+ dm_pipe_info = (struct st_nci_pipe_info *)skb_pipe_info->data;
+ if (dm_pipe_info->dst_gate_id == ST_NCI_APDU_READER_GATE &&
+ dm_pipe_info->src_host_id != ST_NCI_ESE_HOST_ID) {
pr_err("Unexpected apdu_reader pipe on host %x\n",
dm_pipe_info->src_host_id);
continue;
}
- for (j = 0; (j < ARRAY_SIZE(st21nfcb_gates)) &&
- (st21nfcb_gates[j].gate != dm_pipe_info->dst_gate_id); j++)
+ for (j = 0; (j < ARRAY_SIZE(st_nci_gates)) &&
+ (st_nci_gates[j].gate != dm_pipe_info->dst_gate_id); j++)
;
- if (j < ARRAY_SIZE(st21nfcb_gates) &&
- st21nfcb_gates[j].gate == dm_pipe_info->dst_gate_id &&
- ST21NFCB_DM_IS_PIPE_OPEN(dm_pipe_info->pipe_state)) {
- st21nfcb_gates[j].pipe = pipe_info[2];
+ if (j < ARRAY_SIZE(st_nci_gates) &&
+ st_nci_gates[j].gate == dm_pipe_info->dst_gate_id &&
+ ST_NCI_DM_IS_PIPE_OPEN(dm_pipe_info->pipe_state)) {
+ st_nci_gates[j].pipe = pipe_info[2];
- ndev->hci_dev->gate2pipe[st21nfcb_gates[j].gate] =
- st21nfcb_gates[j].pipe;
- ndev->hci_dev->pipes[st21nfcb_gates[j].pipe].gate =
- st21nfcb_gates[j].gate;
- ndev->hci_dev->pipes[st21nfcb_gates[j].pipe].host =
+ ndev->hci_dev->gate2pipe[st_nci_gates[j].gate] =
+ st_nci_gates[j].pipe;
+ ndev->hci_dev->pipes[st_nci_gates[j].pipe].gate =
+ st_nci_gates[j].gate;
+ ndev->hci_dev->pipes[st_nci_gates[j].pipe].host =
dm_pipe_info->src_host_id;
}
}
- memcpy(ndev->hci_dev->init_data.gates, st21nfcb_gates,
- sizeof(st21nfcb_gates));
+ memcpy(ndev->hci_dev->init_data.gates, st_nci_gates,
+ sizeof(st_nci_gates));
free_info:
kfree_skb(skb_pipe_info);
kfree_skb(skb_pipe_list);
return r;
}
-EXPORT_SYMBOL_GPL(st21nfcb_hci_load_session);
+EXPORT_SYMBOL_GPL(st_nci_hci_load_session);
-static void st21nfcb_hci_admin_event_received(struct nci_dev *ndev,
+static void st_nci_hci_admin_event_received(struct nci_dev *ndev,
u8 event, struct sk_buff *skb)
{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
switch (event) {
- case ST21NFCB_EVT_HOT_PLUG:
+ case ST_NCI_EVT_HOT_PLUG:
if (info->se_info.se_active) {
- if (!ST21NFCB_EVT_HOT_PLUG_IS_INHIBITED(skb)) {
+ if (!ST_NCI_EVT_HOT_PLUG_IS_INHIBITED(skb)) {
del_timer_sync(&info->se_info.se_active_timer);
info->se_info.se_active = false;
complete(&info->se_info.req_completion);
} else {
mod_timer(&info->se_info.se_active_timer,
jiffies +
- msecs_to_jiffies(ST21NFCB_SE_TO_PIPES));
+ msecs_to_jiffies(ST_NCI_SE_TO_PIPES));
}
}
break;
}
}
-static int st21nfcb_hci_apdu_reader_event_received(struct nci_dev *ndev,
+static int st_nci_hci_apdu_reader_event_received(struct nci_dev *ndev,
u8 event,
struct sk_buff *skb)
{
int r = 0;
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
pr_debug("apdu reader gate event: %x\n", event);
switch (event) {
- case ST21NFCB_EVT_TRANSMIT_DATA:
+ case ST_NCI_EVT_TRANSMIT_DATA:
del_timer_sync(&info->se_info.bwi_timer);
info->se_info.bwi_active = false;
info->se_info.cb(info->se_info.cb_context,
skb->data, skb->len, 0);
break;
- case ST21NFCB_EVT_WTX_REQUEST:
+ case ST_NCI_EVT_WTX_REQUEST:
mod_timer(&info->se_info.bwi_timer, jiffies +
msecs_to_jiffies(info->se_info.wt_timeout));
break;
@@ -306,7 +306,7 @@ static int st21nfcb_hci_apdu_reader_event_received(struct nci_dev *ndev,
* <= 0: driver handled the event, skb consumed
* 1: driver does not handle the event, please do standard processing
*/
-static int st21nfcb_hci_connectivity_event_received(struct nci_dev *ndev,
+static int st_nci_hci_connectivity_event_received(struct nci_dev *ndev,
u8 host, u8 event,
struct sk_buff *skb)
{
@@ -317,10 +317,10 @@ static int st21nfcb_hci_connectivity_event_received(struct nci_dev *ndev,
pr_debug("connectivity gate event: %x\n", event);
switch (event) {
- case ST21NFCB_EVT_CONNECTIVITY:
+ case ST_NCI_EVT_CONNECTIVITY:
break;
- case ST21NFCB_EVT_TRANSACTION:
+ case ST_NCI_EVT_TRANSACTION:
/* According to specification etsi 102 622
* 11.2.2.4 EVT_TRANSACTION Table 52
* Description Tag Length
@@ -355,7 +355,7 @@ static int st21nfcb_hci_connectivity_event_received(struct nci_dev *ndev,
return r;
}
-void st21nfcb_hci_event_received(struct nci_dev *ndev, u8 pipe,
+void st_nci_hci_event_received(struct nci_dev *ndev, u8 pipe,
u8 event, struct sk_buff *skb)
{
u8 gate = ndev->hci_dev->pipes[pipe].gate;
@@ -363,32 +363,32 @@ void st21nfcb_hci_event_received(struct nci_dev *ndev, u8 pipe,
switch (gate) {
case NCI_HCI_ADMIN_GATE:
- st21nfcb_hci_admin_event_received(ndev, event, skb);
+ st_nci_hci_admin_event_received(ndev, event, skb);
break;
- case ST21NFCB_APDU_READER_GATE:
- st21nfcb_hci_apdu_reader_event_received(ndev, event, skb);
+ case ST_NCI_APDU_READER_GATE:
+ st_nci_hci_apdu_reader_event_received(ndev, event, skb);
break;
- case ST21NFCB_CONNECTIVITY_GATE:
- st21nfcb_hci_connectivity_event_received(ndev, host, event,
+ case ST_NCI_CONNECTIVITY_GATE:
+ st_nci_hci_connectivity_event_received(ndev, host, event,
skb);
break;
}
}
-EXPORT_SYMBOL_GPL(st21nfcb_hci_event_received);
+EXPORT_SYMBOL_GPL(st_nci_hci_event_received);
-void st21nfcb_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
+void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
struct sk_buff *skb)
{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
u8 gate = ndev->hci_dev->pipes[pipe].gate;
pr_debug("cmd: %x\n", cmd);
switch (cmd) {
case NCI_HCI_ANY_OPEN_PIPE:
- if (gate != ST21NFCB_APDU_READER_GATE &&
- ndev->hci_dev->pipes[pipe].host != ST21NFCB_UICC_HOST_ID)
+ if (gate != ST_NCI_APDU_READER_GATE &&
+ ndev->hci_dev->pipes[pipe].host != ST_NCI_UICC_HOST_ID)
ndev->hci_dev->count_pipes++;
if (ndev->hci_dev->count_pipes ==
@@ -401,28 +401,28 @@ void st21nfcb_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
break;
}
}
-EXPORT_SYMBOL_GPL(st21nfcb_hci_cmd_received);
+EXPORT_SYMBOL_GPL(st_nci_hci_cmd_received);
/*
- * Remarks: On some early st21nfcb firmware, nci_nfcee_mode_set(0)
+ * Remarks: On some early st_nci firmware, nci_nfcee_mode_set(0)
* is rejected
*/
-static int st21nfcb_nci_control_se(struct nci_dev *ndev, u8 se_idx,
+static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx,
u8 state)
{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
int r;
struct sk_buff *sk_host_list;
u8 host_id;
switch (se_idx) {
- case ST21NFCB_UICC_HOST_ID:
+ case ST_NCI_UICC_HOST_ID:
ndev->hci_dev->count_pipes = 0;
- ndev->hci_dev->expected_pipes = ST21NFCB_SE_COUNT_PIPE_UICC;
+ ndev->hci_dev->expected_pipes = ST_NCI_SE_COUNT_PIPE_UICC;
break;
- case ST21NFCB_ESE_HOST_ID:
+ case ST_NCI_ESE_HOST_ID:
ndev->hci_dev->count_pipes = 0;
- ndev->hci_dev->expected_pipes = ST21NFCB_SE_COUNT_PIPE_EMBEDDED;
+ ndev->hci_dev->expected_pipes = ST_NCI_SE_COUNT_PIPE_EMBEDDED;
break;
default:
return -EINVAL;
@@ -438,7 +438,7 @@ static int st21nfcb_nci_control_se(struct nci_dev *ndev, u8 se_idx,
return r;
mod_timer(&info->se_info.se_active_timer, jiffies +
- msecs_to_jiffies(ST21NFCB_SE_TO_HOT_PLUG));
+ msecs_to_jiffies(ST_NCI_SE_TO_HOT_PLUG));
info->se_info.se_active = true;
/* Ignore return value and check in any case the host_list */
@@ -458,49 +458,49 @@ static int st21nfcb_nci_control_se(struct nci_dev *ndev, u8 se_idx,
host_id = sk_host_list->data[sk_host_list->len - 1];
kfree_skb(sk_host_list);
- if (state == ST21NFCB_SE_MODE_ON && host_id == se_idx)
+ if (state == ST_NCI_SE_MODE_ON && host_id == se_idx)
return se_idx;
- else if (state == ST21NFCB_SE_MODE_OFF && host_id != se_idx)
+ else if (state == ST_NCI_SE_MODE_OFF && host_id != se_idx)
return se_idx;
return -1;
}
-int st21nfcb_nci_disable_se(struct nci_dev *ndev, u32 se_idx)
+int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx)
{
int r;
- pr_debug("st21nfcb_nci_disable_se\n");
+ pr_debug("st_nci_disable_se\n");
if (se_idx == NFC_SE_EMBEDDED) {
- r = nci_hci_send_event(ndev, ST21NFCB_APDU_READER_GATE,
- ST21NFCB_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0);
+ r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
+ ST_NCI_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0);
if (r < 0)
return r;
}
return 0;
}
-EXPORT_SYMBOL_GPL(st21nfcb_nci_disable_se);
+EXPORT_SYMBOL_GPL(st_nci_disable_se);
-int st21nfcb_nci_enable_se(struct nci_dev *ndev, u32 se_idx)
+int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx)
{
int r;
- pr_debug("st21nfcb_nci_enable_se\n");
+ pr_debug("st_nci_enable_se\n");
- if (se_idx == ST21NFCB_HCI_HOST_ID_ESE) {
- r = nci_hci_send_event(ndev, ST21NFCB_APDU_READER_GATE,
- ST21NFCB_EVT_SE_SOFT_RESET, NULL, 0);
+ if (se_idx == ST_NCI_HCI_HOST_ID_ESE) {
+ r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
+ ST_NCI_EVT_SE_SOFT_RESET, NULL, 0);
if (r < 0)
return r;
}
return 0;
}
-EXPORT_SYMBOL_GPL(st21nfcb_nci_enable_se);
+EXPORT_SYMBOL_GPL(st_nci_enable_se);
-static int st21nfcb_hci_network_init(struct nci_dev *ndev)
+static int st_nci_hci_network_init(struct nci_dev *ndev)
{
struct core_conn_create_dest_spec_params *dest_params;
struct dest_spec_params spec_params;
@@ -519,7 +519,8 @@ static int st21nfcb_hci_network_init(struct nci_dev *ndev)
dest_params->length = sizeof(struct dest_spec_params);
spec_params.id = ndev->hci_dev->nfcee_id;
spec_params.protocol = NCI_NFCEE_INTERFACE_HCI_ACCESS;
- memcpy(dest_params->value, &spec_params, sizeof(struct dest_spec_params));
+ memcpy(dest_params->value, &spec_params,
+ sizeof(struct dest_spec_params));
r = nci_core_conn_create(ndev, NCI_DESTINATION_NFCEE, 1,
sizeof(struct core_conn_create_dest_spec_params) +
sizeof(struct dest_spec_params),
@@ -531,15 +532,15 @@ static int st21nfcb_hci_network_init(struct nci_dev *ndev)
if (!conn_info)
goto free_dest_params;
- memcpy(ndev->hci_dev->init_data.gates, st21nfcb_gates,
- sizeof(st21nfcb_gates));
+ memcpy(ndev->hci_dev->init_data.gates, st_nci_gates,
+ sizeof(st_nci_gates));
/*
* Session id must include the driver name + i2c bus addr
* persistent info to discriminate 2 identical chips
*/
- dev_num = find_first_zero_bit(dev_mask, ST21NFCB_NUM_DEVICES);
- if (dev_num >= ST21NFCB_NUM_DEVICES) {
+ dev_num = find_first_zero_bit(dev_mask, ST_NCI_NUM_DEVICES);
+ if (dev_num >= ST_NCI_NUM_DEVICES) {
r = -ENODEV;
goto free_dest_params;
}
@@ -564,72 +565,72 @@ exit:
return r;
}
-int st21nfcb_nci_discover_se(struct nci_dev *ndev)
+int st_nci_discover_se(struct nci_dev *ndev)
{
u8 param[2];
int r;
int se_count = 0;
- pr_debug("st21nfcb_nci_discover_se\n");
+ pr_debug("st_nci_discover_se\n");
- r = st21nfcb_hci_network_init(ndev);
+ r = st_nci_hci_network_init(ndev);
if (r != 0)
return r;
- param[0] = ST21NFCB_UICC_HOST_ID;
- param[1] = ST21NFCB_HCI_HOST_ID_ESE;
+ param[0] = ST_NCI_UICC_HOST_ID;
+ param[1] = ST_NCI_HCI_HOST_ID_ESE;
r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE,
NCI_HCI_ADMIN_PARAM_WHITELIST,
param, sizeof(param));
if (r != NCI_HCI_ANY_OK)
return r;
- r = st21nfcb_nci_control_se(ndev, ST21NFCB_UICC_HOST_ID,
- ST21NFCB_SE_MODE_ON);
- if (r == ST21NFCB_UICC_HOST_ID) {
- nfc_add_se(ndev->nfc_dev, ST21NFCB_UICC_HOST_ID, NFC_SE_UICC);
+ r = st_nci_control_se(ndev, ST_NCI_UICC_HOST_ID,
+ ST_NCI_SE_MODE_ON);
+ if (r == ST_NCI_UICC_HOST_ID) {
+ nfc_add_se(ndev->nfc_dev, ST_NCI_UICC_HOST_ID, NFC_SE_UICC);
se_count++;
}
/* Try to enable eSE in order to check availability */
- r = st21nfcb_nci_control_se(ndev, ST21NFCB_HCI_HOST_ID_ESE,
- ST21NFCB_SE_MODE_ON);
- if (r == ST21NFCB_HCI_HOST_ID_ESE) {
- nfc_add_se(ndev->nfc_dev, ST21NFCB_HCI_HOST_ID_ESE,
+ r = st_nci_control_se(ndev, ST_NCI_HCI_HOST_ID_ESE,
+ ST_NCI_SE_MODE_ON);
+ if (r == ST_NCI_HCI_HOST_ID_ESE) {
+ nfc_add_se(ndev->nfc_dev, ST_NCI_HCI_HOST_ID_ESE,
NFC_SE_EMBEDDED);
se_count++;
- st21nfcb_se_get_atr(ndev);
+ st_nci_se_get_atr(ndev);
}
return !se_count;
}
-EXPORT_SYMBOL_GPL(st21nfcb_nci_discover_se);
+EXPORT_SYMBOL_GPL(st_nci_discover_se);
-int st21nfcb_nci_se_io(struct nci_dev *ndev, u32 se_idx,
+int st_nci_se_io(struct nci_dev *ndev, u32 se_idx,
u8 *apdu, size_t apdu_length,
se_io_cb_t cb, void *cb_context)
{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
pr_debug("\n");
switch (se_idx) {
- case ST21NFCB_HCI_HOST_ID_ESE:
+ case ST_NCI_HCI_HOST_ID_ESE:
info->se_info.cb = cb;
info->se_info.cb_context = cb_context;
mod_timer(&info->se_info.bwi_timer, jiffies +
msecs_to_jiffies(info->se_info.wt_timeout));
info->se_info.bwi_active = true;
- return nci_hci_send_event(ndev, ST21NFCB_APDU_READER_GATE,
- ST21NFCB_EVT_TRANSMIT_DATA, apdu,
+ return nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
+ ST_NCI_EVT_TRANSMIT_DATA, apdu,
apdu_length);
default:
return -ENODEV;
}
}
-EXPORT_SYMBOL(st21nfcb_nci_se_io);
+EXPORT_SYMBOL(st_nci_se_io);
-static void st21nfcb_se_wt_timeout(unsigned long data)
+static void st_nci_se_wt_timeout(unsigned long data)
{
/*
* No answer from the secure element
@@ -642,7 +643,7 @@ static void st21nfcb_se_wt_timeout(unsigned long data)
*/
/* hardware reset managed through VCC_UICC_OUT power supply */
u8 param = 0x01;
- struct st21nfcb_nci_info *info = (struct st21nfcb_nci_info *) data;
+ struct st_nci_info *info = (struct st_nci_info *) data;
pr_debug("\n");
@@ -650,19 +651,19 @@ static void st21nfcb_se_wt_timeout(unsigned long data)
if (!info->se_info.xch_error) {
info->se_info.xch_error = true;
- nci_hci_send_event(info->ndlc->ndev, ST21NFCB_APDU_READER_GATE,
- ST21NFCB_EVT_SE_SOFT_RESET, NULL, 0);
+ nci_hci_send_event(info->ndlc->ndev, ST_NCI_APDU_READER_GATE,
+ ST_NCI_EVT_SE_SOFT_RESET, NULL, 0);
} else {
info->se_info.xch_error = false;
- nci_hci_send_event(info->ndlc->ndev, ST21NFCB_DEVICE_MGNT_GATE,
- ST21NFCB_EVT_SE_HARD_RESET, &param, 1);
+ nci_hci_send_event(info->ndlc->ndev, ST_NCI_DEVICE_MGNT_GATE,
+ ST_NCI_EVT_SE_HARD_RESET, &param, 1);
}
info->se_info.cb(info->se_info.cb_context, NULL, 0, -ETIME);
}
-static void st21nfcb_se_activation_timeout(unsigned long data)
+static void st_nci_se_activation_timeout(unsigned long data)
{
- struct st21nfcb_nci_info *info = (struct st21nfcb_nci_info *) data;
+ struct st_nci_info *info = (struct st_nci_info *) data;
pr_debug("\n");
@@ -671,35 +672,35 @@ static void st21nfcb_se_activation_timeout(unsigned long data)
complete(&info->se_info.req_completion);
}
-int st21nfcb_se_init(struct nci_dev *ndev)
+int st_nci_se_init(struct nci_dev *ndev)
{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
init_completion(&info->se_info.req_completion);
/* initialize timers */
init_timer(&info->se_info.bwi_timer);
info->se_info.bwi_timer.data = (unsigned long)info;
- info->se_info.bwi_timer.function = st21nfcb_se_wt_timeout;
+ info->se_info.bwi_timer.function = st_nci_se_wt_timeout;
info->se_info.bwi_active = false;
init_timer(&info->se_info.se_active_timer);
info->se_info.se_active_timer.data = (unsigned long)info;
info->se_info.se_active_timer.function =
- st21nfcb_se_activation_timeout;
+ st_nci_se_activation_timeout;
info->se_info.se_active = false;
info->se_info.xch_error = false;
info->se_info.wt_timeout =
- ST21NFCB_BWI_TO_TIMEOUT(ST21NFCB_ATR_DEFAULT_BWI);
+ ST_NCI_BWI_TO_TIMEOUT(ST_NCI_ATR_DEFAULT_BWI);
return 0;
}
-EXPORT_SYMBOL(st21nfcb_se_init);
+EXPORT_SYMBOL(st_nci_se_init);
-void st21nfcb_se_deinit(struct nci_dev *ndev)
+void st_nci_se_deinit(struct nci_dev *ndev)
{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
if (info->se_info.bwi_active)
del_timer_sync(&info->se_info.bwi_timer);
@@ -709,5 +710,5 @@ void st21nfcb_se_deinit(struct nci_dev *ndev)
info->se_info.se_active = false;
info->se_info.bwi_active = false;
}
-EXPORT_SYMBOL(st21nfcb_se_deinit);
+EXPORT_SYMBOL(st_nci_se_deinit);
diff --git a/drivers/nfc/st-nci/st-nci_se.h b/drivers/nfc/st-nci/st-nci_se.h
new file mode 100644
index 000000000000..ea66e879d67f
--- /dev/null
+++ b/drivers/nfc/st-nci/st-nci_se.h
@@ -0,0 +1,61 @@
+/*
+ * Secure Element Driver for STMicroelectronics NFC NCI Chip
+ *
+ * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved.
+ *
+ * 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 that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __LOCAL_ST_NCI_SE_H_
+#define __LOCAL_ST_NCI_SE_H_
+
+/*
+ * ref ISO7816-3 chap 8.1. the initial character TS is followed by a
+ * sequence of at most 32 characters.
+ */
+#define ST_NCI_ESE_MAX_LENGTH 33
+#define ST_NCI_HCI_HOST_ID_ESE 0xc0
+
+struct st_nci_se_info {
+ u8 atr[ST_NCI_ESE_MAX_LENGTH];
+ struct completion req_completion;
+
+ struct timer_list bwi_timer;
+ int wt_timeout; /* in msecs */
+ bool bwi_active;
+
+ struct timer_list se_active_timer;
+ bool se_active;
+
+ bool xch_error;
+
+ se_io_cb_t cb;
+ void *cb_context;
+};
+
+int st_nci_se_init(struct nci_dev *ndev);
+void st_nci_se_deinit(struct nci_dev *ndev);
+
+int st_nci_discover_se(struct nci_dev *ndev);
+int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx);
+int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx);
+int st_nci_se_io(struct nci_dev *ndev, u32 se_idx,
+ u8 *apdu, size_t apdu_length,
+ se_io_cb_t cb, void *cb_context);
+int st_nci_hci_load_session(struct nci_dev *ndev);
+void st_nci_hci_event_received(struct nci_dev *ndev, u8 pipe,
+ u8 event, struct sk_buff *skb);
+void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
+ struct sk_buff *skb);
+
+
+#endif /* __LOCAL_ST_NCI_SE_H_ */
diff --git a/drivers/nfc/st21nfcb/Kconfig b/drivers/nfc/st21nfcb/Kconfig
deleted file mode 100644
index e0322dd03a70..000000000000
--- a/drivers/nfc/st21nfcb/Kconfig
+++ /dev/null
@@ -1,22 +0,0 @@
-config NFC_ST21NFCB
- tristate "STMicroelectronics ST21NFCB NFC driver"
- depends on NFC_NCI
- default n
- ---help---
- STMicroelectronics ST21NFCB core driver. It implements the chipset
- NCI logic and hooks into the NFC kernel APIs. Physical layers will
- register against it.
-
- To compile this driver as a module, choose m here. The module will
- be called st21nfcb.
- Say N if unsure.
-
-config NFC_ST21NFCB_I2C
- tristate "NFC ST21NFCB i2c support"
- depends on NFC_ST21NFCB && I2C
- ---help---
- This module adds support for the STMicroelectronics st21nfcb i2c interface.
- Select this if your platform is using the i2c bus.
-
- If you choose to build a module, it'll be called st21nfcb_i2c.
- Say N if unsure.
diff --git a/drivers/nfc/st21nfcb/Makefile b/drivers/nfc/st21nfcb/Makefile
deleted file mode 100644
index ce659a9e5a1a..000000000000
--- a/drivers/nfc/st21nfcb/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile for ST21NFCB NCI based NFC driver
-#
-
-st21nfcb_nci-objs = ndlc.o st21nfcb.o st21nfcb_se.o
-obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb_nci.o
-
-st21nfcb_i2c-objs = i2c.o
-obj-$(CONFIG_NFC_ST21NFCB_I2C) += st21nfcb_i2c.o
diff --git a/drivers/nfc/st21nfcb/st21nfcb.c b/drivers/nfc/st21nfcb/st21nfcb.c
deleted file mode 100644
index ca9871ab3fb3..000000000000
--- a/drivers/nfc/st21nfcb/st21nfcb.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * NCI based Driver for STMicroelectronics NFC Chip
- *
- * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
- *
- * 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 that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/module.h>
-#include <linux/nfc.h>
-#include <net/nfc/nci.h>
-#include <net/nfc/nci_core.h>
-
-#include "st21nfcb.h"
-#include "st21nfcb_se.h"
-
-#define DRIVER_DESC "NCI NFC driver for ST21NFCB"
-
-#define ST21NFCB_NCI1_X_PROPRIETARY_ISO15693 0x83
-
-static int st21nfcb_nci_open(struct nci_dev *ndev)
-{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
- int r;
-
- if (test_and_set_bit(ST21NFCB_NCI_RUNNING, &info->flags))
- return 0;
-
- r = ndlc_open(info->ndlc);
- if (r)
- clear_bit(ST21NFCB_NCI_RUNNING, &info->flags);
-
- return r;
-}
-
-static int st21nfcb_nci_close(struct nci_dev *ndev)
-{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
-
- if (!test_and_clear_bit(ST21NFCB_NCI_RUNNING, &info->flags))
- return 0;
-
- ndlc_close(info->ndlc);
-
- return 0;
-}
-
-static int st21nfcb_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
-{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
-
- skb->dev = (void *)ndev;
-
- if (!test_bit(ST21NFCB_NCI_RUNNING, &info->flags))
- return -EBUSY;
-
- return ndlc_send(info->ndlc, skb);
-}
-
-static __u32 st21nfcb_nci_get_rfprotocol(struct nci_dev *ndev,
- __u8 rf_protocol)
-{
- return rf_protocol == ST21NFCB_NCI1_X_PROPRIETARY_ISO15693 ?
- NFC_PROTO_ISO15693_MASK : 0;
-}
-
-static struct nci_ops st21nfcb_nci_ops = {
- .open = st21nfcb_nci_open,
- .close = st21nfcb_nci_close,
- .send = st21nfcb_nci_send,
- .get_rfprotocol = st21nfcb_nci_get_rfprotocol,
- .discover_se = st21nfcb_nci_discover_se,
- .enable_se = st21nfcb_nci_enable_se,
- .disable_se = st21nfcb_nci_disable_se,
- .se_io = st21nfcb_nci_se_io,
- .hci_load_session = st21nfcb_hci_load_session,
- .hci_event_received = st21nfcb_hci_event_received,
- .hci_cmd_received = st21nfcb_hci_cmd_received,
-};
-
-int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
- int phy_tailroom)
-{
- struct st21nfcb_nci_info *info;
- int r;
- u32 protocols;
-
- info = devm_kzalloc(ndlc->dev,
- sizeof(struct st21nfcb_nci_info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- protocols = NFC_PROTO_JEWEL_MASK
- | NFC_PROTO_MIFARE_MASK
- | NFC_PROTO_FELICA_MASK
- | NFC_PROTO_ISO14443_MASK
- | NFC_PROTO_ISO14443_B_MASK
- | NFC_PROTO_ISO15693_MASK
- | NFC_PROTO_NFC_DEP_MASK;
-
- ndlc->ndev = nci_allocate_device(&st21nfcb_nci_ops, protocols,
- phy_headroom, phy_tailroom);
- if (!ndlc->ndev) {
- pr_err("Cannot allocate nfc ndev\n");
- return -ENOMEM;
- }
- info->ndlc = ndlc;
-
- nci_set_drvdata(ndlc->ndev, info);
-
- r = nci_register_device(ndlc->ndev);
- if (r) {
- pr_err("Cannot register nfc device to nci core\n");
- nci_free_device(ndlc->ndev);
- return r;
- }
-
- return st21nfcb_se_init(ndlc->ndev);
-}
-EXPORT_SYMBOL_GPL(st21nfcb_nci_probe);
-
-void st21nfcb_nci_remove(struct nci_dev *ndev)
-{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
-
- nci_unregister_device(ndev);
- nci_free_device(ndev);
- kfree(info);
-}
-EXPORT_SYMBOL_GPL(st21nfcb_nci_remove);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/st21nfcb/st21nfcb_se.h b/drivers/nfc/st21nfcb/st21nfcb_se.h
deleted file mode 100644
index 52a323872bea..000000000000
--- a/drivers/nfc/st21nfcb/st21nfcb_se.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * NCI based Driver for STMicroelectronics NFC Chip
- *
- * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
- *
- * 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 that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef __LOCAL_ST21NFCB_SE_H_
-#define __LOCAL_ST21NFCB_SE_H_
-
-/*
- * ref ISO7816-3 chap 8.1. the initial character TS is followed by a
- * sequence of at most 32 characters.
- */
-#define ST21NFCB_ESE_MAX_LENGTH 33
-#define ST21NFCB_HCI_HOST_ID_ESE 0xc0
-
-struct st21nfcb_se_info {
- u8 atr[ST21NFCB_ESE_MAX_LENGTH];
- struct completion req_completion;
-
- struct timer_list bwi_timer;
- int wt_timeout; /* in msecs */
- bool bwi_active;
-
- struct timer_list se_active_timer;
- bool se_active;
-
- bool xch_error;
-
- se_io_cb_t cb;
- void *cb_context;
-};
-
-int st21nfcb_se_init(struct nci_dev *ndev);
-void st21nfcb_se_deinit(struct nci_dev *ndev);
-
-int st21nfcb_nci_discover_se(struct nci_dev *ndev);
-int st21nfcb_nci_enable_se(struct nci_dev *ndev, u32 se_idx);
-int st21nfcb_nci_disable_se(struct nci_dev *ndev, u32 se_idx);
-int st21nfcb_nci_se_io(struct nci_dev *ndev, u32 se_idx,
- u8 *apdu, size_t apdu_length,
- se_io_cb_t cb, void *cb_context);
-int st21nfcb_hci_load_session(struct nci_dev *ndev);
-void st21nfcb_hci_event_received(struct nci_dev *ndev, u8 pipe,
- u8 event, struct sk_buff *skb);
-void st21nfcb_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
- struct sk_buff *skb);
-
-
-#endif /* __LOCAL_ST21NFCB_NCI_H_ */
diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
index aa6a333b2ead..85b4d86772d8 100644
--- a/drivers/nfc/trf7970a.c
+++ b/drivers/nfc/trf7970a.c
@@ -149,6 +149,7 @@
*/
#define TRF7970A_QUIRK_IRQ_STATUS_READ BIT(0)
#define TRF7970A_QUIRK_EN2_MUST_STAY_LOW BIT(1)
+#define TRF7970A_QUIRK_T5T_RMB_EXTRA_BYTE BIT(2)
/* Direct commands */
#define TRF7970A_CMD_IDLE 0x00
@@ -446,6 +447,7 @@ struct trf7970a {
u8 md_rf_tech;
u8 tx_cmd;
bool issue_eof;
+ bool adjust_resp_len;
int en2_gpio;
int en_gpio;
struct mutex lock;
@@ -626,6 +628,11 @@ static void trf7970a_send_upstream(struct trf7970a *trf)
trf->aborting = false;
}
+ if (trf->adjust_resp_len) {
+ skb_trim(trf->rx_skb, trf->rx_skb->len - 1);
+ trf->adjust_resp_len = false;
+ }
+
trf->cb(trf->ddev, trf->cb_arg, trf->rx_skb);
trf->rx_skb = NULL;
@@ -1429,10 +1436,15 @@ static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb)
trf->iso_ctrl = iso_ctrl;
}
- if ((trf->framing == NFC_DIGITAL_FRAMING_ISO15693_T5T) &&
- trf7970a_is_iso15693_write_or_lock(req[1]) &&
- (req[0] & ISO15693_REQ_FLAG_OPTION))
- trf->issue_eof = true;
+ if (trf->framing == NFC_DIGITAL_FRAMING_ISO15693_T5T) {
+ if (trf7970a_is_iso15693_write_or_lock(req[1]) &&
+ (req[0] & ISO15693_REQ_FLAG_OPTION))
+ trf->issue_eof = true;
+ else if ((trf->quirks &
+ TRF7970A_QUIRK_T5T_RMB_EXTRA_BYTE) &&
+ (req[1] == ISO15693_CMD_READ_MULTIPLE_BLOCK))
+ trf->adjust_resp_len = true;
+ }
}
return 0;
@@ -1992,6 +2004,9 @@ static int trf7970a_probe(struct spi_device *spi)
return ret;
}
+ if (of_property_read_bool(np, "t5t-rmb-extra-byte-quirk"))
+ trf->quirks |= TRF7970A_QUIRK_T5T_RMB_EXTRA_BYTE;
+
if (of_property_read_bool(np, "irq-status-read-quirk"))
trf->quirks |= TRF7970A_QUIRK_IRQ_STATUS_READ;
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index 0c064485d1c2..fdc60db60829 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -68,6 +68,9 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi
phy->irq = mdio->irq[addr];
}
+ if (of_property_read_bool(child, "broken-turn-around"))
+ mdio->phy_ignore_ta_mask |= 1 << addr;
+
/* Associate the OF node with the device structure so it
* can be looked up later */
of_node_get(child);
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index aeb5729fbda6..100d9ac2ae1f 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -88,6 +88,15 @@ config PINCTRL_LANTIQ
select PINMUX
select PINCONF
+config PINCTRL_LPC18XX
+ bool "NXP LPC18XX/43XX SCU pinctrl driver"
+ depends on OF && (ARCH_LPC18XX || COMPILE_TEST)
+ default ARCH_LPC18XX
+ select PINMUX
+ select GENERIC_PINCONF
+ help
+ Pinctrl driver for NXP LPC18xx/43xx System Control Unit (SCU).
+
config PINCTRL_FALCON
bool
depends on SOC_FALCON
@@ -123,7 +132,17 @@ config PINCTRL_SIRF
bool "CSR SiRFprimaII pin controller driver"
depends on ARCH_SIRF
select PINMUX
+ select PINCONF
+ select GENERIC_PINCONF
+ select GPIOLIB_IRQCHIP
+
+config PINCTRL_PISTACHIO
+ def_bool y if MACH_PISTACHIO
+ depends on GPIOLIB
+ select PINMUX
+ select GENERIC_PINCONF
select GPIOLIB_IRQCHIP
+ select OF_GPIO
config PINCTRL_ST
bool
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 6eadf04a33b3..f4216d9347e2 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_PINCTRL_AMD) += pinctrl-amd.o
obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o
obj-$(CONFIG_PINCTRL_MESON) += meson/
obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o
+obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o
obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_SIRF) += sirf/
@@ -34,6 +35,7 @@ obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o
obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o
obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o
obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o
+obj-$(CONFIG_PINCTRL_LPC18XX) += pinctrl-lpc18xx.o
obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o
obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c
index 9641f1c7617e..c3c692e508e8 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c
@@ -1425,9 +1425,9 @@ static int __init bcm281xx_pinctrl_probe(struct platform_device *pdev)
pctl = pinctrl_register(&bcm281xx_pinctrl_desc,
&pdev->dev,
pdata);
- if (!pctl) {
+ if (IS_ERR(pctl)) {
dev_err(&pdev->dev, "Failed to register pinctrl\n");
- return -ENODEV;
+ return PTR_ERR(pctl);
}
platform_set_drvdata(pdev, pdata);
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
index 8d908e3f42c3..efcf2a2b3975 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -1036,9 +1036,9 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
}
pc->pctl_dev = pinctrl_register(&bcm2835_pinctrl_desc, dev, pc);
- if (!pc->pctl_dev) {
+ if (IS_ERR(pc->pctl_dev)) {
gpiochip_remove(&pc->gpio_chip);
- return -EINVAL;
+ return PTR_ERR(pc->pctl_dev);
}
pc->gpio_range = bcm2835_pinctrl_gpio_range;
diff --git a/drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c b/drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c
index e406e3d8c1c7..7d9482bf8252 100644
--- a/drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c
+++ b/drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c
@@ -38,7 +38,7 @@
#define CYGNUS_GPIO_DATA_IN_OFFSET 0x00
#define CYGNUS_GPIO_DATA_OUT_OFFSET 0x04
#define CYGNUS_GPIO_OUT_EN_OFFSET 0x08
-#define CYGNUS_GPIO_IN_TYPE_OFFSET 0x0c
+#define CYGNUS_GPIO_INT_TYPE_OFFSET 0x0c
#define CYGNUS_GPIO_INT_DE_OFFSET 0x10
#define CYGNUS_GPIO_INT_EDGE_OFFSET 0x14
#define CYGNUS_GPIO_INT_MSK_OFFSET 0x18
@@ -264,7 +264,7 @@ static int cygnus_gpio_irq_set_type(struct irq_data *d, unsigned int type)
}
spin_lock_irqsave(&chip->lock, flags);
- cygnus_set_bit(chip, CYGNUS_GPIO_IN_TYPE_OFFSET, gpio,
+ cygnus_set_bit(chip, CYGNUS_GPIO_INT_TYPE_OFFSET, gpio,
level_triggered);
cygnus_set_bit(chip, CYGNUS_GPIO_INT_DE_OFFSET, gpio, dual_edge);
cygnus_set_bit(chip, CYGNUS_GPIO_INT_EDGE_OFFSET, gpio,
@@ -750,9 +750,9 @@ static int cygnus_gpio_register_pinconf(struct cygnus_gpio *chip)
pctldesc->confops = &cygnus_pconf_ops;
chip->pctl = pinctrl_register(pctldesc, chip->dev, chip);
- if (!chip->pctl) {
+ if (IS_ERR(chip->pctl)) {
dev_err(chip->dev, "unable to register pinctrl device\n");
- return -EINVAL;
+ return PTR_ERR(chip->pctl);
}
return 0;
diff --git a/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c b/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c
index f9a9283caf81..9728f3db9126 100644
--- a/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c
+++ b/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c
@@ -989,9 +989,9 @@ static int cygnus_pinmux_probe(struct platform_device *pdev)
pinctrl->pctl = pinctrl_register(&cygnus_pinctrl_desc, &pdev->dev,
pinctrl);
- if (!pinctrl->pctl) {
+ if (IS_ERR(pinctrl->pctl)) {
dev_err(&pdev->dev, "unable to register Cygnus IOMUX pinctrl\n");
- return -EINVAL;
+ return PTR_ERR(pinctrl->pctl);
}
return 0;
diff --git a/drivers/pinctrl/berlin/berlin-bg2.c b/drivers/pinctrl/berlin/berlin-bg2.c
index b71a6fffef1b..b467e6e14f8a 100644
--- a/drivers/pinctrl/berlin/berlin-bg2.c
+++ b/drivers/pinctrl/berlin/berlin-bg2.c
@@ -20,24 +20,24 @@
static const struct berlin_desc_group berlin2_soc_pinctrl_groups[] = {
/* G */
BERLIN_PINCTRL_GROUP("G0", 0x00, 0x1, 0x00,
- BERLIN_PINCTRL_FUNCTION(0x0, "spi1"),
+ BERLIN_PINCTRL_FUNCTION(0x0, "spi1"), /* SS0n */
BERLIN_PINCTRL_FUNCTION(0x1, "gpio")),
BERLIN_PINCTRL_GROUP("G1", 0x00, 0x2, 0x01,
- BERLIN_PINCTRL_FUNCTION(0x0, "spi1"),
+ BERLIN_PINCTRL_FUNCTION(0x0, "spi1"), /* SS1n */
BERLIN_PINCTRL_FUNCTION(0x1, "gpio"),
BERLIN_PINCTRL_FUNCTION(0x2, "usb1")),
BERLIN_PINCTRL_GROUP("G2", 0x00, 0x2, 0x02,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
- BERLIN_PINCTRL_FUNCTION(0x1, "spi1"),
+ BERLIN_PINCTRL_FUNCTION(0x1, "spi1"), /* SS2n */
BERLIN_PINCTRL_FUNCTION(0x2, "pwm"),
BERLIN_PINCTRL_FUNCTION(0x3, "i2s0")),
BERLIN_PINCTRL_GROUP("G3", 0x00, 0x2, 0x04,
BERLIN_PINCTRL_FUNCTION(0x0, "soc"),
- BERLIN_PINCTRL_FUNCTION(0x1, "spi1"),
+ BERLIN_PINCTRL_FUNCTION(0x1, "spi1"), /* SS3n */
BERLIN_PINCTRL_FUNCTION(0x2, "gpio"),
BERLIN_PINCTRL_FUNCTION(0x3, "i2s1")),
BERLIN_PINCTRL_GROUP("G4", 0x00, 0x2, 0x06,
- BERLIN_PINCTRL_FUNCTION(0x0, "spi1"),
+ BERLIN_PINCTRL_FUNCTION(0x0, "spi1"), /* CLK/SDI/SDO */
BERLIN_PINCTRL_FUNCTION(0x1, "gpio"),
BERLIN_PINCTRL_FUNCTION(0x2, "pwm")),
BERLIN_PINCTRL_GROUP("G5", 0x00, 0x3, 0x08,
@@ -163,15 +163,15 @@ static const struct berlin_desc_group berlin2_sysmgr_pinctrl_groups[] = {
/* GSM */
BERLIN_PINCTRL_GROUP("GSM0", 0x40, 0x2, 0x00,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
- BERLIN_PINCTRL_FUNCTION(0x1, "spi2"),
+ BERLIN_PINCTRL_FUNCTION(0x1, "spi2"), /* SS0n */
BERLIN_PINCTRL_FUNCTION(0x2, "eth1")),
BERLIN_PINCTRL_GROUP("GSM1", 0x40, 0x2, 0x02,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
- BERLIN_PINCTRL_FUNCTION(0x1, "spi2"),
+ BERLIN_PINCTRL_FUNCTION(0x1, "spi2"), /* SS1n */
BERLIN_PINCTRL_FUNCTION(0x2, "eth1")),
BERLIN_PINCTRL_GROUP("GSM2", 0x40, 0x2, 0x04,
BERLIN_PINCTRL_FUNCTION(0x0, "twsi2"),
- BERLIN_PINCTRL_FUNCTION(0x1, "spi2")),
+ BERLIN_PINCTRL_FUNCTION(0x1, "spi2")), /* SS2n/SS3n */
BERLIN_PINCTRL_GROUP("GSM3", 0x40, 0x2, 0x06,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
BERLIN_PINCTRL_FUNCTION(0x1, "uart0"), /* CTS/RTS */
@@ -187,7 +187,7 @@ static const struct berlin_desc_group berlin2_sysmgr_pinctrl_groups[] = {
BERLIN_PINCTRL_FUNCTION(0x3, "twsi3")),
BERLIN_PINCTRL_GROUP("GSM6", 0x40, 0x2, 0x0c,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
- BERLIN_PINCTRL_FUNCTION(0x1, "spi2"),
+ BERLIN_PINCTRL_FUNCTION(0x1, "spi2"), /* CLK/SDO */
BERLIN_PINCTRL_FUNCTION(0x1, "clki")),
BERLIN_PINCTRL_GROUP("GSM7", 0x40, 0x1, 0x0e,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
diff --git a/drivers/pinctrl/berlin/berlin-bg2cd.c b/drivers/pinctrl/berlin/berlin-bg2cd.c
index 19ac5a22c947..a8b98083a031 100644
--- a/drivers/pinctrl/berlin/berlin-bg2cd.c
+++ b/drivers/pinctrl/berlin/berlin-bg2cd.c
@@ -68,17 +68,17 @@ static const struct berlin_desc_group berlin2cd_soc_pinctrl_groups[] = {
BERLIN_PINCTRL_FUNCTION(0x1, "twsi1"),
BERLIN_PINCTRL_FUNCTION(0x2, "gpio")),
BERLIN_PINCTRL_GROUP("G8", 0x00, 0x3, 0x10,
- BERLIN_PINCTRL_FUNCTION(0x0, "ss0"),
+ BERLIN_PINCTRL_FUNCTION(0x0, "spi1"), /* SS0n */
BERLIN_PINCTRL_FUNCTION(0x1, "gpio")),
BERLIN_PINCTRL_GROUP("G9", 0x00, 0x3, 0x13,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
- BERLIN_PINCTRL_FUNCTION(0x1, "spi1"),
+ BERLIN_PINCTRL_FUNCTION(0x1, "spi1"), /* SS1n/SS2n */
BERLIN_PINCTRL_FUNCTION(0x2, "twsi0")),
BERLIN_PINCTRL_GROUP("G10", 0x00, 0x2, 0x16,
- BERLIN_PINCTRL_FUNCTION(0x0, "spi1"),
+ BERLIN_PINCTRL_FUNCTION(0x0, "spi1"), /* CLK */
BERLIN_PINCTRL_FUNCTION(0x1, "gpio")),
BERLIN_PINCTRL_GROUP("G11", 0x00, 0x2, 0x18,
- BERLIN_PINCTRL_FUNCTION(0x0, "spi1"),
+ BERLIN_PINCTRL_FUNCTION(0x0, "spi1"), /* SDI/SDO */
BERLIN_PINCTRL_FUNCTION(0x1, "gpio")),
BERLIN_PINCTRL_GROUP("G12", 0x00, 0x3, 0x1a,
BERLIN_PINCTRL_FUNCTION(0x0, "usb1"),
diff --git a/drivers/pinctrl/berlin/berlin-bg2q.c b/drivers/pinctrl/berlin/berlin-bg2q.c
index bd9662e57ad3..65fb8711a42f 100644
--- a/drivers/pinctrl/berlin/berlin-bg2q.c
+++ b/drivers/pinctrl/berlin/berlin-bg2q.c
@@ -59,21 +59,21 @@ static const struct berlin_desc_group berlin2q_soc_pinctrl_groups[] = {
BERLIN_PINCTRL_FUNCTION(0x2, "gpio"),
BERLIN_PINCTRL_FUNCTION(0x3, "eddc")),
BERLIN_PINCTRL_GROUP("G8", 0x18, 0x3, 0x18,
- BERLIN_PINCTRL_FUNCTION(0x0, "spi1"),
+ BERLIN_PINCTRL_FUNCTION(0x0, "spi1"), /* CLK/SDI/SDO */
BERLIN_PINCTRL_FUNCTION(0x1, "gpio")),
BERLIN_PINCTRL_GROUP("G9", 0x18, 0x3, 0x1b,
- BERLIN_PINCTRL_FUNCTION(0x0, "spi1"),
+ BERLIN_PINCTRL_FUNCTION(0x0, "spi1"), /* SS0n/SS1n */
BERLIN_PINCTRL_FUNCTION(0x1, "gpio"),
BERLIN_PINCTRL_FUNCTION(0x5, "sata")),
BERLIN_PINCTRL_GROUP("G10", 0x1c, 0x3, 0x00,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
- BERLIN_PINCTRL_FUNCTION(0x1, "spi1"),
+ BERLIN_PINCTRL_FUNCTION(0x1, "spi1"), /* SS2n */
BERLIN_PINCTRL_FUNCTION(0x3, "i2s0"),
BERLIN_PINCTRL_FUNCTION(0x4, "pwm"),
BERLIN_PINCTRL_FUNCTION(0x5, "sata")),
BERLIN_PINCTRL_GROUP("G11", 0x1c, 0x3, 0x03,
BERLIN_PINCTRL_FUNCTION(0x0, "jtag"),
- BERLIN_PINCTRL_FUNCTION(0x1, "spi1"),
+ BERLIN_PINCTRL_FUNCTION(0x1, "spi1"), /* SS3n */
BERLIN_PINCTRL_FUNCTION(0x2, "gpio"),
BERLIN_PINCTRL_FUNCTION(0x3, "i2s1"),
BERLIN_PINCTRL_FUNCTION(0x4, "pwm"),
@@ -301,19 +301,19 @@ static const struct berlin_desc_group berlin2q_sysmgr_pinctrl_groups[] = {
/* GSM */
BERLIN_PINCTRL_GROUP("GSM0", 0x40, 0x2, 0x00,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
- BERLIN_PINCTRL_FUNCTION(0x1, "spi2"),
+ BERLIN_PINCTRL_FUNCTION(0x1, "spi2"), /* SS0n */
BERLIN_PINCTRL_FUNCTION(0x2, "eth1")),
BERLIN_PINCTRL_GROUP("GSM1", 0x40, 0x2, 0x02,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
- BERLIN_PINCTRL_FUNCTION(0x1, "spi2"),
+ BERLIN_PINCTRL_FUNCTION(0x1, "spi2"), /* SS1n */
BERLIN_PINCTRL_FUNCTION(0x2, "eth1")),
BERLIN_PINCTRL_GROUP("GSM2", 0x40, 0x2, 0x04,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
- BERLIN_PINCTRL_FUNCTION(0x1, "spi2"),
+ BERLIN_PINCTRL_FUNCTION(0x1, "spi2"), /* SS2n/SS3n */
BERLIN_PINCTRL_FUNCTION(0x2, "eddc")),
BERLIN_PINCTRL_GROUP("GSM3", 0x40, 0x2, 0x06,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
- BERLIN_PINCTRL_FUNCTION(0x1, "spi2"),
+ BERLIN_PINCTRL_FUNCTION(0x1, "spi2"), /* CLK/SDO */
BERLIN_PINCTRL_FUNCTION(0x2, "eddc")),
BERLIN_PINCTRL_GROUP("GSM4", 0x40, 0x1, 0x08,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"),
diff --git a/drivers/pinctrl/berlin/berlin.c b/drivers/pinctrl/berlin/berlin.c
index 7f0b0f93242b..ddbcd1d7de52 100644
--- a/drivers/pinctrl/berlin/berlin.c
+++ b/drivers/pinctrl/berlin/berlin.c
@@ -320,9 +320,9 @@ int berlin_pinctrl_probe(struct platform_device *pdev,
}
pctrl->pctrl_dev = pinctrl_register(&berlin_pctrl_desc, dev, pctrl);
- if (!pctrl->pctrl_dev) {
+ if (IS_ERR(pctrl->pctrl_dev)) {
dev_err(dev, "failed to register pinctrl driver\n");
- return -EINVAL;
+ return PTR_ERR(pctrl->pctrl_dev);
}
return 0;
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 18ee2089df4a..8b8f3a04c353 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -558,7 +558,7 @@ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
}
/**
- * pinctrl_request_gpio() - request a single pin to be used in as GPIO
+ * pinctrl_request_gpio() - request a single pin to be used as GPIO
* @gpio: the GPIO pin number from the GPIO subsystem number space
*
* This function should *ONLY* be used from gpiolib-based GPIO drivers,
@@ -1115,7 +1115,7 @@ int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
int i, ret;
struct pinctrl_maps *maps_node;
- pr_debug("add %d pinmux maps\n", num_maps);
+ pr_debug("add %u pinctrl maps\n", num_maps);
/* First sanity check the new mapping */
for (i = 0; i < num_maps; i++) {
@@ -1704,14 +1704,14 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
int ret;
if (!pctldesc)
- return NULL;
+ return ERR_PTR(-EINVAL);
if (!pctldesc->name)
- return NULL;
+ return ERR_PTR(-EINVAL);
pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
if (pctldev == NULL) {
dev_err(dev, "failed to alloc struct pinctrl_dev\n");
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
/* Initialize pin control device struct */
@@ -1724,20 +1724,23 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
mutex_init(&pctldev->mutex);
/* check core ops for sanity */
- if (pinctrl_check_ops(pctldev)) {
+ ret = pinctrl_check_ops(pctldev);
+ if (ret) {
dev_err(dev, "pinctrl ops lacks necessary functions\n");
goto out_err;
}
/* If we're implementing pinmuxing, check the ops for sanity */
if (pctldesc->pmxops) {
- if (pinmux_check_ops(pctldev))
+ ret = pinmux_check_ops(pctldev);
+ if (ret)
goto out_err;
}
/* If we're implementing pinconfig, check the ops for sanity */
if (pctldesc->confops) {
- if (pinconf_check_ops(pctldev))
+ ret = pinconf_check_ops(pctldev);
+ if (ret)
goto out_err;
}
@@ -1783,7 +1786,7 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
out_err:
mutex_destroy(&pctldev->mutex);
kfree(pctldev);
- return NULL;
+ return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(pinctrl_register);
diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
index 16aac38793fe..12ef544b4894 100644
--- a/drivers/pinctrl/freescale/Kconfig
+++ b/drivers/pinctrl/freescale/Kconfig
@@ -87,6 +87,13 @@ config PINCTRL_IMX6SX
help
Say Y here to enable the imx6sx pinctrl driver
+config PINCTRL_IMX7D
+ bool "IMX7D pinctrl driver"
+ depends on SOC_IMX7D
+ select PINCTRL_IMX
+ help
+ Say Y here to enable the imx7d pinctrl driver
+
config PINCTRL_VF610
bool "Freescale Vybrid VF610 pinctrl driver"
depends on SOC_VF610
diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile
index bba73c22f043..343cb436ab17 100644
--- a/drivers/pinctrl/freescale/Makefile
+++ b/drivers/pinctrl/freescale/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6q.o
obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6dl.o
obj-$(CONFIG_PINCTRL_IMX6SL) += pinctrl-imx6sl.o
obj-$(CONFIG_PINCTRL_IMX6SX) += pinctrl-imx6sx.o
+obj-$(CONFIG_PINCTRL_IMX7D) += pinctrl-imx7d.o
obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o
obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o
obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o
diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c
index e261f1cf85c6..d7b98ba36825 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx.c
@@ -606,6 +606,29 @@ static int imx_pinctrl_parse_functions(struct device_node *np,
return 0;
}
+/*
+ * Check if the DT contains pins in the direct child nodes. This indicates the
+ * newer DT format to store pins. This function returns true if the first found
+ * fsl,pins property is in a child of np. Otherwise false is returned.
+ */
+static bool imx_pinctrl_dt_is_flat_functions(struct device_node *np)
+{
+ struct device_node *function_np;
+ struct device_node *pinctrl_np;
+
+ for_each_child_of_node(np, function_np) {
+ if (of_property_read_bool(function_np, "fsl,pins"))
+ return true;
+
+ for_each_child_of_node(function_np, pinctrl_np) {
+ if (of_property_read_bool(pinctrl_np, "fsl,pins"))
+ return false;
+ }
+ }
+
+ return true;
+}
+
static int imx_pinctrl_probe_dt(struct platform_device *pdev,
struct imx_pinctrl_soc_info *info)
{
@@ -613,14 +636,20 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev,
struct device_node *child;
u32 nfuncs = 0;
u32 i = 0;
+ bool flat_funcs;
if (!np)
return -ENODEV;
- nfuncs = of_get_child_count(np);
- if (nfuncs <= 0) {
- dev_err(&pdev->dev, "no functions defined\n");
- return -EINVAL;
+ flat_funcs = imx_pinctrl_dt_is_flat_functions(np);
+ if (flat_funcs) {
+ nfuncs = 1;
+ } else {
+ nfuncs = of_get_child_count(np);
+ if (nfuncs <= 0) {
+ dev_err(&pdev->dev, "no functions defined\n");
+ return -EINVAL;
+ }
}
info->nfunctions = nfuncs;
@@ -629,16 +658,24 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev,
if (!info->functions)
return -ENOMEM;
- info->ngroups = 0;
- for_each_child_of_node(np, child)
- info->ngroups += of_get_child_count(child);
+ if (flat_funcs) {
+ info->ngroups = of_get_child_count(np);
+ } else {
+ info->ngroups = 0;
+ for_each_child_of_node(np, child)
+ info->ngroups += of_get_child_count(child);
+ }
info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct imx_pin_group),
GFP_KERNEL);
if (!info->groups)
return -ENOMEM;
- for_each_child_of_node(np, child)
- imx_pinctrl_parse_functions(child, info, i++);
+ if (flat_funcs) {
+ imx_pinctrl_parse_functions(np, info, 0);
+ } else {
+ for_each_child_of_node(np, child)
+ imx_pinctrl_parse_functions(child, info, i++);
+ }
return 0;
}
@@ -690,9 +727,9 @@ int imx_pinctrl_probe(struct platform_device *pdev,
ipctl->dev = info->dev;
platform_set_drvdata(pdev, ipctl);
ipctl->pctl = pinctrl_register(&imx_pinctrl_desc, &pdev->dev, ipctl);
- if (!ipctl->pctl) {
+ if (IS_ERR(ipctl->pctl)) {
dev_err(&pdev->dev, "could not register IMX pinctrl driver\n");
- return -EINVAL;
+ return PTR_ERR(ipctl->pctl);
}
dev_info(&pdev->dev, "initialized IMX pinctrl driver\n");
diff --git a/drivers/pinctrl/freescale/pinctrl-imx1-core.c b/drivers/pinctrl/freescale/pinctrl-imx1-core.c
index 5ac59fbb2440..5fd4437cee15 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx1-core.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx1-core.c
@@ -633,9 +633,9 @@ int imx1_pinctrl_core_probe(struct platform_device *pdev,
ipctl->dev = info->dev;
platform_set_drvdata(pdev, ipctl);
ipctl->pctl = pinctrl_register(pctl_desc, &pdev->dev, ipctl);
- if (!ipctl->pctl) {
+ if (IS_ERR(ipctl->pctl)) {
dev_err(&pdev->dev, "could not register IMX pinctrl driver\n");
- return -EINVAL;
+ return PTR_ERR(ipctl->pctl);
}
ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
diff --git a/drivers/pinctrl/freescale/pinctrl-imx7d.c b/drivers/pinctrl/freescale/pinctrl-imx7d.c
new file mode 100644
index 000000000000..1fa7530530dd
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-imx7d.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-imx.h"
+
+enum imx7d_pads {
+ MX7D_PAD_RESERVE0 = 0,
+ MX7D_PAD_RESERVE1 = 1,
+ MX7D_PAD_RESERVE2 = 2,
+ MX7D_PAD_RESERVE3 = 3,
+ MX7D_PAD_RESERVE4 = 4,
+ MX7D_PAD_GPIO1_IO08 = 5,
+ MX7D_PAD_GPIO1_IO09 = 6,
+ MX7D_PAD_GPIO1_IO10 = 7,
+ MX7D_PAD_GPIO1_IO11 = 8,
+ MX7D_PAD_GPIO1_IO12 = 9,
+ MX7D_PAD_GPIO1_IO13 = 10,
+ MX7D_PAD_GPIO1_IO14 = 11,
+ MX7D_PAD_GPIO1_IO15 = 12,
+ MX7D_PAD_EPDC_DATA00 = 13,
+ MX7D_PAD_EPDC_DATA01 = 14,
+ MX7D_PAD_EPDC_DATA02 = 15,
+ MX7D_PAD_EPDC_DATA03 = 16,
+ MX7D_PAD_EPDC_DATA04 = 17,
+ MX7D_PAD_EPDC_DATA05 = 18,
+ MX7D_PAD_EPDC_DATA06 = 19,
+ MX7D_PAD_EPDC_DATA07 = 20,
+ MX7D_PAD_EPDC_DATA08 = 21,
+ MX7D_PAD_EPDC_DATA09 = 22,
+ MX7D_PAD_EPDC_DATA10 = 23,
+ MX7D_PAD_EPDC_DATA11 = 24,
+ MX7D_PAD_EPDC_DATA12 = 25,
+ MX7D_PAD_EPDC_DATA13 = 26,
+ MX7D_PAD_EPDC_DATA14 = 27,
+ MX7D_PAD_EPDC_DATA15 = 28,
+ MX7D_PAD_EPDC_SDCLK = 29,
+ MX7D_PAD_EPDC_SDLE = 30,
+ MX7D_PAD_EPDC_SDOE = 31,
+ MX7D_PAD_EPDC_SDSHR = 32,
+ MX7D_PAD_EPDC_SDCE0 = 33,
+ MX7D_PAD_EPDC_SDCE1 = 34,
+ MX7D_PAD_EPDC_SDCE2 = 35,
+ MX7D_PAD_EPDC_SDCE3 = 36,
+ MX7D_PAD_EPDC_GDCLK = 37,
+ MX7D_PAD_EPDC_GDOE = 38,
+ MX7D_PAD_EPDC_GDRL = 39,
+ MX7D_PAD_EPDC_GDSP = 40,
+ MX7D_PAD_EPDC_BDR0 = 41,
+ MX7D_PAD_EPDC_BDR1 = 42,
+ MX7D_PAD_EPDC_PWR_COM = 43,
+ MX7D_PAD_EPDC_PWR_STAT = 44,
+ MX7D_PAD_LCD_CLK = 45,
+ MX7D_PAD_LCD_ENABLE = 46,
+ MX7D_PAD_LCD_HSYNC = 47,
+ MX7D_PAD_LCD_VSYNC = 48,
+ MX7D_PAD_LCD_RESET = 49,
+ MX7D_PAD_LCD_DATA00 = 50,
+ MX7D_PAD_LCD_DATA01 = 51,
+ MX7D_PAD_LCD_DATA02 = 52,
+ MX7D_PAD_LCD_DATA03 = 53,
+ MX7D_PAD_LCD_DATA04 = 54,
+ MX7D_PAD_LCD_DATA05 = 55,
+ MX7D_PAD_LCD_DATA06 = 56,
+ MX7D_PAD_LCD_DATA07 = 57,
+ MX7D_PAD_LCD_DATA08 = 58,
+ MX7D_PAD_LCD_DATA09 = 59,
+ MX7D_PAD_LCD_DATA10 = 60,
+ MX7D_PAD_LCD_DATA11 = 61,
+ MX7D_PAD_LCD_DATA12 = 62,
+ MX7D_PAD_LCD_DATA13 = 63,
+ MX7D_PAD_LCD_DATA14 = 64,
+ MX7D_PAD_LCD_DATA15 = 65,
+ MX7D_PAD_LCD_DATA16 = 66,
+ MX7D_PAD_LCD_DATA17 = 67,
+ MX7D_PAD_LCD_DATA18 = 68,
+ MX7D_PAD_LCD_DATA19 = 69,
+ MX7D_PAD_LCD_DATA20 = 70,
+ MX7D_PAD_LCD_DATA21 = 71,
+ MX7D_PAD_LCD_DATA22 = 72,
+ MX7D_PAD_LCD_DATA23 = 73,
+ MX7D_PAD_UART1_RX_DATA = 74,
+ MX7D_PAD_UART1_TX_DATA = 75,
+ MX7D_PAD_UART2_RX_DATA = 76,
+ MX7D_PAD_UART2_TX_DATA = 77,
+ MX7D_PAD_UART3_RX_DATA = 78,
+ MX7D_PAD_UART3_TX_DATA = 79,
+ MX7D_PAD_UART3_RTS_B = 80,
+ MX7D_PAD_UART3_CTS_B = 81,
+ MX7D_PAD_I2C1_SCL = 82,
+ MX7D_PAD_I2C1_SDA = 83,
+ MX7D_PAD_I2C2_SCL = 84,
+ MX7D_PAD_I2C2_SDA = 85,
+ MX7D_PAD_I2C3_SCL = 86,
+ MX7D_PAD_I2C3_SDA = 87,
+ MX7D_PAD_I2C4_SCL = 88,
+ MX7D_PAD_I2C4_SDA = 89,
+ MX7D_PAD_ECSPI1_SCLK = 90,
+ MX7D_PAD_ECSPI1_MOSI = 91,
+ MX7D_PAD_ECSPI1_MISO = 92,
+ MX7D_PAD_ECSPI1_SS0 = 93,
+ MX7D_PAD_ECSPI2_SCLK = 94,
+ MX7D_PAD_ECSPI2_MOSI = 95,
+ MX7D_PAD_ECSPI2_MISO = 96,
+ MX7D_PAD_ECSPI2_SS0 = 97,
+ MX7D_PAD_SD1_CD_B = 98,
+ MX7D_PAD_SD1_WP = 99,
+ MX7D_PAD_SD1_RESET_B = 100,
+ MX7D_PAD_SD1_CLK = 101,
+ MX7D_PAD_SD1_CMD = 102,
+ MX7D_PAD_SD1_DATA0 = 103,
+ MX7D_PAD_SD1_DATA1 = 104,
+ MX7D_PAD_SD1_DATA2 = 105,
+ MX7D_PAD_SD1_DATA3 = 106,
+ MX7D_PAD_SD2_CD_B = 107,
+ MX7D_PAD_SD2_WP = 108,
+ MX7D_PAD_SD2_RESET_B = 109,
+ MX7D_PAD_SD2_CLK = 110,
+ MX7D_PAD_SD2_CMD = 111,
+ MX7D_PAD_SD2_DATA0 = 112,
+ MX7D_PAD_SD2_DATA1 = 113,
+ MX7D_PAD_SD2_DATA2 = 114,
+ MX7D_PAD_SD2_DATA3 = 115,
+ MX7D_PAD_SD3_CLK = 116,
+ MX7D_PAD_SD3_CMD = 117,
+ MX7D_PAD_SD3_DATA0 = 118,
+ MX7D_PAD_SD3_DATA1 = 119,
+ MX7D_PAD_SD3_DATA2 = 120,
+ MX7D_PAD_SD3_DATA3 = 121,
+ MX7D_PAD_SD3_DATA4 = 122,
+ MX7D_PAD_SD3_DATA5 = 123,
+ MX7D_PAD_SD3_DATA6 = 124,
+ MX7D_PAD_SD3_DATA7 = 125,
+ MX7D_PAD_SD3_STROBE = 126,
+ MX7D_PAD_SD3_RESET_B = 127,
+ MX7D_PAD_SAI1_RX_DATA = 128,
+ MX7D_PAD_SAI1_TX_BCLK = 129,
+ MX7D_PAD_SAI1_TX_SYNC = 130,
+ MX7D_PAD_SAI1_TX_DATA = 131,
+ MX7D_PAD_SAI1_RX_SYNC = 132,
+ MX7D_PAD_SAI1_RX_BCLK = 133,
+ MX7D_PAD_SAI1_MCLK = 134,
+ MX7D_PAD_SAI2_TX_SYNC = 135,
+ MX7D_PAD_SAI2_TX_BCLK = 136,
+ MX7D_PAD_SAI2_RX_DATA = 137,
+ MX7D_PAD_SAI2_TX_DATA = 138,
+ MX7D_PAD_ENET1_RGMII_RD0 = 139,
+ MX7D_PAD_ENET1_RGMII_RD1 = 140,
+ MX7D_PAD_ENET1_RGMII_RD2 = 141,
+ MX7D_PAD_ENET1_RGMII_RD3 = 142,
+ MX7D_PAD_ENET1_RGMII_RX_CTL = 143,
+ MX7D_PAD_ENET1_RGMII_RXC = 144,
+ MX7D_PAD_ENET1_RGMII_TD0 = 145,
+ MX7D_PAD_ENET1_RGMII_TD1 = 146,
+ MX7D_PAD_ENET1_RGMII_TD2 = 147,
+ MX7D_PAD_ENET1_RGMII_TD3 = 148,
+ MX7D_PAD_ENET1_RGMII_TX_CTL = 149,
+ MX7D_PAD_ENET1_RGMII_TXC = 150,
+ MX7D_PAD_ENET1_TX_CLK = 151,
+ MX7D_PAD_ENET1_RX_CLK = 152,
+ MX7D_PAD_ENET1_CRS = 153,
+ MX7D_PAD_ENET1_COL = 154,
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx7d_pinctrl_pads[] = {
+ IMX_PINCTRL_PIN(MX7D_PAD_RESERVE0),
+ IMX_PINCTRL_PIN(MX7D_PAD_RESERVE1),
+ IMX_PINCTRL_PIN(MX7D_PAD_RESERVE2),
+ IMX_PINCTRL_PIN(MX7D_PAD_RESERVE3),
+ IMX_PINCTRL_PIN(MX7D_PAD_RESERVE4),
+ IMX_PINCTRL_PIN(MX7D_PAD_GPIO1_IO08),
+ IMX_PINCTRL_PIN(MX7D_PAD_GPIO1_IO09),
+ IMX_PINCTRL_PIN(MX7D_PAD_GPIO1_IO10),
+ IMX_PINCTRL_PIN(MX7D_PAD_GPIO1_IO11),
+ IMX_PINCTRL_PIN(MX7D_PAD_GPIO1_IO12),
+ IMX_PINCTRL_PIN(MX7D_PAD_GPIO1_IO13),
+ IMX_PINCTRL_PIN(MX7D_PAD_GPIO1_IO14),
+ IMX_PINCTRL_PIN(MX7D_PAD_GPIO1_IO15),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA00),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA01),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA02),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA03),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA04),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA05),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA06),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA07),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA08),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA09),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA10),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA11),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA12),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA13),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA14),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_DATA15),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_SDCLK),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_SDLE),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_SDOE),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_SDSHR),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_SDCE0),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_SDCE1),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_SDCE2),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_SDCE3),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_GDCLK),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_GDOE),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_GDRL),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_GDSP),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_BDR0),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_BDR1),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_PWR_COM),
+ IMX_PINCTRL_PIN(MX7D_PAD_EPDC_PWR_STAT),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_CLK),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_ENABLE),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_HSYNC),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_VSYNC),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_RESET),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA00),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA01),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA02),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA03),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA04),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA05),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA06),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA07),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA08),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA09),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA10),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA11),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA12),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA13),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA14),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA15),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA16),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA17),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA18),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA19),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA20),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA21),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA22),
+ IMX_PINCTRL_PIN(MX7D_PAD_LCD_DATA23),
+ IMX_PINCTRL_PIN(MX7D_PAD_UART1_RX_DATA),
+ IMX_PINCTRL_PIN(MX7D_PAD_UART1_TX_DATA),
+ IMX_PINCTRL_PIN(MX7D_PAD_UART2_RX_DATA),
+ IMX_PINCTRL_PIN(MX7D_PAD_UART2_TX_DATA),
+ IMX_PINCTRL_PIN(MX7D_PAD_UART3_RX_DATA),
+ IMX_PINCTRL_PIN(MX7D_PAD_UART3_TX_DATA),
+ IMX_PINCTRL_PIN(MX7D_PAD_UART3_RTS_B),
+ IMX_PINCTRL_PIN(MX7D_PAD_UART3_CTS_B),
+ IMX_PINCTRL_PIN(MX7D_PAD_I2C1_SCL),
+ IMX_PINCTRL_PIN(MX7D_PAD_I2C1_SDA),
+ IMX_PINCTRL_PIN(MX7D_PAD_I2C2_SCL),
+ IMX_PINCTRL_PIN(MX7D_PAD_I2C2_SDA),
+ IMX_PINCTRL_PIN(MX7D_PAD_I2C3_SCL),
+ IMX_PINCTRL_PIN(MX7D_PAD_I2C3_SDA),
+ IMX_PINCTRL_PIN(MX7D_PAD_I2C4_SCL),
+ IMX_PINCTRL_PIN(MX7D_PAD_I2C4_SDA),
+ IMX_PINCTRL_PIN(MX7D_PAD_ECSPI1_SCLK),
+ IMX_PINCTRL_PIN(MX7D_PAD_ECSPI1_MOSI),
+ IMX_PINCTRL_PIN(MX7D_PAD_ECSPI1_MISO),
+ IMX_PINCTRL_PIN(MX7D_PAD_ECSPI1_SS0),
+ IMX_PINCTRL_PIN(MX7D_PAD_ECSPI2_SCLK),
+ IMX_PINCTRL_PIN(MX7D_PAD_ECSPI2_MOSI),
+ IMX_PINCTRL_PIN(MX7D_PAD_ECSPI2_MISO),
+ IMX_PINCTRL_PIN(MX7D_PAD_ECSPI2_SS0),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD1_CD_B),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD1_WP),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD1_RESET_B),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD1_CLK),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD1_CMD),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD1_DATA0),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD1_DATA1),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD1_DATA2),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD1_DATA3),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD2_CD_B),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD2_WP),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD2_RESET_B),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD2_CLK),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD2_CMD),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD2_DATA0),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD2_DATA1),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD2_DATA2),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD2_DATA3),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD3_CLK),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD3_CMD),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD3_DATA0),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD3_DATA1),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD3_DATA2),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD3_DATA3),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD3_DATA4),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD3_DATA5),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD3_DATA6),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD3_DATA7),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD3_STROBE),
+ IMX_PINCTRL_PIN(MX7D_PAD_SD3_RESET_B),
+ IMX_PINCTRL_PIN(MX7D_PAD_SAI1_RX_DATA),
+ IMX_PINCTRL_PIN(MX7D_PAD_SAI1_TX_BCLK),
+ IMX_PINCTRL_PIN(MX7D_PAD_SAI1_TX_SYNC),
+ IMX_PINCTRL_PIN(MX7D_PAD_SAI1_TX_DATA),
+ IMX_PINCTRL_PIN(MX7D_PAD_SAI1_RX_SYNC),
+ IMX_PINCTRL_PIN(MX7D_PAD_SAI1_RX_BCLK),
+ IMX_PINCTRL_PIN(MX7D_PAD_SAI1_MCLK),
+ IMX_PINCTRL_PIN(MX7D_PAD_SAI2_TX_SYNC),
+ IMX_PINCTRL_PIN(MX7D_PAD_SAI2_TX_BCLK),
+ IMX_PINCTRL_PIN(MX7D_PAD_SAI2_RX_DATA),
+ IMX_PINCTRL_PIN(MX7D_PAD_SAI2_TX_DATA),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_RGMII_RD0),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_RGMII_RD1),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_RGMII_RD2),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_RGMII_RD3),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_RGMII_RX_CTL),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_RGMII_RXC),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_RGMII_TD0),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_RGMII_TD1),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_RGMII_TD2),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_RGMII_TD3),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_RGMII_TX_CTL),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_RGMII_TXC),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_TX_CLK),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_RX_CLK),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_CRS),
+ IMX_PINCTRL_PIN(MX7D_PAD_ENET1_COL),
+};
+
+static struct imx_pinctrl_soc_info imx7d_pinctrl_info = {
+ .pins = imx7d_pinctrl_pads,
+ .npins = ARRAY_SIZE(imx7d_pinctrl_pads),
+};
+
+static struct of_device_id imx7d_pinctrl_of_match[] = {
+ { .compatible = "fsl,imx7d-iomuxc", .data = &imx7d_pinctrl_info, },
+ { /* sentinel */ }
+};
+
+static int imx7d_pinctrl_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct imx_pinctrl_soc_info *pinctrl_info;
+
+ match = of_match_device(imx7d_pinctrl_of_match, &pdev->dev);
+
+ if (!match)
+ return -ENODEV;
+
+ pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;
+
+ return imx_pinctrl_probe(pdev, pinctrl_info);
+}
+
+static struct platform_driver imx7d_pinctrl_driver = {
+ .driver = {
+ .name = "imx7d-pinctrl",
+ .of_match_table = of_match_ptr(imx7d_pinctrl_of_match),
+ },
+ .probe = imx7d_pinctrl_probe,
+ .remove = imx_pinctrl_remove,
+};
+
+static int __init imx7d_pinctrl_init(void)
+{
+ return platform_driver_register(&imx7d_pinctrl_driver);
+}
+arch_initcall(imx7d_pinctrl_init);
+
+static void __exit imx7d_pinctrl_exit(void)
+{
+ platform_driver_unregister(&imx7d_pinctrl_driver);
+}
+module_exit(imx7d_pinctrl_exit);
+
+MODULE_AUTHOR("Anson Huang <Anson.Huang@freescale.com>");
+MODULE_DESCRIPTION("Freescale imx7d pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/freescale/pinctrl-mxs.c b/drivers/pinctrl/freescale/pinctrl-mxs.c
index 646d5c244af1..f64eecb24755 100644
--- a/drivers/pinctrl/freescale/pinctrl-mxs.c
+++ b/drivers/pinctrl/freescale/pinctrl-mxs.c
@@ -540,9 +540,9 @@ int mxs_pinctrl_probe(struct platform_device *pdev,
}
d->pctl = pinctrl_register(&mxs_pinctrl_desc, &pdev->dev, d);
- if (!d->pctl) {
+ if (IS_ERR(d->pctl)) {
dev_err(&pdev->dev, "Couldn't register MXS pinctrl driver\n");
- ret = -EINVAL;
+ ret = PTR_ERR(d->pctl);
goto err;
}
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
index 732ff757a95f..3f737daa3fd2 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -1533,9 +1533,9 @@ static int chv_pinctrl_probe(struct platform_device *pdev)
pctrl->pctldesc.npins = pctrl->community->npins;
pctrl->pctldev = pinctrl_register(&pctrl->pctldesc, &pdev->dev, pctrl);
- if (!pctrl->pctldev) {
+ if (IS_ERR(pctrl->pctldev)) {
dev_err(&pdev->dev, "failed to register pinctrl driver\n");
- return -ENODEV;
+ return PTR_ERR(pctrl->pctldev);
}
ret = chv_gpio_probe(pctrl, irq);
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index 00768e53deec..f9ee0d68b288 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -1021,9 +1021,9 @@ int intel_pinctrl_probe(struct platform_device *pdev,
pctrl->pctldesc.npins = pctrl->soc->npins;
pctrl->pctldev = pinctrl_register(&pctrl->pctldesc, &pdev->dev, pctrl);
- if (!pctrl->pctldev) {
+ if (IS_ERR(pctrl->pctldev)) {
dev_err(&pdev->dev, "failed to register pinctrl driver\n");
- return -ENODEV;
+ return PTR_ERR(pctrl->pctldev);
}
ret = intel_gpio_probe(pctrl, irq);
diff --git a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c
index 55d025dc89e8..1de9ae5010db 100644
--- a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c
+++ b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c
@@ -284,8 +284,271 @@ static const struct intel_pinctrl_soc_data sptlp_soc_data = {
.ncommunities = ARRAY_SIZE(sptlp_communities),
};
+/* Sunrisepoint-H */
+static const struct pinctrl_pin_desc spth_pins[] = {
+ /* GPP_A */
+ PINCTRL_PIN(0, "RCINB"),
+ PINCTRL_PIN(1, "LAD_0"),
+ PINCTRL_PIN(2, "LAD_1"),
+ PINCTRL_PIN(3, "LAD_2"),
+ PINCTRL_PIN(4, "LAD_3"),
+ PINCTRL_PIN(5, "LFRAMEB"),
+ PINCTRL_PIN(6, "SERIQ"),
+ PINCTRL_PIN(7, "PIRQAB"),
+ PINCTRL_PIN(8, "CLKRUNB"),
+ PINCTRL_PIN(9, "CLKOUT_LPC_0"),
+ PINCTRL_PIN(10, "CLKOUT_LPC_1"),
+ PINCTRL_PIN(11, "PMEB"),
+ PINCTRL_PIN(12, "BM_BUSYB"),
+ PINCTRL_PIN(13, "SUSWARNB_SUS_PWRDNACK"),
+ PINCTRL_PIN(14, "SUS_STATB"),
+ PINCTRL_PIN(15, "SUSACKB"),
+ PINCTRL_PIN(16, "CLKOUT_48"),
+ PINCTRL_PIN(17, "ISH_GP_7"),
+ PINCTRL_PIN(18, "ISH_GP_0"),
+ PINCTRL_PIN(19, "ISH_GP_1"),
+ PINCTRL_PIN(20, "ISH_GP_2"),
+ PINCTRL_PIN(21, "ISH_GP_3"),
+ PINCTRL_PIN(22, "ISH_GP_4"),
+ PINCTRL_PIN(23, "ISH_GP_5"),
+ /* GPP_B */
+ PINCTRL_PIN(24, "CORE_VID_0"),
+ PINCTRL_PIN(25, "CORE_VID_1"),
+ PINCTRL_PIN(26, "VRALERTB"),
+ PINCTRL_PIN(27, "CPU_GP_2"),
+ PINCTRL_PIN(28, "CPU_GP_3"),
+ PINCTRL_PIN(29, "SRCCLKREQB_0"),
+ PINCTRL_PIN(30, "SRCCLKREQB_1"),
+ PINCTRL_PIN(31, "SRCCLKREQB_2"),
+ PINCTRL_PIN(32, "SRCCLKREQB_3"),
+ PINCTRL_PIN(33, "SRCCLKREQB_4"),
+ PINCTRL_PIN(34, "SRCCLKREQB_5"),
+ PINCTRL_PIN(35, "EXT_PWR_GATEB"),
+ PINCTRL_PIN(36, "SLP_S0B"),
+ PINCTRL_PIN(37, "PLTRSTB"),
+ PINCTRL_PIN(38, "SPKR"),
+ PINCTRL_PIN(39, "GSPI0_CSB"),
+ PINCTRL_PIN(40, "GSPI0_CLK"),
+ PINCTRL_PIN(41, "GSPI0_MISO"),
+ PINCTRL_PIN(42, "GSPI0_MOSI"),
+ PINCTRL_PIN(43, "GSPI1_CSB"),
+ PINCTRL_PIN(44, "GSPI1_CLK"),
+ PINCTRL_PIN(45, "GSPI1_MISO"),
+ PINCTRL_PIN(46, "GSPI1_MOSI"),
+ PINCTRL_PIN(47, "SML1ALERTB"),
+ /* GPP_C */
+ PINCTRL_PIN(48, "SMBCLK"),
+ PINCTRL_PIN(49, "SMBDATA"),
+ PINCTRL_PIN(50, "SMBALERTB"),
+ PINCTRL_PIN(51, "SML0CLK"),
+ PINCTRL_PIN(52, "SML0DATA"),
+ PINCTRL_PIN(53, "SML0ALERTB"),
+ PINCTRL_PIN(54, "SML1CLK"),
+ PINCTRL_PIN(55, "SML1DATA"),
+ PINCTRL_PIN(56, "UART0_RXD"),
+ PINCTRL_PIN(57, "UART0_TXD"),
+ PINCTRL_PIN(58, "UART0_RTSB"),
+ PINCTRL_PIN(59, "UART0_CTSB"),
+ PINCTRL_PIN(60, "UART1_RXD"),
+ PINCTRL_PIN(61, "UART1_TXD"),
+ PINCTRL_PIN(62, "UART1_RTSB"),
+ PINCTRL_PIN(63, "UART1_CTSB"),
+ PINCTRL_PIN(64, "I2C0_SDA"),
+ PINCTRL_PIN(65, "I2C0_SCL"),
+ PINCTRL_PIN(66, "I2C1_SDA"),
+ PINCTRL_PIN(67, "I2C1_SCL"),
+ PINCTRL_PIN(68, "UART2_RXD"),
+ PINCTRL_PIN(69, "UART2_TXD"),
+ PINCTRL_PIN(70, "UART2_RTSB"),
+ PINCTRL_PIN(71, "UART2_CTSB"),
+ /* GPP_D */
+ PINCTRL_PIN(72, "SPI1_CSB"),
+ PINCTRL_PIN(73, "SPI1_CLK"),
+ PINCTRL_PIN(74, "SPI1_MISO_IO_1"),
+ PINCTRL_PIN(75, "SPI1_MOSI_IO_0"),
+ PINCTRL_PIN(76, "ISH_I2C2_SDA"),
+ PINCTRL_PIN(77, "SSP0_SFRM"),
+ PINCTRL_PIN(78, "SSP0_TXD"),
+ PINCTRL_PIN(79, "SSP0_RXD"),
+ PINCTRL_PIN(80, "SSP0_SCLK"),
+ PINCTRL_PIN(81, "ISH_SPI_CSB"),
+ PINCTRL_PIN(82, "ISH_SPI_CLK"),
+ PINCTRL_PIN(83, "ISH_SPI_MISO"),
+ PINCTRL_PIN(84, "ISH_SPI_MOSI"),
+ PINCTRL_PIN(85, "ISH_UART0_RXD"),
+ PINCTRL_PIN(86, "ISH_UART0_TXD"),
+ PINCTRL_PIN(87, "ISH_UART0_RTSB"),
+ PINCTRL_PIN(88, "ISH_UART0_CTSB"),
+ PINCTRL_PIN(89, "DMIC_CLK_1"),
+ PINCTRL_PIN(90, "DMIC_DATA_1"),
+ PINCTRL_PIN(91, "DMIC_CLK_0"),
+ PINCTRL_PIN(92, "DMIC_DATA_0"),
+ PINCTRL_PIN(93, "SPI1_IO_2"),
+ PINCTRL_PIN(94, "SPI1_IO_3"),
+ PINCTRL_PIN(95, "ISH_I2C2_SCL"),
+ /* GPP_E */
+ PINCTRL_PIN(96, "SATAXPCIE_0"),
+ PINCTRL_PIN(97, "SATAXPCIE_1"),
+ PINCTRL_PIN(98, "SATAXPCIE_2"),
+ PINCTRL_PIN(99, "CPU_GP_0"),
+ PINCTRL_PIN(100, "SATA_DEVSLP_0"),
+ PINCTRL_PIN(101, "SATA_DEVSLP_1"),
+ PINCTRL_PIN(102, "SATA_DEVSLP_2"),
+ PINCTRL_PIN(103, "CPU_GP_1"),
+ PINCTRL_PIN(104, "SATA_LEDB"),
+ PINCTRL_PIN(105, "USB2_OCB_0"),
+ PINCTRL_PIN(106, "USB2_OCB_1"),
+ PINCTRL_PIN(107, "USB2_OCB_2"),
+ PINCTRL_PIN(108, "USB2_OCB_3"),
+ /* GPP_F */
+ PINCTRL_PIN(109, "SATAXPCIE_3"),
+ PINCTRL_PIN(110, "SATAXPCIE_4"),
+ PINCTRL_PIN(111, "SATAXPCIE_5"),
+ PINCTRL_PIN(112, "SATAXPCIE_6"),
+ PINCTRL_PIN(113, "SATAXPCIE_7"),
+ PINCTRL_PIN(114, "SATA_DEVSLP_3"),
+ PINCTRL_PIN(115, "SATA_DEVSLP_4"),
+ PINCTRL_PIN(116, "SATA_DEVSLP_5"),
+ PINCTRL_PIN(117, "SATA_DEVSLP_6"),
+ PINCTRL_PIN(118, "SATA_DEVSLP_7"),
+ PINCTRL_PIN(119, "SATA_SCLOCK"),
+ PINCTRL_PIN(120, "SATA_SLOAD"),
+ PINCTRL_PIN(121, "SATA_SDATAOUT1"),
+ PINCTRL_PIN(122, "SATA_SDATAOUT0"),
+ PINCTRL_PIN(123, "GPP_F_14"),
+ PINCTRL_PIN(124, "USB_OCB_4"),
+ PINCTRL_PIN(125, "USB_OCB_5"),
+ PINCTRL_PIN(126, "USB_OCB_6"),
+ PINCTRL_PIN(127, "USB_OCB_7"),
+ PINCTRL_PIN(128, "L_VDDEN"),
+ PINCTRL_PIN(129, "L_BKLTEN"),
+ PINCTRL_PIN(130, "L_BKLTCTL"),
+ PINCTRL_PIN(131, "GPP_F_22"),
+ PINCTRL_PIN(132, "GPP_F_23"),
+ /* GPP_G */
+ PINCTRL_PIN(133, "FAN_TACH_0"),
+ PINCTRL_PIN(134, "FAN_TACH_1"),
+ PINCTRL_PIN(135, "FAN_TACH_2"),
+ PINCTRL_PIN(136, "FAN_TACH_3"),
+ PINCTRL_PIN(137, "FAN_TACH_4"),
+ PINCTRL_PIN(138, "FAN_TACH_5"),
+ PINCTRL_PIN(139, "FAN_TACH_6"),
+ PINCTRL_PIN(140, "FAN_TACH_7"),
+ PINCTRL_PIN(141, "FAN_PWM_0"),
+ PINCTRL_PIN(142, "FAN_PWM_1"),
+ PINCTRL_PIN(143, "FAN_PWM_2"),
+ PINCTRL_PIN(144, "FAN_PWM_3"),
+ PINCTRL_PIN(145, "GSXDOUT"),
+ PINCTRL_PIN(146, "GSXSLOAD"),
+ PINCTRL_PIN(147, "GSXDIN"),
+ PINCTRL_PIN(148, "GSXRESETB"),
+ PINCTRL_PIN(149, "GSXCLK"),
+ PINCTRL_PIN(150, "ADR_COMPLETE"),
+ PINCTRL_PIN(151, "NMIB"),
+ PINCTRL_PIN(152, "SMIB"),
+ PINCTRL_PIN(153, "GPP_G_20"),
+ PINCTRL_PIN(154, "GPP_G_21"),
+ PINCTRL_PIN(155, "GPP_G_22"),
+ PINCTRL_PIN(156, "GPP_G_23"),
+ /* GPP_H */
+ PINCTRL_PIN(157, "SRCCLKREQB_6"),
+ PINCTRL_PIN(158, "SRCCLKREQB_7"),
+ PINCTRL_PIN(159, "SRCCLKREQB_8"),
+ PINCTRL_PIN(160, "SRCCLKREQB_9"),
+ PINCTRL_PIN(161, "SRCCLKREQB_10"),
+ PINCTRL_PIN(162, "SRCCLKREQB_11"),
+ PINCTRL_PIN(163, "SRCCLKREQB_12"),
+ PINCTRL_PIN(164, "SRCCLKREQB_13"),
+ PINCTRL_PIN(165, "SRCCLKREQB_14"),
+ PINCTRL_PIN(166, "SRCCLKREQB_15"),
+ PINCTRL_PIN(167, "SML2CLK"),
+ PINCTRL_PIN(168, "SML2DATA"),
+ PINCTRL_PIN(169, "SML2ALERTB"),
+ PINCTRL_PIN(170, "SML3CLK"),
+ PINCTRL_PIN(171, "SML3DATA"),
+ PINCTRL_PIN(172, "SML3ALERTB"),
+ PINCTRL_PIN(173, "SML4CLK"),
+ PINCTRL_PIN(174, "SML4DATA"),
+ PINCTRL_PIN(175, "SML4ALERTB"),
+ PINCTRL_PIN(176, "ISH_I2C0_SDA"),
+ PINCTRL_PIN(177, "ISH_I2C0_SCL"),
+ PINCTRL_PIN(178, "ISH_I2C1_SDA"),
+ PINCTRL_PIN(179, "ISH_I2C1_SCL"),
+ PINCTRL_PIN(180, "GPP_H_23"),
+ /* GPP_I */
+ PINCTRL_PIN(181, "DDSP_HDP_0"),
+ PINCTRL_PIN(182, "DDSP_HDP_1"),
+ PINCTRL_PIN(183, "DDSP_HDP_2"),
+ PINCTRL_PIN(184, "DDSP_HDP_3"),
+ PINCTRL_PIN(185, "EDP_HPD"),
+ PINCTRL_PIN(186, "DDPB_CTRLCLK"),
+ PINCTRL_PIN(187, "DDPB_CTRLDATA"),
+ PINCTRL_PIN(188, "DDPC_CTRLCLK"),
+ PINCTRL_PIN(189, "DDPC_CTRLDATA"),
+ PINCTRL_PIN(190, "DDPD_CTRLCLK"),
+ PINCTRL_PIN(191, "DDPD_CTRLDATA"),
+};
+
+static const unsigned spth_spi0_pins[] = { 39, 40, 41, 42 };
+static const unsigned spth_spi1_pins[] = { 43, 44, 45, 46 };
+static const unsigned spth_uart0_pins[] = { 56, 57, 58, 59 };
+static const unsigned spth_uart1_pins[] = { 60, 61, 62, 63 };
+static const unsigned spth_uart2_pins[] = { 68, 69, 71, 71 };
+static const unsigned spth_i2c0_pins[] = { 64, 65 };
+static const unsigned spth_i2c1_pins[] = { 66, 67 };
+static const unsigned spth_i2c2_pins[] = { 76, 95 };
+
+static const struct intel_pingroup spth_groups[] = {
+ PIN_GROUP("spi0_grp", spth_spi0_pins, 1),
+ PIN_GROUP("spi1_grp", spth_spi1_pins, 1),
+ PIN_GROUP("uart0_grp", spth_uart0_pins, 1),
+ PIN_GROUP("uart1_grp", spth_uart1_pins, 1),
+ PIN_GROUP("uart2_grp", spth_uart2_pins, 1),
+ PIN_GROUP("i2c0_grp", spth_i2c0_pins, 1),
+ PIN_GROUP("i2c1_grp", spth_i2c1_pins, 1),
+ PIN_GROUP("i2c2_grp", spth_i2c2_pins, 2),
+};
+
+static const char * const spth_spi0_groups[] = { "spi0_grp" };
+static const char * const spth_spi1_groups[] = { "spi0_grp" };
+static const char * const spth_uart0_groups[] = { "uart0_grp" };
+static const char * const spth_uart1_groups[] = { "uart1_grp" };
+static const char * const spth_uart2_groups[] = { "uart2_grp" };
+static const char * const spth_i2c0_groups[] = { "i2c0_grp" };
+static const char * const spth_i2c1_groups[] = { "i2c1_grp" };
+static const char * const spth_i2c2_groups[] = { "i2c2_grp" };
+
+static const struct intel_function spth_functions[] = {
+ FUNCTION("spi0", spth_spi0_groups),
+ FUNCTION("spi1", spth_spi1_groups),
+ FUNCTION("uart0", spth_uart0_groups),
+ FUNCTION("uart1", spth_uart1_groups),
+ FUNCTION("uart2", spth_uart2_groups),
+ FUNCTION("i2c0", spth_i2c0_groups),
+ FUNCTION("i2c1", spth_i2c1_groups),
+ FUNCTION("i2c2", spth_i2c2_groups),
+};
+
+static const struct intel_community spth_communities[] = {
+ SPT_COMMUNITY(0, 0, 47),
+ SPT_COMMUNITY(1, 48, 180),
+ SPT_COMMUNITY(2, 181, 191),
+};
+
+static const struct intel_pinctrl_soc_data spth_soc_data = {
+ .pins = spth_pins,
+ .npins = ARRAY_SIZE(spth_pins),
+ .groups = spth_groups,
+ .ngroups = ARRAY_SIZE(spth_groups),
+ .functions = spth_functions,
+ .nfunctions = ARRAY_SIZE(spth_functions),
+ .communities = spth_communities,
+ .ncommunities = ARRAY_SIZE(spth_communities),
+};
+
static const struct acpi_device_id spt_pinctrl_acpi_match[] = {
{ "INT344B", (kernel_ulong_t)&sptlp_soc_data },
+ { "INT345D", (kernel_ulong_t)&spth_soc_data },
{ }
};
MODULE_DEVICE_TABLE(acpi, spt_pinctrl_acpi_match);
diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 6b3551cad111..02f6f92df86c 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -15,6 +15,12 @@ config PINCTRL_MT8135
default MACH_MT8135
select PINCTRL_MTK_COMMON
+config PINCTRL_MT8127
+ bool "Mediatek MT8127 pin control" if COMPILE_TEST && !MACH_MT8127
+ depends on OF
+ default MACH_MT8127
+ select PINCTRL_MTK_COMMON
+
# For ARMv8 SoCs
config PINCTRL_MT8173
bool "Mediatek MT8173 pin control"
@@ -23,4 +29,11 @@ config PINCTRL_MT8173
default ARM64 && ARCH_MEDIATEK
select PINCTRL_MTK_COMMON
+# For PMIC
+config PINCTRL_MT6397
+ bool "Mediatek MT6397 pin control" if COMPILE_TEST && !MFD_MT6397
+ depends on OF
+ default MFD_MT6397
+ select PINCTRL_MTK_COMMON
+
endif
diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
index d8606a2179cf..eb923d64d387 100644
--- a/drivers/pinctrl/mediatek/Makefile
+++ b/drivers/pinctrl/mediatek/Makefile
@@ -3,4 +3,6 @@ obj-$(CONFIG_PINCTRL_MTK_COMMON) += pinctrl-mtk-common.o
# SoC Drivers
obj-$(CONFIG_PINCTRL_MT8135) += pinctrl-mt8135.o
+obj-$(CONFIG_PINCTRL_MT8127) += pinctrl-mt8127.o
obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
+obj-$(CONFIG_PINCTRL_MT6397) += pinctrl-mt6397.o
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt6397.c b/drivers/pinctrl/mediatek/pinctrl-mt6397.c
new file mode 100644
index 000000000000..f9751ae28e32
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt6397.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Hongzhou.Yang <hongzhou.yang@mediatek.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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/mfd/mt6397/core.h>
+
+#include "pinctrl-mtk-common.h"
+#include "pinctrl-mtk-mt6397.h"
+
+#define MT6397_PIN_REG_BASE 0xc000
+
+static const struct mtk_pinctrl_devdata mt6397_pinctrl_data = {
+ .pins = mtk_pins_mt6397,
+ .npins = ARRAY_SIZE(mtk_pins_mt6397),
+ .dir_offset = (MT6397_PIN_REG_BASE + 0x000),
+ .ies_offset = MTK_PINCTRL_NOT_SUPPORT,
+ .smt_offset = MTK_PINCTRL_NOT_SUPPORT,
+ .pullen_offset = (MT6397_PIN_REG_BASE + 0x020),
+ .pullsel_offset = (MT6397_PIN_REG_BASE + 0x040),
+ .dout_offset = (MT6397_PIN_REG_BASE + 0x080),
+ .din_offset = (MT6397_PIN_REG_BASE + 0x0a0),
+ .pinmux_offset = (MT6397_PIN_REG_BASE + 0x0c0),
+ .type1_start = 41,
+ .type1_end = 41,
+ .port_shf = 3,
+ .port_mask = 0x3,
+ .port_align = 2,
+};
+
+static int mt6397_pinctrl_probe(struct platform_device *pdev)
+{
+ struct mt6397_chip *mt6397;
+
+ mt6397 = dev_get_drvdata(pdev->dev.parent);
+ return mtk_pctrl_init(pdev, &mt6397_pinctrl_data, mt6397->regmap);
+}
+
+static const struct of_device_id mt6397_pctrl_match[] = {
+ { .compatible = "mediatek,mt6397-pinctrl", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mt6397_pctrl_match);
+
+static struct platform_driver mtk_pinctrl_driver = {
+ .probe = mt6397_pinctrl_probe,
+ .driver = {
+ .name = "mediatek-mt6397-pinctrl",
+ .of_match_table = mt6397_pctrl_match,
+ },
+};
+
+static int __init mtk_pinctrl_init(void)
+{
+ return platform_driver_register(&mtk_pinctrl_driver);
+}
+
+module_init(mtk_pinctrl_init);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MediaTek MT6397 Pinctrl Driver");
+MODULE_AUTHOR("Hongzhou Yang <hongzhou.yang@mediatek.com>");
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8127.c b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
new file mode 100644
index 000000000000..b317b0b664ea
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Hongzhou.Yang <hongzhou.yang@mediatek.com>
+ * Yingjoe Chen <yingjoe.chen@mediatek.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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/regmap.h>
+#include <dt-bindings/pinctrl/mt65xx.h>
+
+#include "pinctrl-mtk-common.h"
+#include "pinctrl-mtk-mt8127.h"
+
+static const struct mtk_drv_group_desc mt8127_drv_grp[] = {
+ /* 0E4E8SR 4/8/12/16 */
+ MTK_DRV_GRP(4, 16, 1, 2, 4),
+ /* 0E2E4SR 2/4/6/8 */
+ MTK_DRV_GRP(2, 8, 1, 2, 2),
+ /* E8E4E2 2/4/6/8/10/12/14/16 */
+ MTK_DRV_GRP(2, 16, 0, 2, 2)
+};
+
+static const struct mtk_pin_drv_grp mt8127_pin_drv[] = {
+ MTK_PIN_DRV_GRP(0, 0xb00, 0, 1),
+ MTK_PIN_DRV_GRP(1, 0xb00, 0, 1),
+ MTK_PIN_DRV_GRP(2, 0xb00, 0, 1),
+ MTK_PIN_DRV_GRP(3, 0xb00, 0, 1),
+ MTK_PIN_DRV_GRP(4, 0xb00, 0, 1),
+ MTK_PIN_DRV_GRP(5, 0xb00, 0, 1),
+ MTK_PIN_DRV_GRP(6, 0xb00, 0, 1),
+ MTK_PIN_DRV_GRP(7, 0xb00, 12, 1),
+ MTK_PIN_DRV_GRP(8, 0xb00, 12, 1),
+ MTK_PIN_DRV_GRP(9, 0xb00, 12, 1),
+ MTK_PIN_DRV_GRP(10, 0xb00, 8, 1),
+ MTK_PIN_DRV_GRP(11, 0xb00, 8, 1),
+ MTK_PIN_DRV_GRP(12, 0xb00, 8, 1),
+ MTK_PIN_DRV_GRP(13, 0xb00, 8, 1),
+ MTK_PIN_DRV_GRP(14, 0xb10, 4, 0),
+ MTK_PIN_DRV_GRP(15, 0xb10, 4, 0),
+ MTK_PIN_DRV_GRP(16, 0xb10, 4, 0),
+ MTK_PIN_DRV_GRP(17, 0xb10, 4, 0),
+ MTK_PIN_DRV_GRP(18, 0xb10, 8, 0),
+ MTK_PIN_DRV_GRP(19, 0xb10, 8, 0),
+ MTK_PIN_DRV_GRP(20, 0xb10, 8, 0),
+ MTK_PIN_DRV_GRP(21, 0xb10, 8, 0),
+ MTK_PIN_DRV_GRP(22, 0xb20, 0, 0),
+ MTK_PIN_DRV_GRP(23, 0xb20, 0, 0),
+ MTK_PIN_DRV_GRP(24, 0xb20, 0, 0),
+ MTK_PIN_DRV_GRP(25, 0xb20, 0, 0),
+ MTK_PIN_DRV_GRP(26, 0xb20, 0, 0),
+ MTK_PIN_DRV_GRP(27, 0xb20, 4, 0),
+ MTK_PIN_DRV_GRP(28, 0xb20, 4, 0),
+ MTK_PIN_DRV_GRP(29, 0xb20, 4, 0),
+ MTK_PIN_DRV_GRP(30, 0xb20, 4, 0),
+ MTK_PIN_DRV_GRP(31, 0xb20, 4, 0),
+ MTK_PIN_DRV_GRP(32, 0xb20, 4, 0),
+ MTK_PIN_DRV_GRP(33, 0xb30, 4, 1),
+ MTK_PIN_DRV_GRP(34, 0xb30, 8, 1),
+ MTK_PIN_DRV_GRP(35, 0xb30, 8, 1),
+ MTK_PIN_DRV_GRP(36, 0xb30, 8, 1),
+ MTK_PIN_DRV_GRP(37, 0xb30, 8, 1),
+ MTK_PIN_DRV_GRP(38, 0xb30, 8, 1),
+ MTK_PIN_DRV_GRP(39, 0xb30, 12, 1),
+ MTK_PIN_DRV_GRP(40, 0xb30, 12, 1),
+ MTK_PIN_DRV_GRP(41, 0xb30, 12, 1),
+ MTK_PIN_DRV_GRP(42, 0xb30, 12, 1),
+ MTK_PIN_DRV_GRP(43, 0xb40, 12, 0),
+ MTK_PIN_DRV_GRP(44, 0xb40, 12, 0),
+ MTK_PIN_DRV_GRP(45, 0xb40, 12, 0),
+ MTK_PIN_DRV_GRP(46, 0xb50, 0, 2),
+ MTK_PIN_DRV_GRP(47, 0xb50, 0, 2),
+ MTK_PIN_DRV_GRP(48, 0xb50, 0, 2),
+ MTK_PIN_DRV_GRP(49, 0xb50, 0, 2),
+ MTK_PIN_DRV_GRP(50, 0xb70, 0, 1),
+ MTK_PIN_DRV_GRP(51, 0xb70, 0, 1),
+ MTK_PIN_DRV_GRP(52, 0xb70, 0, 1),
+ MTK_PIN_DRV_GRP(53, 0xb50, 12, 1),
+ MTK_PIN_DRV_GRP(54, 0xb50, 12, 1),
+ MTK_PIN_DRV_GRP(55, 0xb50, 12, 1),
+ MTK_PIN_DRV_GRP(56, 0xb50, 12, 1),
+ MTK_PIN_DRV_GRP(59, 0xb40, 4, 1),
+ MTK_PIN_DRV_GRP(60, 0xb40, 0, 1),
+ MTK_PIN_DRV_GRP(61, 0xb40, 0, 1),
+ MTK_PIN_DRV_GRP(62, 0xb40, 0, 1),
+ MTK_PIN_DRV_GRP(63, 0xb40, 4, 1),
+ MTK_PIN_DRV_GRP(64, 0xb40, 4, 1),
+ MTK_PIN_DRV_GRP(65, 0xb40, 4, 1),
+ MTK_PIN_DRV_GRP(66, 0xb40, 8, 1),
+ MTK_PIN_DRV_GRP(67, 0xb40, 8, 1),
+ MTK_PIN_DRV_GRP(68, 0xb40, 8, 1),
+ MTK_PIN_DRV_GRP(69, 0xb40, 8, 1),
+ MTK_PIN_DRV_GRP(70, 0xb40, 8, 1),
+ MTK_PIN_DRV_GRP(71, 0xb40, 8, 1),
+ MTK_PIN_DRV_GRP(72, 0xb50, 4, 1),
+ MTK_PIN_DRV_GRP(73, 0xb50, 4, 1),
+ MTK_PIN_DRV_GRP(74, 0xb50, 4, 1),
+ MTK_PIN_DRV_GRP(79, 0xb50, 8, 1),
+ MTK_PIN_DRV_GRP(80, 0xb50, 8, 1),
+ MTK_PIN_DRV_GRP(81, 0xb50, 8, 1),
+ MTK_PIN_DRV_GRP(82, 0xb50, 8, 1),
+ MTK_PIN_DRV_GRP(83, 0xb50, 8, 1),
+ MTK_PIN_DRV_GRP(84, 0xb50, 8, 1),
+ MTK_PIN_DRV_GRP(85, 0xce0, 0, 2),
+ MTK_PIN_DRV_GRP(86, 0xcd0, 0, 2),
+ MTK_PIN_DRV_GRP(87, 0xcf0, 0, 2),
+ MTK_PIN_DRV_GRP(88, 0xcf0, 0, 2),
+ MTK_PIN_DRV_GRP(89, 0xcf0, 0, 2),
+ MTK_PIN_DRV_GRP(90, 0xcf0, 0, 2),
+ MTK_PIN_DRV_GRP(117, 0xb60, 12, 1),
+ MTK_PIN_DRV_GRP(118, 0xb60, 12, 1),
+ MTK_PIN_DRV_GRP(119, 0xb60, 12, 1),
+ MTK_PIN_DRV_GRP(120, 0xb60, 12, 1),
+ MTK_PIN_DRV_GRP(121, 0xc80, 0, 2),
+ MTK_PIN_DRV_GRP(122, 0xc70, 0, 2),
+ MTK_PIN_DRV_GRP(123, 0xc90, 0, 2),
+ MTK_PIN_DRV_GRP(124, 0xc90, 0, 2),
+ MTK_PIN_DRV_GRP(125, 0xc90, 0, 2),
+ MTK_PIN_DRV_GRP(126, 0xc90, 0, 2),
+ MTK_PIN_DRV_GRP(127, 0xc20, 0, 2),
+ MTK_PIN_DRV_GRP(128, 0xc20, 0, 2),
+ MTK_PIN_DRV_GRP(129, 0xc20, 0, 2),
+ MTK_PIN_DRV_GRP(130, 0xc20, 0, 2),
+ MTK_PIN_DRV_GRP(131, 0xc20, 0, 2),
+ MTK_PIN_DRV_GRP(132, 0xc10, 0, 2),
+ MTK_PIN_DRV_GRP(133, 0xc00, 0, 2),
+ MTK_PIN_DRV_GRP(134, 0xc20, 0, 2),
+ MTK_PIN_DRV_GRP(135, 0xc20, 0, 2),
+ MTK_PIN_DRV_GRP(136, 0xc20, 0, 2),
+ MTK_PIN_DRV_GRP(137, 0xc20, 0, 2),
+ MTK_PIN_DRV_GRP(142, 0xb50, 0, 2),
+};
+
+static const struct mtk_pin_spec_pupd_set_samereg mt8127_spec_pupd[] = {
+ MTK_PIN_PUPD_SPEC_SR(33, 0xd90, 2, 0, 1), /* KPROW0 */
+ MTK_PIN_PUPD_SPEC_SR(34, 0xd90, 6, 4, 5), /* KPROW1 */
+ MTK_PIN_PUPD_SPEC_SR(35, 0xd90, 10, 8, 9), /* KPROW2 */
+ MTK_PIN_PUPD_SPEC_SR(36, 0xda0, 2, 0, 1), /* KPCOL0 */
+ MTK_PIN_PUPD_SPEC_SR(37, 0xda0, 6, 4, 5), /* KPCOL1 */
+ MTK_PIN_PUPD_SPEC_SR(38, 0xda0, 10, 8, 9), /* KPCOL2 */
+ MTK_PIN_PUPD_SPEC_SR(46, 0xdb0, 2, 0, 1), /* EINT14 */
+ MTK_PIN_PUPD_SPEC_SR(47, 0xdb0, 6, 4, 5), /* EINT15 */
+ MTK_PIN_PUPD_SPEC_SR(48, 0xdb0, 10, 8, 9), /* EINT16 */
+ MTK_PIN_PUPD_SPEC_SR(49, 0xdb0, 14, 12, 13), /* EINT17 */
+ MTK_PIN_PUPD_SPEC_SR(85, 0xce0, 8, 10, 9), /* MSDC2_CMD */
+ MTK_PIN_PUPD_SPEC_SR(86, 0xcd0, 8, 10, 9), /* MSDC2_CLK */
+ MTK_PIN_PUPD_SPEC_SR(87, 0xd00, 0, 2, 1), /* MSDC2_DAT0 */
+ MTK_PIN_PUPD_SPEC_SR(88, 0xd00, 4, 6, 5), /* MSDC2_DAT1 */
+ MTK_PIN_PUPD_SPEC_SR(89, 0xd00, 8, 10, 9), /* MSDC2_DAT2 */
+ MTK_PIN_PUPD_SPEC_SR(90, 0xd00, 12, 14, 13), /* MSDC2_DAT3 */
+ MTK_PIN_PUPD_SPEC_SR(121, 0xc80, 8, 10, 9), /* MSDC1_CMD */
+ MTK_PIN_PUPD_SPEC_SR(122, 0xc70, 8, 10, 9), /* MSDC1_CLK */
+ MTK_PIN_PUPD_SPEC_SR(123, 0xca0, 0, 2, 1), /* MSDC1_DAT0 */
+ MTK_PIN_PUPD_SPEC_SR(124, 0xca0, 4, 6, 5), /* MSDC1_DAT1 */
+ MTK_PIN_PUPD_SPEC_SR(125, 0xca0, 8, 10, 9), /* MSDC1_DAT2 */
+ MTK_PIN_PUPD_SPEC_SR(126, 0xca0, 12, 14, 13), /* MSDC1_DAT3 */
+ MTK_PIN_PUPD_SPEC_SR(127, 0xc40, 12, 14, 13), /* MSDC0_DAT7 */
+ MTK_PIN_PUPD_SPEC_SR(128, 0xc40, 8, 10, 9), /* MSDC0_DAT6 */
+ MTK_PIN_PUPD_SPEC_SR(129, 0xc40, 4, 6, 5), /* MSDC0_DAT5 */
+ MTK_PIN_PUPD_SPEC_SR(130, 0xc40, 0, 2, 1), /* MSDC0_DAT4 */
+ MTK_PIN_PUPD_SPEC_SR(131, 0xc50, 0, 2, 1), /* MSDC0_RSTB */
+ MTK_PIN_PUPD_SPEC_SR(132, 0xc10, 8, 10, 9), /* MSDC0_CMD */
+ MTK_PIN_PUPD_SPEC_SR(133, 0xc00, 8, 10, 9), /* MSDC0_CLK */
+ MTK_PIN_PUPD_SPEC_SR(134, 0xc30, 12, 14, 13), /* MSDC0_DAT3 */
+ MTK_PIN_PUPD_SPEC_SR(135, 0xc30, 8, 10, 9), /* MSDC0_DAT2 */
+ MTK_PIN_PUPD_SPEC_SR(136, 0xc30, 4, 6, 5), /* MSDC0_DAT1 */
+ MTK_PIN_PUPD_SPEC_SR(137, 0xc30, 0, 2, 1), /* MSDC0_DAT0 */
+ MTK_PIN_PUPD_SPEC_SR(142, 0xdc0, 2, 0, 1), /* EINT21 */
+};
+
+static int mt8127_spec_pull_set(struct regmap *regmap, unsigned int pin,
+ unsigned char align, bool isup, unsigned int r1r0)
+{
+ return mtk_pctrl_spec_pull_set_samereg(regmap, mt8127_spec_pupd,
+ ARRAY_SIZE(mt8127_spec_pupd), pin, align, isup, r1r0);
+}
+
+static const struct mtk_pin_ies_smt_set mt8127_ies_set[] = {
+ MTK_PIN_IES_SMT_SPEC(0, 9, 0x900, 0),
+ MTK_PIN_IES_SMT_SPEC(10, 13, 0x900, 1),
+ MTK_PIN_IES_SMT_SPEC(14, 28, 0x900, 2),
+ MTK_PIN_IES_SMT_SPEC(29, 32, 0x900, 3),
+ MTK_PIN_IES_SMT_SPEC(33, 33, 0x910, 11),
+ MTK_PIN_IES_SMT_SPEC(34, 38, 0x900, 10),
+ MTK_PIN_IES_SMT_SPEC(39, 42, 0x900, 11),
+ MTK_PIN_IES_SMT_SPEC(43, 45, 0x900, 12),
+ MTK_PIN_IES_SMT_SPEC(46, 49, 0x900, 13),
+ MTK_PIN_IES_SMT_SPEC(50, 52, 0x910, 10),
+ MTK_PIN_IES_SMT_SPEC(53, 56, 0x900, 14),
+ MTK_PIN_IES_SMT_SPEC(57, 58, 0x910, 0),
+ MTK_PIN_IES_SMT_SPEC(59, 65, 0x910, 2),
+ MTK_PIN_IES_SMT_SPEC(66, 71, 0x910, 3),
+ MTK_PIN_IES_SMT_SPEC(72, 74, 0x910, 4),
+ MTK_PIN_IES_SMT_SPEC(75, 76, 0x900, 15),
+ MTK_PIN_IES_SMT_SPEC(77, 78, 0x910, 1),
+ MTK_PIN_IES_SMT_SPEC(79, 82, 0x910, 5),
+ MTK_PIN_IES_SMT_SPEC(83, 84, 0x910, 6),
+ MTK_PIN_IES_SMT_SPEC(117, 120, 0x910, 7),
+ MTK_PIN_IES_SMT_SPEC(121, 121, 0xc80, 4),
+ MTK_PIN_IES_SMT_SPEC(122, 122, 0xc70, 4),
+ MTK_PIN_IES_SMT_SPEC(123, 126, 0xc90, 4),
+ MTK_PIN_IES_SMT_SPEC(127, 131, 0xc20, 4),
+ MTK_PIN_IES_SMT_SPEC(132, 132, 0xc10, 4),
+ MTK_PIN_IES_SMT_SPEC(133, 133, 0xc00, 4),
+ MTK_PIN_IES_SMT_SPEC(134, 137, 0xc20, 4),
+ MTK_PIN_IES_SMT_SPEC(138, 141, 0x910, 9),
+ MTK_PIN_IES_SMT_SPEC(142, 142, 0x900, 13),
+};
+
+static const struct mtk_pin_ies_smt_set mt8127_smt_set[] = {
+ MTK_PIN_IES_SMT_SPEC(0, 9, 0x920, 0),
+ MTK_PIN_IES_SMT_SPEC(10, 13, 0x920, 1),
+ MTK_PIN_IES_SMT_SPEC(14, 28, 0x920, 2),
+ MTK_PIN_IES_SMT_SPEC(29, 32, 0x920, 3),
+ MTK_PIN_IES_SMT_SPEC(33, 33, 0x930, 11),
+ MTK_PIN_IES_SMT_SPEC(34, 38, 0x920, 10),
+ MTK_PIN_IES_SMT_SPEC(39, 42, 0x920, 11),
+ MTK_PIN_IES_SMT_SPEC(43, 45, 0x920, 12),
+ MTK_PIN_IES_SMT_SPEC(46, 49, 0x920, 13),
+ MTK_PIN_IES_SMT_SPEC(50, 52, 0x930, 10),
+ MTK_PIN_IES_SMT_SPEC(53, 56, 0x920, 14),
+ MTK_PIN_IES_SMT_SPEC(57, 58, 0x930, 0),
+ MTK_PIN_IES_SMT_SPEC(59, 65, 0x930, 2),
+ MTK_PIN_IES_SMT_SPEC(66, 71, 0x930, 3),
+ MTK_PIN_IES_SMT_SPEC(72, 74, 0x930, 4),
+ MTK_PIN_IES_SMT_SPEC(75, 76, 0x920, 15),
+ MTK_PIN_IES_SMT_SPEC(77, 78, 0x930, 1),
+ MTK_PIN_IES_SMT_SPEC(79, 82, 0x930, 5),
+ MTK_PIN_IES_SMT_SPEC(83, 84, 0x930, 6),
+ MTK_PIN_IES_SMT_SPEC(85, 85, 0xce0, 11),
+ MTK_PIN_IES_SMT_SPEC(86, 86, 0xcd0, 11),
+ MTK_PIN_IES_SMT_SPEC(87, 87, 0xd00, 3),
+ MTK_PIN_IES_SMT_SPEC(88, 88, 0xd00, 7),
+ MTK_PIN_IES_SMT_SPEC(89, 89, 0xd00, 11),
+ MTK_PIN_IES_SMT_SPEC(90, 90, 0xd00, 15),
+ MTK_PIN_IES_SMT_SPEC(117, 120, 0x930, 7),
+ MTK_PIN_IES_SMT_SPEC(121, 121, 0xc80, 11),
+ MTK_PIN_IES_SMT_SPEC(122, 122, 0xc70, 11),
+ MTK_PIN_IES_SMT_SPEC(123, 123, 0xca0, 3),
+ MTK_PIN_IES_SMT_SPEC(124, 124, 0xca0, 7),
+ MTK_PIN_IES_SMT_SPEC(125, 125, 0xca0, 11),
+ MTK_PIN_IES_SMT_SPEC(126, 126, 0xca0, 15),
+ MTK_PIN_IES_SMT_SPEC(127, 127, 0xc40, 15),
+ MTK_PIN_IES_SMT_SPEC(128, 128, 0xc40, 11),
+ MTK_PIN_IES_SMT_SPEC(129, 129, 0xc40, 7),
+ MTK_PIN_IES_SMT_SPEC(130, 130, 0xc40, 3),
+ MTK_PIN_IES_SMT_SPEC(131, 131, 0xc50, 3),
+ MTK_PIN_IES_SMT_SPEC(132, 132, 0xc10, 11),
+ MTK_PIN_IES_SMT_SPEC(133, 133, 0xc00, 11),
+ MTK_PIN_IES_SMT_SPEC(134, 134, 0xc30, 15),
+ MTK_PIN_IES_SMT_SPEC(135, 135, 0xc30, 11),
+ MTK_PIN_IES_SMT_SPEC(136, 136, 0xc30, 7),
+ MTK_PIN_IES_SMT_SPEC(137, 137, 0xc30, 3),
+ MTK_PIN_IES_SMT_SPEC(138, 141, 0x930, 9),
+ MTK_PIN_IES_SMT_SPEC(142, 142, 0x920, 13),
+};
+
+static int mt8127_ies_smt_set(struct regmap *regmap, unsigned int pin,
+ unsigned char align, int value, enum pin_config_param arg)
+{
+ if (arg == PIN_CONFIG_INPUT_ENABLE)
+ return mtk_pconf_spec_set_ies_smt_range(regmap, mt8127_ies_set,
+ ARRAY_SIZE(mt8127_ies_set), pin, align, value);
+ else if (arg == PIN_CONFIG_INPUT_SCHMITT_ENABLE)
+ return mtk_pconf_spec_set_ies_smt_range(regmap, mt8127_smt_set,
+ ARRAY_SIZE(mt8127_smt_set), pin, align, value);
+ return -EINVAL;
+}
+
+
+static const struct mtk_pinctrl_devdata mt8127_pinctrl_data = {
+ .pins = mtk_pins_mt8127,
+ .npins = ARRAY_SIZE(mtk_pins_mt8127),
+ .grp_desc = mt8127_drv_grp,
+ .n_grp_cls = ARRAY_SIZE(mt8127_drv_grp),
+ .pin_drv_grp = mt8127_pin_drv,
+ .n_pin_drv_grps = ARRAY_SIZE(mt8127_pin_drv),
+ .spec_pull_set = mt8127_spec_pull_set,
+ .spec_ies_smt_set = mt8127_ies_smt_set,
+ .dir_offset = 0x0000,
+ .pullen_offset = 0x0100,
+ .pullsel_offset = 0x0200,
+ .dout_offset = 0x0400,
+ .din_offset = 0x0500,
+ .pinmux_offset = 0x0600,
+ .type1_start = 143,
+ .type1_end = 143,
+ .port_shf = 4,
+ .port_mask = 0xf,
+ .port_align = 4,
+ .eint_offsets = {
+ .name = "mt8127_eint",
+ .stat = 0x000,
+ .ack = 0x040,
+ .mask = 0x080,
+ .mask_set = 0x0c0,
+ .mask_clr = 0x100,
+ .sens = 0x140,
+ .sens_set = 0x180,
+ .sens_clr = 0x1c0,
+ .soft = 0x200,
+ .soft_set = 0x240,
+ .soft_clr = 0x280,
+ .pol = 0x300,
+ .pol_set = 0x340,
+ .pol_clr = 0x380,
+ .dom_en = 0x400,
+ .dbnc_ctrl = 0x500,
+ .dbnc_set = 0x600,
+ .dbnc_clr = 0x700,
+ .port_mask = 7,
+ .ports = 6,
+ },
+ .ap_num = 143,
+ .db_cnt = 16,
+};
+
+static int mt8127_pinctrl_probe(struct platform_device *pdev)
+{
+ return mtk_pctrl_init(pdev, &mt8127_pinctrl_data, NULL);
+}
+
+static const struct of_device_id mt8127_pctrl_match[] = {
+ { .compatible = "mediatek,mt8127-pinctrl", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mt8127_pctrl_match);
+
+static struct platform_driver mtk_pinctrl_driver = {
+ .probe = mt8127_pinctrl_probe,
+ .driver = {
+ .name = "mediatek-mt8127-pinctrl",
+ .of_match_table = mt8127_pctrl_match,
+ },
+};
+
+static int __init mtk_pinctrl_init(void)
+{
+ return platform_driver_register(&mtk_pinctrl_driver);
+}
+
+module_init(mtk_pinctrl_init);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MediaTek MT8127 Pinctrl Driver");
+MODULE_AUTHOR("Yingjoe Chen <yingjoe.chen@mediatek.com>");
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8135.c b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
index f1e1e187ce96..404f1178511d 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8135.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
@@ -32,12 +32,12 @@
#define R1_BASE2 0x250
struct mtk_spec_pull_set {
- unsigned int pin;
- unsigned int pupd_offset;
+ unsigned char pin;
unsigned char pupd_bit;
- unsigned int r0_offset;
+ unsigned short pupd_offset;
+ unsigned short r0_offset;
+ unsigned short r1_offset;
unsigned char r0_bit;
- unsigned int r1_offset;
unsigned char r1_bit;
};
@@ -305,7 +305,6 @@ static const struct mtk_pinctrl_devdata mt8135_pinctrl_data = {
.pullen_offset = 0x0200,
.smt_offset = 0x0300,
.pullsel_offset = 0x0400,
- .invser_offset = 0x0600,
.dout_offset = 0x0800,
.din_offset = 0x0A00,
.pinmux_offset = 0x0C00,
@@ -314,7 +313,6 @@ static const struct mtk_pinctrl_devdata mt8135_pinctrl_data = {
.port_shf = 4,
.port_mask = 0xf,
.port_align = 4,
- .chip_type = MTK_CHIP_TYPE_BASE,
.eint_offsets = {
.name = "mt8135_eint",
.stat = 0x000,
@@ -344,7 +342,7 @@ static const struct mtk_pinctrl_devdata mt8135_pinctrl_data = {
static int mt8135_pinctrl_probe(struct platform_device *pdev)
{
- return mtk_pctrl_init(pdev, &mt8135_pinctrl_data);
+ return mtk_pctrl_init(pdev, &mt8135_pinctrl_data, NULL);
}
static const struct of_device_id mt8135_pctrl_match[] = {
@@ -359,7 +357,6 @@ static struct platform_driver mtk_pinctrl_driver = {
.probe = mt8135_pinctrl_probe,
.driver = {
.name = "mediatek-mt8135-pinctrl",
- .owner = THIS_MODULE,
.of_match_table = mt8135_pctrl_match,
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8173.c b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
index 412ea84836a1..d0c811d5f07b 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8173.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
@@ -18,6 +18,7 @@
#include <linux/of_device.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/regmap.h>
+#include <linux/pinctrl/pinconf-generic.h>
#include <dt-bindings/pinctrl/mt65xx.h>
#include "pinctrl-mtk-common.h"
@@ -25,228 +26,172 @@
#define DRV_BASE 0xb00
-/**
- * struct mtk_pin_ies_smt_set - For special pins' ies and smt setting.
- * @start: The start pin number of those special pins.
- * @end: The end pin number of those special pins.
- * @offset: The offset of special setting register.
- * @bit: The bit of special setting register.
- */
-struct mtk_pin_ies_smt_set {
- unsigned int start;
- unsigned int end;
- unsigned int offset;
- unsigned char bit;
+static const struct mtk_pin_spec_pupd_set_samereg mt8173_spec_pupd[] = {
+ MTK_PIN_PUPD_SPEC_SR(119, 0xe00, 2, 1, 0), /* KROW0 */
+ MTK_PIN_PUPD_SPEC_SR(120, 0xe00, 6, 5, 4), /* KROW1 */
+ MTK_PIN_PUPD_SPEC_SR(121, 0xe00, 10, 9, 8), /* KROW2 */
+ MTK_PIN_PUPD_SPEC_SR(122, 0xe10, 2, 1, 0), /* KCOL0 */
+ MTK_PIN_PUPD_SPEC_SR(123, 0xe10, 6, 5, 4), /* KCOL1 */
+ MTK_PIN_PUPD_SPEC_SR(124, 0xe10, 10, 9, 8), /* KCOL2 */
+
+ MTK_PIN_PUPD_SPEC_SR(67, 0xd10, 2, 1, 0), /* ms0 DS */
+ MTK_PIN_PUPD_SPEC_SR(68, 0xd00, 2, 1, 0), /* ms0 RST */
+ MTK_PIN_PUPD_SPEC_SR(66, 0xc10, 2, 1, 0), /* ms0 cmd */
+ MTK_PIN_PUPD_SPEC_SR(65, 0xc00, 2, 1, 0), /* ms0 clk */
+ MTK_PIN_PUPD_SPEC_SR(57, 0xc20, 2, 1, 0), /* ms0 data0 */
+ MTK_PIN_PUPD_SPEC_SR(58, 0xc20, 2, 1, 0), /* ms0 data1 */
+ MTK_PIN_PUPD_SPEC_SR(59, 0xc20, 2, 1, 0), /* ms0 data2 */
+ MTK_PIN_PUPD_SPEC_SR(60, 0xc20, 2, 1, 0), /* ms0 data3 */
+ MTK_PIN_PUPD_SPEC_SR(61, 0xc20, 2, 1, 0), /* ms0 data4 */
+ MTK_PIN_PUPD_SPEC_SR(62, 0xc20, 2, 1, 0), /* ms0 data5 */
+ MTK_PIN_PUPD_SPEC_SR(63, 0xc20, 2, 1, 0), /* ms0 data6 */
+ MTK_PIN_PUPD_SPEC_SR(64, 0xc20, 2, 1, 0), /* ms0 data7 */
+
+ MTK_PIN_PUPD_SPEC_SR(78, 0xc50, 2, 1, 0), /* ms1 cmd */
+ MTK_PIN_PUPD_SPEC_SR(73, 0xd20, 2, 1, 0), /* ms1 dat0 */
+ MTK_PIN_PUPD_SPEC_SR(74, 0xd20, 6, 5, 4), /* ms1 dat1 */
+ MTK_PIN_PUPD_SPEC_SR(75, 0xd20, 10, 9, 8), /* ms1 dat2 */
+ MTK_PIN_PUPD_SPEC_SR(76, 0xd20, 14, 13, 12), /* ms1 dat3 */
+ MTK_PIN_PUPD_SPEC_SR(77, 0xc40, 2, 1, 0), /* ms1 clk */
+
+ MTK_PIN_PUPD_SPEC_SR(100, 0xd40, 2, 1, 0), /* ms2 dat0 */
+ MTK_PIN_PUPD_SPEC_SR(101, 0xd40, 6, 5, 4), /* ms2 dat1 */
+ MTK_PIN_PUPD_SPEC_SR(102, 0xd40, 10, 9, 8), /* ms2 dat2 */
+ MTK_PIN_PUPD_SPEC_SR(103, 0xd40, 14, 13, 12), /* ms2 dat3 */
+ MTK_PIN_PUPD_SPEC_SR(104, 0xc80, 2, 1, 0), /* ms2 clk */
+ MTK_PIN_PUPD_SPEC_SR(105, 0xc90, 2, 1, 0), /* ms2 cmd */
+
+ MTK_PIN_PUPD_SPEC_SR(22, 0xd60, 2, 1, 0), /* ms3 dat0 */
+ MTK_PIN_PUPD_SPEC_SR(23, 0xd60, 6, 5, 4), /* ms3 dat1 */
+ MTK_PIN_PUPD_SPEC_SR(24, 0xd60, 10, 9, 8), /* ms3 dat2 */
+ MTK_PIN_PUPD_SPEC_SR(25, 0xd60, 14, 13, 12), /* ms3 dat3 */
+ MTK_PIN_PUPD_SPEC_SR(26, 0xcc0, 2, 1, 0), /* ms3 clk */
+ MTK_PIN_PUPD_SPEC_SR(27, 0xcd0, 2, 1, 0) /* ms3 cmd */
};
-#define MTK_PIN_IES_SMT_SET(_start, _end, _offset, _bit) \
- { \
- .start = _start, \
- .end = _end, \
- .bit = _bit, \
- .offset = _offset, \
- }
-
-/**
- * struct mtk_pin_spec_pupd_set - For special pins' pull up/down setting.
- * @pin: The pin number.
- * @offset: The offset of special pull up/down setting register.
- * @pupd_bit: The pull up/down bit in this register.
- * @r0_bit: The r0 bit of pull resistor.
- * @r1_bit: The r1 bit of pull resistor.
- */
-struct mtk_pin_spec_pupd_set {
- unsigned int pin;
- unsigned int offset;
- unsigned char pupd_bit;
- unsigned char r1_bit;
- unsigned char r0_bit;
-};
-
-#define MTK_PIN_PUPD_SPEC(_pin, _offset, _pupd, _r1, _r0) \
- { \
- .pin = _pin, \
- .offset = _offset, \
- .pupd_bit = _pupd, \
- .r1_bit = _r1, \
- .r0_bit = _r0, \
- }
-
-static const struct mtk_pin_spec_pupd_set mt8173_spec_pupd[] = {
- MTK_PIN_PUPD_SPEC(119, 0xe00, 2, 1, 0), /* KROW0 */
- MTK_PIN_PUPD_SPEC(120, 0xe00, 6, 5, 4), /* KROW1 */
- MTK_PIN_PUPD_SPEC(121, 0xe00, 10, 9, 8), /* KROW2 */
- MTK_PIN_PUPD_SPEC(122, 0xe10, 2, 1, 0), /* KCOL0 */
- MTK_PIN_PUPD_SPEC(123, 0xe10, 6, 5, 4), /* KCOL1 */
- MTK_PIN_PUPD_SPEC(124, 0xe10, 10, 9, 8), /* KCOL2 */
-
- MTK_PIN_PUPD_SPEC(67, 0xd10, 2, 1, 0), /* ms0 DS */
- MTK_PIN_PUPD_SPEC(68, 0xd00, 2, 1, 0), /* ms0 RST */
- MTK_PIN_PUPD_SPEC(66, 0xc10, 2, 1, 0), /* ms0 cmd */
- MTK_PIN_PUPD_SPEC(65, 0xc00, 2, 1, 0), /* ms0 clk */
- MTK_PIN_PUPD_SPEC(57, 0xc20, 2, 1, 0), /* ms0 data0 */
- MTK_PIN_PUPD_SPEC(58, 0xc20, 2, 1, 0), /* ms0 data1 */
- MTK_PIN_PUPD_SPEC(59, 0xc20, 2, 1, 0), /* ms0 data2 */
- MTK_PIN_PUPD_SPEC(60, 0xc20, 2, 1, 0), /* ms0 data3 */
- MTK_PIN_PUPD_SPEC(61, 0xc20, 2, 1, 0), /* ms0 data4 */
- MTK_PIN_PUPD_SPEC(62, 0xc20, 2, 1, 0), /* ms0 data5 */
- MTK_PIN_PUPD_SPEC(63, 0xc20, 2, 1, 0), /* ms0 data6 */
- MTK_PIN_PUPD_SPEC(64, 0xc20, 2, 1, 0), /* ms0 data7 */
-
- MTK_PIN_PUPD_SPEC(78, 0xc50, 2, 1, 0), /* ms1 cmd */
- MTK_PIN_PUPD_SPEC(73, 0xd20, 2, 1, 0), /* ms1 dat0 */
- MTK_PIN_PUPD_SPEC(74, 0xd20, 6, 5, 4), /* ms1 dat1 */
- MTK_PIN_PUPD_SPEC(75, 0xd20, 10, 9, 8), /* ms1 dat2 */
- MTK_PIN_PUPD_SPEC(76, 0xd20, 14, 13, 12), /* ms1 dat3 */
- MTK_PIN_PUPD_SPEC(77, 0xc40, 2, 1, 0), /* ms1 clk */
-
- MTK_PIN_PUPD_SPEC(100, 0xd40, 2, 1, 0), /* ms2 dat0 */
- MTK_PIN_PUPD_SPEC(101, 0xd40, 6, 5, 4), /* ms2 dat1 */
- MTK_PIN_PUPD_SPEC(102, 0xd40, 10, 9, 8), /* ms2 dat2 */
- MTK_PIN_PUPD_SPEC(103, 0xd40, 14, 13, 12), /* ms2 dat3 */
- MTK_PIN_PUPD_SPEC(104, 0xc80, 2, 1, 0), /* ms2 clk */
- MTK_PIN_PUPD_SPEC(105, 0xc90, 2, 1, 0), /* ms2 cmd */
-
- MTK_PIN_PUPD_SPEC(22, 0xd60, 2, 1, 0), /* ms3 dat0 */
- MTK_PIN_PUPD_SPEC(23, 0xd60, 6, 5, 4), /* ms3 dat1 */
- MTK_PIN_PUPD_SPEC(24, 0xd60, 10, 9, 8), /* ms3 dat2 */
- MTK_PIN_PUPD_SPEC(25, 0xd60, 14, 13, 12), /* ms3 dat3 */
- MTK_PIN_PUPD_SPEC(26, 0xcc0, 2, 1, 0), /* ms3 clk */
- MTK_PIN_PUPD_SPEC(27, 0xcd0, 2, 1, 0) /* ms3 cmd */
-};
-
-static int spec_pull_set(struct regmap *regmap, unsigned int pin,
+static int mt8173_spec_pull_set(struct regmap *regmap, unsigned int pin,
unsigned char align, bool isup, unsigned int r1r0)
{
- unsigned int i;
- unsigned int reg_pupd, reg_set, reg_rst;
- unsigned int bit_pupd, bit_r0, bit_r1;
- const struct mtk_pin_spec_pupd_set *spec_pupd_pin;
- bool find = false;
-
- for (i = 0; i < ARRAY_SIZE(mt8173_spec_pupd); i++) {
- if (pin == mt8173_spec_pupd[i].pin) {
- find = true;
- break;
- }
- }
-
- if (!find)
- return -EINVAL;
-
- spec_pupd_pin = mt8173_spec_pupd + i;
- reg_set = spec_pupd_pin->offset + align;
- reg_rst = spec_pupd_pin->offset + (align << 1);
-
- if (isup)
- reg_pupd = reg_rst;
- else
- reg_pupd = reg_set;
-
- bit_pupd = BIT(spec_pupd_pin->pupd_bit);
- regmap_write(regmap, reg_pupd, bit_pupd);
-
- bit_r0 = BIT(spec_pupd_pin->r0_bit);
- bit_r1 = BIT(spec_pupd_pin->r1_bit);
-
- switch (r1r0) {
- case MTK_PUPD_SET_R1R0_00:
- regmap_write(regmap, reg_rst, bit_r0);
- regmap_write(regmap, reg_rst, bit_r1);
- break;
- case MTK_PUPD_SET_R1R0_01:
- regmap_write(regmap, reg_set, bit_r0);
- regmap_write(regmap, reg_rst, bit_r1);
- break;
- case MTK_PUPD_SET_R1R0_10:
- regmap_write(regmap, reg_rst, bit_r0);
- regmap_write(regmap, reg_set, bit_r1);
- break;
- case MTK_PUPD_SET_R1R0_11:
- regmap_write(regmap, reg_set, bit_r0);
- regmap_write(regmap, reg_set, bit_r1);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
+ return mtk_pctrl_spec_pull_set_samereg(regmap, mt8173_spec_pupd,
+ ARRAY_SIZE(mt8173_spec_pupd), pin, align, isup, r1r0);
}
-static const struct mtk_pin_ies_smt_set mt8173_ies_smt_set[] = {
- MTK_PIN_IES_SMT_SET(0, 4, 0x930, 1),
- MTK_PIN_IES_SMT_SET(5, 9, 0x930, 2),
- MTK_PIN_IES_SMT_SET(10, 13, 0x930, 10),
- MTK_PIN_IES_SMT_SET(14, 15, 0x940, 10),
- MTK_PIN_IES_SMT_SET(16, 16, 0x930, 0),
- MTK_PIN_IES_SMT_SET(17, 17, 0x950, 2),
- MTK_PIN_IES_SMT_SET(18, 21, 0x940, 3),
- MTK_PIN_IES_SMT_SET(29, 32, 0x930, 3),
- MTK_PIN_IES_SMT_SET(33, 33, 0x930, 4),
- MTK_PIN_IES_SMT_SET(34, 36, 0x930, 5),
- MTK_PIN_IES_SMT_SET(37, 38, 0x930, 6),
- MTK_PIN_IES_SMT_SET(39, 39, 0x930, 7),
- MTK_PIN_IES_SMT_SET(40, 41, 0x930, 9),
- MTK_PIN_IES_SMT_SET(42, 42, 0x940, 0),
- MTK_PIN_IES_SMT_SET(43, 44, 0x930, 11),
- MTK_PIN_IES_SMT_SET(45, 46, 0x930, 12),
- MTK_PIN_IES_SMT_SET(57, 64, 0xc20, 13),
- MTK_PIN_IES_SMT_SET(65, 65, 0xc10, 13),
- MTK_PIN_IES_SMT_SET(66, 66, 0xc00, 13),
- MTK_PIN_IES_SMT_SET(67, 67, 0xd10, 13),
- MTK_PIN_IES_SMT_SET(68, 68, 0xd00, 13),
- MTK_PIN_IES_SMT_SET(69, 72, 0x940, 14),
- MTK_PIN_IES_SMT_SET(73, 76, 0xc60, 13),
- MTK_PIN_IES_SMT_SET(77, 77, 0xc40, 13),
- MTK_PIN_IES_SMT_SET(78, 78, 0xc50, 13),
- MTK_PIN_IES_SMT_SET(79, 82, 0x940, 15),
- MTK_PIN_IES_SMT_SET(83, 83, 0x950, 0),
- MTK_PIN_IES_SMT_SET(84, 85, 0x950, 1),
- MTK_PIN_IES_SMT_SET(86, 91, 0x950, 2),
- MTK_PIN_IES_SMT_SET(92, 92, 0x930, 13),
- MTK_PIN_IES_SMT_SET(93, 95, 0x930, 14),
- MTK_PIN_IES_SMT_SET(96, 99, 0x930, 15),
- MTK_PIN_IES_SMT_SET(100, 103, 0xca0, 13),
- MTK_PIN_IES_SMT_SET(104, 104, 0xc80, 13),
- MTK_PIN_IES_SMT_SET(105, 105, 0xc90, 13),
- MTK_PIN_IES_SMT_SET(106, 107, 0x940, 4),
- MTK_PIN_IES_SMT_SET(108, 112, 0x940, 1),
- MTK_PIN_IES_SMT_SET(113, 116, 0x940, 2),
- MTK_PIN_IES_SMT_SET(117, 118, 0x940, 5),
- MTK_PIN_IES_SMT_SET(119, 124, 0x940, 6),
- MTK_PIN_IES_SMT_SET(125, 126, 0x940, 7),
- MTK_PIN_IES_SMT_SET(127, 127, 0x940, 0),
- MTK_PIN_IES_SMT_SET(128, 128, 0x950, 8),
- MTK_PIN_IES_SMT_SET(129, 130, 0x950, 9),
- MTK_PIN_IES_SMT_SET(131, 132, 0x950, 8),
- MTK_PIN_IES_SMT_SET(133, 134, 0x910, 8)
+static const struct mtk_pin_ies_smt_set mt8173_smt_set[] = {
+ MTK_PIN_IES_SMT_SPEC(0, 4, 0x930, 1),
+ MTK_PIN_IES_SMT_SPEC(5, 9, 0x930, 2),
+ MTK_PIN_IES_SMT_SPEC(10, 13, 0x930, 10),
+ MTK_PIN_IES_SMT_SPEC(14, 15, 0x940, 10),
+ MTK_PIN_IES_SMT_SPEC(16, 16, 0x930, 0),
+ MTK_PIN_IES_SMT_SPEC(17, 17, 0x950, 2),
+ MTK_PIN_IES_SMT_SPEC(18, 21, 0x940, 3),
+ MTK_PIN_IES_SMT_SPEC(22, 25, 0xce0, 13),
+ MTK_PIN_IES_SMT_SPEC(26, 26, 0xcc0, 13),
+ MTK_PIN_IES_SMT_SPEC(27, 27, 0xcd0, 13),
+ MTK_PIN_IES_SMT_SPEC(28, 28, 0xd70, 13),
+ MTK_PIN_IES_SMT_SPEC(29, 32, 0x930, 3),
+ MTK_PIN_IES_SMT_SPEC(33, 33, 0x930, 4),
+ MTK_PIN_IES_SMT_SPEC(34, 36, 0x930, 5),
+ MTK_PIN_IES_SMT_SPEC(37, 38, 0x930, 6),
+ MTK_PIN_IES_SMT_SPEC(39, 39, 0x930, 7),
+ MTK_PIN_IES_SMT_SPEC(40, 41, 0x930, 9),
+ MTK_PIN_IES_SMT_SPEC(42, 42, 0x940, 0),
+ MTK_PIN_IES_SMT_SPEC(43, 44, 0x930, 11),
+ MTK_PIN_IES_SMT_SPEC(45, 46, 0x930, 12),
+ MTK_PIN_IES_SMT_SPEC(57, 64, 0xc20, 13),
+ MTK_PIN_IES_SMT_SPEC(65, 65, 0xc10, 13),
+ MTK_PIN_IES_SMT_SPEC(66, 66, 0xc00, 13),
+ MTK_PIN_IES_SMT_SPEC(67, 67, 0xd10, 13),
+ MTK_PIN_IES_SMT_SPEC(68, 68, 0xd00, 13),
+ MTK_PIN_IES_SMT_SPEC(69, 72, 0x940, 14),
+ MTK_PIN_IES_SMT_SPEC(73, 76, 0xc60, 13),
+ MTK_PIN_IES_SMT_SPEC(77, 77, 0xc40, 13),
+ MTK_PIN_IES_SMT_SPEC(78, 78, 0xc50, 13),
+ MTK_PIN_IES_SMT_SPEC(79, 82, 0x940, 15),
+ MTK_PIN_IES_SMT_SPEC(83, 83, 0x950, 0),
+ MTK_PIN_IES_SMT_SPEC(84, 85, 0x950, 1),
+ MTK_PIN_IES_SMT_SPEC(86, 91, 0x950, 2),
+ MTK_PIN_IES_SMT_SPEC(92, 92, 0x930, 13),
+ MTK_PIN_IES_SMT_SPEC(93, 95, 0x930, 14),
+ MTK_PIN_IES_SMT_SPEC(96, 99, 0x930, 15),
+ MTK_PIN_IES_SMT_SPEC(100, 103, 0xca0, 13),
+ MTK_PIN_IES_SMT_SPEC(104, 104, 0xc80, 13),
+ MTK_PIN_IES_SMT_SPEC(105, 105, 0xc90, 13),
+ MTK_PIN_IES_SMT_SPEC(106, 107, 0x940, 4),
+ MTK_PIN_IES_SMT_SPEC(108, 112, 0x940, 1),
+ MTK_PIN_IES_SMT_SPEC(113, 116, 0x940, 2),
+ MTK_PIN_IES_SMT_SPEC(117, 118, 0x940, 5),
+ MTK_PIN_IES_SMT_SPEC(119, 124, 0x940, 6),
+ MTK_PIN_IES_SMT_SPEC(125, 126, 0x940, 7),
+ MTK_PIN_IES_SMT_SPEC(127, 127, 0x940, 0),
+ MTK_PIN_IES_SMT_SPEC(128, 128, 0x950, 8),
+ MTK_PIN_IES_SMT_SPEC(129, 130, 0x950, 9),
+ MTK_PIN_IES_SMT_SPEC(131, 132, 0x950, 8),
+ MTK_PIN_IES_SMT_SPEC(133, 134, 0x910, 8)
};
-static int spec_ies_smt_set(struct regmap *regmap, unsigned int pin,
- unsigned char align, int value)
-{
- unsigned int i, reg_addr, bit;
- bool find = false;
-
- for (i = 0; i < ARRAY_SIZE(mt8173_ies_smt_set); i++) {
- if (pin >= mt8173_ies_smt_set[i].start &&
- pin <= mt8173_ies_smt_set[i].end) {
- find = true;
- break;
- }
- }
-
- if (!find)
- return -EINVAL;
-
- if (value)
- reg_addr = mt8173_ies_smt_set[i].offset + align;
- else
- reg_addr = mt8173_ies_smt_set[i].offset + (align << 1);
+static const struct mtk_pin_ies_smt_set mt8173_ies_set[] = {
+ MTK_PIN_IES_SMT_SPEC(0, 4, 0x900, 1),
+ MTK_PIN_IES_SMT_SPEC(5, 9, 0x900, 2),
+ MTK_PIN_IES_SMT_SPEC(10, 13, 0x900, 10),
+ MTK_PIN_IES_SMT_SPEC(14, 15, 0x910, 10),
+ MTK_PIN_IES_SMT_SPEC(16, 16, 0x900, 0),
+ MTK_PIN_IES_SMT_SPEC(17, 17, 0x920, 2),
+ MTK_PIN_IES_SMT_SPEC(18, 21, 0x910, 3),
+ MTK_PIN_IES_SMT_SPEC(22, 25, 0xce0, 14),
+ MTK_PIN_IES_SMT_SPEC(26, 26, 0xcc0, 14),
+ MTK_PIN_IES_SMT_SPEC(27, 27, 0xcd0, 14),
+ MTK_PIN_IES_SMT_SPEC(28, 28, 0xd70, 14),
+ MTK_PIN_IES_SMT_SPEC(29, 32, 0x900, 3),
+ MTK_PIN_IES_SMT_SPEC(33, 33, 0x900, 4),
+ MTK_PIN_IES_SMT_SPEC(34, 36, 0x900, 5),
+ MTK_PIN_IES_SMT_SPEC(37, 38, 0x900, 6),
+ MTK_PIN_IES_SMT_SPEC(39, 39, 0x900, 7),
+ MTK_PIN_IES_SMT_SPEC(40, 41, 0x900, 9),
+ MTK_PIN_IES_SMT_SPEC(42, 42, 0x910, 0),
+ MTK_PIN_IES_SMT_SPEC(43, 44, 0x900, 11),
+ MTK_PIN_IES_SMT_SPEC(45, 46, 0x900, 12),
+ MTK_PIN_IES_SMT_SPEC(57, 64, 0xc20, 14),
+ MTK_PIN_IES_SMT_SPEC(65, 65, 0xc10, 14),
+ MTK_PIN_IES_SMT_SPEC(66, 66, 0xc00, 14),
+ MTK_PIN_IES_SMT_SPEC(67, 67, 0xd10, 14),
+ MTK_PIN_IES_SMT_SPEC(68, 68, 0xd00, 14),
+ MTK_PIN_IES_SMT_SPEC(69, 72, 0x910, 14),
+ MTK_PIN_IES_SMT_SPEC(73, 76, 0xc60, 14),
+ MTK_PIN_IES_SMT_SPEC(77, 77, 0xc40, 14),
+ MTK_PIN_IES_SMT_SPEC(78, 78, 0xc50, 14),
+ MTK_PIN_IES_SMT_SPEC(79, 82, 0x910, 15),
+ MTK_PIN_IES_SMT_SPEC(83, 83, 0x920, 0),
+ MTK_PIN_IES_SMT_SPEC(84, 85, 0x920, 1),
+ MTK_PIN_IES_SMT_SPEC(86, 91, 0x920, 2),
+ MTK_PIN_IES_SMT_SPEC(92, 92, 0x900, 13),
+ MTK_PIN_IES_SMT_SPEC(93, 95, 0x900, 14),
+ MTK_PIN_IES_SMT_SPEC(96, 99, 0x900, 15),
+ MTK_PIN_IES_SMT_SPEC(100, 103, 0xca0, 14),
+ MTK_PIN_IES_SMT_SPEC(104, 104, 0xc80, 14),
+ MTK_PIN_IES_SMT_SPEC(105, 105, 0xc90, 14),
+ MTK_PIN_IES_SMT_SPEC(106, 107, 0x910, 4),
+ MTK_PIN_IES_SMT_SPEC(108, 112, 0x910, 1),
+ MTK_PIN_IES_SMT_SPEC(113, 116, 0x910, 2),
+ MTK_PIN_IES_SMT_SPEC(117, 118, 0x910, 5),
+ MTK_PIN_IES_SMT_SPEC(119, 124, 0x910, 6),
+ MTK_PIN_IES_SMT_SPEC(125, 126, 0x910, 7),
+ MTK_PIN_IES_SMT_SPEC(127, 127, 0x910, 0),
+ MTK_PIN_IES_SMT_SPEC(128, 128, 0x920, 8),
+ MTK_PIN_IES_SMT_SPEC(129, 130, 0x920, 9),
+ MTK_PIN_IES_SMT_SPEC(131, 132, 0x920, 8),
+ MTK_PIN_IES_SMT_SPEC(133, 134, 0x910, 8)
+};
- bit = BIT(mt8173_ies_smt_set[i].bit);
- regmap_write(regmap, reg_addr, bit);
- return 0;
+static int mt8173_ies_smt_set(struct regmap *regmap, unsigned int pin,
+ unsigned char align, int value, enum pin_config_param arg)
+{
+ if (arg == PIN_CONFIG_INPUT_ENABLE)
+ return mtk_pconf_spec_set_ies_smt_range(regmap, mt8173_ies_set,
+ ARRAY_SIZE(mt8173_ies_set), pin, align, value);
+ else if (arg == PIN_CONFIG_INPUT_SCHMITT_ENABLE)
+ return mtk_pconf_spec_set_ies_smt_range(regmap, mt8173_smt_set,
+ ARRAY_SIZE(mt8173_smt_set), pin, align, value);
+ return -EINVAL;
}
static const struct mtk_drv_group_desc mt8173_drv_grp[] = {
@@ -382,8 +327,8 @@ static const struct mtk_pinctrl_devdata mt8173_pinctrl_data = {
.n_grp_cls = ARRAY_SIZE(mt8173_drv_grp),
.pin_drv_grp = mt8173_pin_drv,
.n_pin_drv_grps = ARRAY_SIZE(mt8173_pin_drv),
- .spec_pull_set = spec_pull_set,
- .spec_ies_smt_set = spec_ies_smt_set,
+ .spec_pull_set = mt8173_spec_pull_set,
+ .spec_ies_smt_set = mt8173_ies_smt_set,
.dir_offset = 0x0000,
.pullen_offset = 0x0100,
.pullsel_offset = 0x0200,
@@ -424,7 +369,7 @@ static const struct mtk_pinctrl_devdata mt8173_pinctrl_data = {
static int mt8173_pinctrl_probe(struct platform_device *pdev)
{
- return mtk_pctrl_init(pdev, &mt8173_pinctrl_data);
+ return mtk_pctrl_init(pdev, &mt8173_pinctrl_data, NULL);
}
static const struct of_device_id mt8173_pctrl_match[] = {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index 474812e2b0cb..c4fc77aa766e 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -107,28 +107,38 @@ static void mtk_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
regmap_write(mtk_get_regmap(pctl, offset), reg_addr, bit);
}
-static void mtk_pconf_set_ies_smt(struct mtk_pinctrl *pctl, unsigned pin,
- int value, enum pin_config_param param)
+static int mtk_pconf_set_ies_smt(struct mtk_pinctrl *pctl, unsigned pin,
+ int value, enum pin_config_param arg)
{
unsigned int reg_addr, offset;
unsigned int bit;
- int ret;
+
+ /**
+ * Due to some soc are not support ies/smt config, add this special
+ * control to handle it.
+ */
+ if (!pctl->devdata->spec_ies_smt_set &&
+ pctl->devdata->ies_offset == MTK_PINCTRL_NOT_SUPPORT &&
+ arg == PIN_CONFIG_INPUT_ENABLE)
+ return -EINVAL;
+
+ if (!pctl->devdata->spec_ies_smt_set &&
+ pctl->devdata->smt_offset == MTK_PINCTRL_NOT_SUPPORT &&
+ arg == PIN_CONFIG_INPUT_SCHMITT_ENABLE)
+ return -EINVAL;
/*
* Due to some pins are irregular, their input enable and smt
- * control register are discontinuous, but they are mapping together.
- * So we need this special handle.
+ * control register are discontinuous, so we need this special handle.
*/
if (pctl->devdata->spec_ies_smt_set) {
- ret = pctl->devdata->spec_ies_smt_set(mtk_get_regmap(pctl, pin),
- pin, pctl->devdata->port_align, value);
- if (!ret)
- return;
+ return pctl->devdata->spec_ies_smt_set(mtk_get_regmap(pctl, pin),
+ pin, pctl->devdata->port_align, value, arg);
}
bit = BIT(pin & 0xf);
- if (param == PIN_CONFIG_INPUT_ENABLE)
+ if (arg == PIN_CONFIG_INPUT_ENABLE)
offset = pctl->devdata->ies_offset;
else
offset = pctl->devdata->smt_offset;
@@ -139,6 +149,33 @@ static void mtk_pconf_set_ies_smt(struct mtk_pinctrl *pctl, unsigned pin,
reg_addr = CLR_ADDR(mtk_get_port(pctl, pin) + offset, pctl);
regmap_write(mtk_get_regmap(pctl, pin), reg_addr, bit);
+ return 0;
+}
+
+int mtk_pconf_spec_set_ies_smt_range(struct regmap *regmap,
+ const struct mtk_pin_ies_smt_set *ies_smt_infos, unsigned int info_num,
+ unsigned int pin, unsigned char align, int value)
+{
+ unsigned int i, reg_addr, bit;
+
+ for (i = 0; i < info_num; i++) {
+ if (pin >= ies_smt_infos[i].start &&
+ pin <= ies_smt_infos[i].end) {
+ break;
+ }
+ }
+
+ if (i == info_num)
+ return -EINVAL;
+
+ if (value)
+ reg_addr = ies_smt_infos[i].offset + align;
+ else
+ reg_addr = ies_smt_infos[i].offset + (align << 1);
+
+ bit = BIT(ies_smt_infos[i].bit);
+ regmap_write(regmap, reg_addr, bit);
+ return 0;
}
static const struct mtk_pin_drv_grp *mtk_find_pin_drv_grp_by_pin(
@@ -186,6 +223,66 @@ static int mtk_pconf_set_driving(struct mtk_pinctrl *pctl,
return -EINVAL;
}
+int mtk_pctrl_spec_pull_set_samereg(struct regmap *regmap,
+ const struct mtk_pin_spec_pupd_set_samereg *pupd_infos,
+ unsigned int info_num, unsigned int pin,
+ unsigned char align, bool isup, unsigned int r1r0)
+{
+ unsigned int i;
+ unsigned int reg_pupd, reg_set, reg_rst;
+ unsigned int bit_pupd, bit_r0, bit_r1;
+ const struct mtk_pin_spec_pupd_set_samereg *spec_pupd_pin;
+ bool find = false;
+
+ for (i = 0; i < info_num; i++) {
+ if (pin == pupd_infos[i].pin) {
+ find = true;
+ break;
+ }
+ }
+
+ if (!find)
+ return -EINVAL;
+
+ spec_pupd_pin = pupd_infos + i;
+ reg_set = spec_pupd_pin->offset + align;
+ reg_rst = spec_pupd_pin->offset + (align << 1);
+
+ if (isup)
+ reg_pupd = reg_rst;
+ else
+ reg_pupd = reg_set;
+
+ bit_pupd = BIT(spec_pupd_pin->pupd_bit);
+ regmap_write(regmap, reg_pupd, bit_pupd);
+
+ bit_r0 = BIT(spec_pupd_pin->r0_bit);
+ bit_r1 = BIT(spec_pupd_pin->r1_bit);
+
+ switch (r1r0) {
+ case MTK_PUPD_SET_R1R0_00:
+ regmap_write(regmap, reg_rst, bit_r0);
+ regmap_write(regmap, reg_rst, bit_r1);
+ break;
+ case MTK_PUPD_SET_R1R0_01:
+ regmap_write(regmap, reg_set, bit_r0);
+ regmap_write(regmap, reg_rst, bit_r1);
+ break;
+ case MTK_PUPD_SET_R1R0_10:
+ regmap_write(regmap, reg_rst, bit_r0);
+ regmap_write(regmap, reg_set, bit_r1);
+ break;
+ case MTK_PUPD_SET_R1R0_11:
+ regmap_write(regmap, reg_set, bit_r0);
+ regmap_write(regmap, reg_set, bit_r1);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int mtk_pconf_set_pull_select(struct mtk_pinctrl *pctl,
unsigned int pin, bool enable, bool isup, unsigned int arg)
{
@@ -235,36 +332,37 @@ static int mtk_pconf_parse_conf(struct pinctrl_dev *pctldev,
unsigned int pin, enum pin_config_param param,
enum pin_config_param arg)
{
+ int ret = 0;
struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
- mtk_pconf_set_pull_select(pctl, pin, false, false, arg);
+ ret = mtk_pconf_set_pull_select(pctl, pin, false, false, arg);
break;
case PIN_CONFIG_BIAS_PULL_UP:
- mtk_pconf_set_pull_select(pctl, pin, true, true, arg);
+ ret = mtk_pconf_set_pull_select(pctl, pin, true, true, arg);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
- mtk_pconf_set_pull_select(pctl, pin, true, false, arg);
+ ret = mtk_pconf_set_pull_select(pctl, pin, true, false, arg);
break;
case PIN_CONFIG_INPUT_ENABLE:
- mtk_pconf_set_ies_smt(pctl, pin, arg, param);
+ ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param);
break;
case PIN_CONFIG_OUTPUT:
mtk_gpio_set(pctl->chip, pin, arg);
- mtk_pmx_gpio_set_direction(pctldev, NULL, pin, false);
+ ret = mtk_pmx_gpio_set_direction(pctldev, NULL, pin, false);
break;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
- mtk_pconf_set_ies_smt(pctl, pin, arg, param);
+ ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param);
break;
case PIN_CONFIG_DRIVE_STRENGTH:
- mtk_pconf_set_driving(pctl, pin, arg);
+ ret = mtk_pconf_set_driving(pctl, pin, arg);
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+ return ret;
}
static int mtk_pconf_group_get(struct pinctrl_dev *pctldev,
@@ -283,12 +381,14 @@ static int mtk_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group,
{
struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
struct mtk_pinctrl_group *g = &pctl->groups[group];
- int i;
+ int i, ret;
for (i = 0; i < num_configs; i++) {
- mtk_pconf_parse_conf(pctldev, g->pin,
+ ret = mtk_pconf_parse_conf(pctldev, g->pin,
pinconf_to_config_param(configs[i]),
pinconf_to_config_argument(configs[i]));
+ if (ret < 0)
+ return ret;
g->config = configs[i];
}
@@ -1109,7 +1209,8 @@ static struct pinctrl_desc mtk_pctrl_desc = {
};
int mtk_pctrl_init(struct platform_device *pdev,
- const struct mtk_pinctrl_devdata *data)
+ const struct mtk_pinctrl_devdata *data,
+ struct regmap *regmap)
{
struct pinctrl_pin_desc *pins;
struct mtk_pinctrl *pctl;
@@ -1135,6 +1236,11 @@ int mtk_pctrl_init(struct platform_device *pdev,
pctl->regmap1 = syscon_node_to_regmap(node);
if (IS_ERR(pctl->regmap1))
return PTR_ERR(pctl->regmap1);
+ } else if (regmap) {
+ pctl->regmap1 = regmap;
+ } else {
+ dev_err(&pdev->dev, "Pinctrl node has not register regmap.\n");
+ return -EINVAL;
}
/* Only 8135 has two base addr, other SoCs have only one. */
@@ -1165,9 +1271,9 @@ int mtk_pctrl_init(struct platform_device *pdev,
mtk_pctrl_desc.npins = pctl->devdata->npins;
pctl->dev = &pdev->dev;
pctl->pctl_dev = pinctrl_register(&mtk_pctrl_desc, &pdev->dev, pctl);
- if (!pctl->pctl_dev) {
+ if (IS_ERR(pctl->pctl_dev)) {
dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
- return -EINVAL;
+ return PTR_ERR(pctl->pctl_dev);
}
pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL);
@@ -1176,11 +1282,11 @@ int mtk_pctrl_init(struct platform_device *pdev,
goto pctrl_error;
}
- pctl->chip = &mtk_gpio_chip;
+ *pctl->chip = mtk_gpio_chip;
pctl->chip->ngpio = pctl->devdata->npins;
pctl->chip->label = dev_name(&pdev->dev);
pctl->chip->dev = &pdev->dev;
- pctl->chip->base = 0;
+ pctl->chip->base = -1;
ret = gpiochip_add(pctl->chip);
if (ret) {
@@ -1196,6 +1302,9 @@ int mtk_pctrl_init(struct platform_device *pdev,
goto chip_error;
}
+ if (!of_property_read_bool(np, "interrupt-controller"))
+ return 0;
+
/* Get EINT register base from dts. */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
index 375771db9bd0..30213e514c2f 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
@@ -17,16 +17,17 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/regmap.h>
+#include <linux/pinctrl/pinconf-generic.h>
#define NO_EINT_SUPPORT 255
-#define MTK_CHIP_TYPE_BASE 0
-#define MTK_CHIP_TYPE_PMIC 1
#define MT_EDGE_SENSITIVE 0
#define MT_LEVEL_SENSITIVE 1
#define EINT_DBNC_SET_DBNC_BITS 4
#define EINT_DBNC_RST_BIT (0x1 << 1)
#define EINT_DBNC_SET_EN (0x1 << 0)
+#define MTK_PINCTRL_NOT_SUPPORT (0xffff)
+
struct mtk_desc_function {
const char *name;
unsigned char muxval;
@@ -39,7 +40,6 @@ struct mtk_desc_eint {
struct mtk_desc_pin {
struct pinctrl_pin_desc pin;
- const char *chip;
const struct mtk_desc_eint eint;
const struct mtk_desc_function *functions;
};
@@ -47,7 +47,6 @@ struct mtk_desc_pin {
#define MTK_PIN(_pin, _pad, _chip, _eint, ...) \
{ \
.pin = _pin, \
- .chip = _chip, \
.eint = _eint, \
.functions = (struct mtk_desc_function[]){ \
__VA_ARGS__, { } }, \
@@ -107,8 +106,8 @@ struct mtk_drv_group_desc {
* @grp: The group for this pin belongs to.
*/
struct mtk_pin_drv_grp {
- unsigned int pin;
- unsigned int offset;
+ unsigned short pin;
+ unsigned short offset;
unsigned char bit;
unsigned char grp;
};
@@ -121,6 +120,54 @@ struct mtk_pin_drv_grp {
.grp = _grp, \
}
+/**
+ * struct mtk_pin_spec_pupd_set_samereg
+ * - For special pins' pull up/down setting which resides in same register
+ * @pin: The pin number.
+ * @offset: The offset of special pull up/down setting register.
+ * @pupd_bit: The pull up/down bit in this register.
+ * @r0_bit: The r0 bit of pull resistor.
+ * @r1_bit: The r1 bit of pull resistor.
+ */
+struct mtk_pin_spec_pupd_set_samereg {
+ unsigned short pin;
+ unsigned short offset;
+ unsigned char pupd_bit;
+ unsigned char r1_bit;
+ unsigned char r0_bit;
+};
+
+#define MTK_PIN_PUPD_SPEC_SR(_pin, _offset, _pupd, _r1, _r0) \
+ { \
+ .pin = _pin, \
+ .offset = _offset, \
+ .pupd_bit = _pupd, \
+ .r1_bit = _r1, \
+ .r0_bit = _r0, \
+ }
+
+/**
+ * struct mtk_pin_ies_set - For special pins' ies and smt setting.
+ * @start: The start pin number of those special pins.
+ * @end: The end pin number of those special pins.
+ * @offset: The offset of special setting register.
+ * @bit: The bit of special setting register.
+ */
+struct mtk_pin_ies_smt_set {
+ unsigned short start;
+ unsigned short end;
+ unsigned short offset;
+ unsigned char bit;
+};
+
+#define MTK_PIN_IES_SMT_SPEC(_start, _end, _offset, _bit) \
+ { \
+ .start = _start, \
+ .end = _end, \
+ .bit = _bit, \
+ .offset = _offset, \
+ }
+
struct mtk_eint_offsets {
const char *name;
unsigned int stat;
@@ -186,14 +233,13 @@ struct mtk_pinctrl_devdata {
int (*spec_pull_set)(struct regmap *reg, unsigned int pin,
unsigned char align, bool isup, unsigned int arg);
int (*spec_ies_smt_set)(struct regmap *reg, unsigned int pin,
- unsigned char align, int value);
+ unsigned char align, int value, enum pin_config_param arg);
unsigned int dir_offset;
unsigned int ies_offset;
unsigned int smt_offset;
unsigned int pullen_offset;
unsigned int pullsel_offset;
unsigned int drv_offset;
- unsigned int invser_offset;
unsigned int dout_offset;
unsigned int din_offset;
unsigned int pinmux_offset;
@@ -202,7 +248,6 @@ struct mtk_pinctrl_devdata {
unsigned char port_shf;
unsigned char port_mask;
unsigned char port_align;
- unsigned char chip_type;
struct mtk_eint_offsets eint_offsets;
unsigned int ap_num;
unsigned int db_cnt;
@@ -224,6 +269,16 @@ struct mtk_pinctrl {
};
int mtk_pctrl_init(struct platform_device *pdev,
- const struct mtk_pinctrl_devdata *data);
+ const struct mtk_pinctrl_devdata *data,
+ struct regmap *regmap);
+
+int mtk_pctrl_spec_pull_set_samereg(struct regmap *regmap,
+ const struct mtk_pin_spec_pupd_set_samereg *pupd_infos,
+ unsigned int info_num, unsigned int pin,
+ unsigned char align, bool isup, unsigned int r1r0);
+
+int mtk_pconf_spec_set_ies_smt_range(struct regmap *regmap,
+ const struct mtk_pin_ies_smt_set *ies_smt_infos, unsigned int info_num,
+ unsigned int pin, unsigned char align, int value);
#endif /* __PINCTRL_MTK_COMMON_H */
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt6397.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt6397.h
new file mode 100644
index 000000000000..4eb98ddb40a4
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt6397.h
@@ -0,0 +1,424 @@
+#ifndef __PINCTRL_MTK_MT6397_H
+#define __PINCTRL_MTK_MT6397_H
+
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-mtk-common.h"
+
+static const struct mtk_desc_pin mtk_pins_mt6397[] = {
+ MTK_PIN(
+ PINCTRL_PIN(0, "INT"),
+ "N2", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO0"),
+ MTK_FUNCTION(1, "INT")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(1, "SRCVOLTEN"),
+ "M4", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO1"),
+ MTK_FUNCTION(1, "SRCVOLTEN"),
+ MTK_FUNCTION(6, "TEST_CK1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(2, "SRCLKEN_PERI"),
+ "M2", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO2"),
+ MTK_FUNCTION(1, "SRCLKEN_PERI"),
+ MTK_FUNCTION(6, "TEST_CK2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(3, "RTC_32K1V8"),
+ "K3", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO3"),
+ MTK_FUNCTION(1, "RTC_32K1V8"),
+ MTK_FUNCTION(6, "TEST_CK3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(4, "WRAP_EVENT"),
+ "J2", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO4"),
+ MTK_FUNCTION(1, "WRAP_EVENT")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(5, "SPI_CLK"),
+ "L4", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO5"),
+ MTK_FUNCTION(1, "SPI_CLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(6, "SPI_CSN"),
+ "J3", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO6"),
+ MTK_FUNCTION(1, "SPI_CSN")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(7, "SPI_MOSI"),
+ "J1", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO7"),
+ MTK_FUNCTION(1, "SPI_MOSI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(8, "SPI_MISO"),
+ "L3", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO8"),
+ MTK_FUNCTION(1, "SPI_MISO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(9, "AUD_CLK_MOSI"),
+ "H2", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO9"),
+ MTK_FUNCTION(1, "AUD_CLK"),
+ MTK_FUNCTION(6, "TEST_IN0"),
+ MTK_FUNCTION(7, "TEST_OUT0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(10, "AUD_DAT_MISO"),
+ "H3", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO10"),
+ MTK_FUNCTION(1, "AUD_MISO"),
+ MTK_FUNCTION(6, "TEST_IN1"),
+ MTK_FUNCTION(7, "TEST_OUT1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(11, "AUD_DAT_MOSI"),
+ "H1", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO11"),
+ MTK_FUNCTION(1, "AUD_MOSI"),
+ MTK_FUNCTION(6, "TEST_IN2"),
+ MTK_FUNCTION(7, "TEST_OUT2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(12, "COL0"),
+ "F3", "mt6397",
+ MTK_EINT_FUNCTION(2, 10),
+ MTK_FUNCTION(0, "GPIO12"),
+ MTK_FUNCTION(1, "COL0_USBDL"),
+ MTK_FUNCTION(2, "EINT10_1X"),
+ MTK_FUNCTION(3, "PWM1_3X"),
+ MTK_FUNCTION(6, "TEST_IN3"),
+ MTK_FUNCTION(7, "TEST_OUT3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(13, "COL1"),
+ "G8", "mt6397",
+ MTK_EINT_FUNCTION(2, 11),
+ MTK_FUNCTION(0, "GPIO13"),
+ MTK_FUNCTION(1, "COL1"),
+ MTK_FUNCTION(2, "EINT11_1X"),
+ MTK_FUNCTION(3, "SCL0_2X"),
+ MTK_FUNCTION(6, "TEST_IN4"),
+ MTK_FUNCTION(7, "TEST_OUT4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(14, "COL2"),
+ "H4", "mt6397",
+ MTK_EINT_FUNCTION(2, 12),
+ MTK_FUNCTION(0, "GPIO14"),
+ MTK_FUNCTION(1, "COL2"),
+ MTK_FUNCTION(2, "EINT12_1X"),
+ MTK_FUNCTION(3, "SDA0_2X"),
+ MTK_FUNCTION(6, "TEST_IN5"),
+ MTK_FUNCTION(7, "TEST_OUT5")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(15, "COL3"),
+ "G2", "mt6397",
+ MTK_EINT_FUNCTION(2, 13),
+ MTK_FUNCTION(0, "GPIO15"),
+ MTK_FUNCTION(1, "COL3"),
+ MTK_FUNCTION(2, "EINT13_1X"),
+ MTK_FUNCTION(3, "SCL1_2X"),
+ MTK_FUNCTION(6, "TEST_IN6"),
+ MTK_FUNCTION(7, "TEST_OUT6")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(16, "COL4"),
+ "F2", "mt6397",
+ MTK_EINT_FUNCTION(2, 14),
+ MTK_FUNCTION(0, "GPIO16"),
+ MTK_FUNCTION(1, "COL4"),
+ MTK_FUNCTION(2, "EINT14_1X"),
+ MTK_FUNCTION(3, "SDA1_2X"),
+ MTK_FUNCTION(6, "TEST_IN7"),
+ MTK_FUNCTION(7, "TEST_OUT7")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(17, "COL5"),
+ "G7", "mt6397",
+ MTK_EINT_FUNCTION(2, 15),
+ MTK_FUNCTION(0, "GPIO17"),
+ MTK_FUNCTION(1, "COL5"),
+ MTK_FUNCTION(2, "EINT15_1X"),
+ MTK_FUNCTION(3, "SCL2_2X"),
+ MTK_FUNCTION(6, "TEST_IN8"),
+ MTK_FUNCTION(7, "TEST_OUT8")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(18, "COL6"),
+ "J6", "mt6397",
+ MTK_EINT_FUNCTION(2, 16),
+ MTK_FUNCTION(0, "GPIO18"),
+ MTK_FUNCTION(1, "COL6"),
+ MTK_FUNCTION(2, "EINT16_1X"),
+ MTK_FUNCTION(3, "SDA2_2X"),
+ MTK_FUNCTION(4, "GPIO32K_0"),
+ MTK_FUNCTION(5, "GPIO26M_0"),
+ MTK_FUNCTION(6, "TEST_IN9"),
+ MTK_FUNCTION(7, "TEST_OUT9")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(19, "COL7"),
+ "J5", "mt6397",
+ MTK_EINT_FUNCTION(2, 17),
+ MTK_FUNCTION(0, "GPIO19"),
+ MTK_FUNCTION(1, "COL7"),
+ MTK_FUNCTION(2, "EINT17_1X"),
+ MTK_FUNCTION(3, "PWM2_3X"),
+ MTK_FUNCTION(4, "GPIO32K_1"),
+ MTK_FUNCTION(5, "GPIO26M_1"),
+ MTK_FUNCTION(6, "TEST_IN10"),
+ MTK_FUNCTION(7, "TEST_OUT10")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(20, "ROW0"),
+ "L7", "mt6397",
+ MTK_EINT_FUNCTION(2, 18),
+ MTK_FUNCTION(0, "GPIO20"),
+ MTK_FUNCTION(1, "ROW0"),
+ MTK_FUNCTION(2, "EINT18_1X"),
+ MTK_FUNCTION(3, "SCL0_3X"),
+ MTK_FUNCTION(6, "TEST_IN11"),
+ MTK_FUNCTION(7, "TEST_OUT11")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(21, "ROW1"),
+ "P1", "mt6397",
+ MTK_EINT_FUNCTION(2, 19),
+ MTK_FUNCTION(0, "GPIO21"),
+ MTK_FUNCTION(1, "ROW1"),
+ MTK_FUNCTION(2, "EINT19_1X"),
+ MTK_FUNCTION(3, "SDA0_3X"),
+ MTK_FUNCTION(4, "AUD_TSTCK"),
+ MTK_FUNCTION(6, "TEST_IN12"),
+ MTK_FUNCTION(7, "TEST_OUT12")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(22, "ROW2"),
+ "J8", "mt6397",
+ MTK_EINT_FUNCTION(2, 20),
+ MTK_FUNCTION(0, "GPIO22"),
+ MTK_FUNCTION(1, "ROW2"),
+ MTK_FUNCTION(2, "EINT20_1X"),
+ MTK_FUNCTION(3, "SCL1_3X"),
+ MTK_FUNCTION(6, "TEST_IN13"),
+ MTK_FUNCTION(7, "TEST_OUT13")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(23, "ROW3"),
+ "J7", "mt6397",
+ MTK_EINT_FUNCTION(2, 21),
+ MTK_FUNCTION(0, "GPIO23"),
+ MTK_FUNCTION(1, "ROW3"),
+ MTK_FUNCTION(2, "EINT21_1X"),
+ MTK_FUNCTION(3, "SDA1_3X"),
+ MTK_FUNCTION(6, "TEST_IN14"),
+ MTK_FUNCTION(7, "TEST_OUT14")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(24, "ROW4"),
+ "L5", "mt6397",
+ MTK_EINT_FUNCTION(2, 22),
+ MTK_FUNCTION(0, "GPIO24"),
+ MTK_FUNCTION(1, "ROW4"),
+ MTK_FUNCTION(2, "EINT22_1X"),
+ MTK_FUNCTION(3, "SCL2_3X"),
+ MTK_FUNCTION(6, "TEST_IN15"),
+ MTK_FUNCTION(7, "TEST_OUT15")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(25, "ROW5"),
+ "N6", "mt6397",
+ MTK_EINT_FUNCTION(2, 23),
+ MTK_FUNCTION(0, "GPIO25"),
+ MTK_FUNCTION(1, "ROW5"),
+ MTK_FUNCTION(2, "EINT23_1X"),
+ MTK_FUNCTION(3, "SDA2_3X"),
+ MTK_FUNCTION(6, "TEST_IN16"),
+ MTK_FUNCTION(7, "TEST_OUT16")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(26, "ROW6"),
+ "L6", "mt6397",
+ MTK_EINT_FUNCTION(2, 24),
+ MTK_FUNCTION(0, "GPIO26"),
+ MTK_FUNCTION(1, "ROW6"),
+ MTK_FUNCTION(2, "EINT24_1X"),
+ MTK_FUNCTION(3, "PWM3_3X"),
+ MTK_FUNCTION(4, "GPIO32K_2"),
+ MTK_FUNCTION(5, "GPIO26M_2"),
+ MTK_FUNCTION(6, "TEST_IN17"),
+ MTK_FUNCTION(7, "TEST_OUT17")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(27, "ROW7"),
+ "P2", "mt6397",
+ MTK_EINT_FUNCTION(2, 3),
+ MTK_FUNCTION(0, "GPIO27"),
+ MTK_FUNCTION(1, "ROW7"),
+ MTK_FUNCTION(2, "EINT3_1X"),
+ MTK_FUNCTION(3, "CBUS"),
+ MTK_FUNCTION(4, "GPIO32K_3"),
+ MTK_FUNCTION(5, "GPIO26M_3"),
+ MTK_FUNCTION(6, "TEST_IN18"),
+ MTK_FUNCTION(7, "TEST_OUT18")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(28, "PWM1(VMSEL1)"),
+ "J4", "mt6397",
+ MTK_EINT_FUNCTION(2, 4),
+ MTK_FUNCTION(0, "GPIO28"),
+ MTK_FUNCTION(1, "PWM1"),
+ MTK_FUNCTION(2, "EINT4_1X"),
+ MTK_FUNCTION(4, "GPIO32K_4"),
+ MTK_FUNCTION(5, "GPIO26M_4"),
+ MTK_FUNCTION(6, "TEST_IN19"),
+ MTK_FUNCTION(7, "TEST_OUT19")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(29, "PWM2(VMSEL2)"),
+ "N5", "mt6397",
+ MTK_EINT_FUNCTION(2, 5),
+ MTK_FUNCTION(0, "GPIO29"),
+ MTK_FUNCTION(1, "PWM2"),
+ MTK_FUNCTION(2, "EINT5_1X"),
+ MTK_FUNCTION(4, "GPIO32K_5"),
+ MTK_FUNCTION(5, "GPIO26M_5"),
+ MTK_FUNCTION(6, "TEST_IN20"),
+ MTK_FUNCTION(7, "TEST_OUT20")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(30, "PWM3(PWM)"),
+ "R3", "mt6397",
+ MTK_EINT_FUNCTION(2, 6),
+ MTK_FUNCTION(0, "GPIO30"),
+ MTK_FUNCTION(1, "PWM3"),
+ MTK_FUNCTION(2, "EINT6_1X"),
+ MTK_FUNCTION(3, "COL0"),
+ MTK_FUNCTION(4, "GPIO32K_6"),
+ MTK_FUNCTION(5, "GPIO26M_6"),
+ MTK_FUNCTION(6, "TEST_IN21"),
+ MTK_FUNCTION(7, "TEST_OUT21")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(31, "SCL0"),
+ "N1", "mt6397",
+ MTK_EINT_FUNCTION(2, 7),
+ MTK_FUNCTION(0, "GPIO31"),
+ MTK_FUNCTION(1, "SCL0"),
+ MTK_FUNCTION(2, "EINT7_1X"),
+ MTK_FUNCTION(3, "PWM1_2X"),
+ MTK_FUNCTION(6, "TEST_IN22"),
+ MTK_FUNCTION(7, "TEST_OUT22")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(32, "SDA0"),
+ "N3", "mt6397",
+ MTK_EINT_FUNCTION(2, 8),
+ MTK_FUNCTION(0, "GPIO32"),
+ MTK_FUNCTION(1, "SDA0"),
+ MTK_FUNCTION(2, "EINT8_1X"),
+ MTK_FUNCTION(6, "TEST_IN23"),
+ MTK_FUNCTION(7, "TEST_OUT23")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(33, "SCL1"),
+ "T1", "mt6397",
+ MTK_EINT_FUNCTION(2, 9),
+ MTK_FUNCTION(0, "GPIO33"),
+ MTK_FUNCTION(1, "SCL1"),
+ MTK_FUNCTION(2, "EINT9_1X"),
+ MTK_FUNCTION(3, "PWM2_2X"),
+ MTK_FUNCTION(6, "TEST_IN24"),
+ MTK_FUNCTION(7, "TEST_OUT24")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(34, "SDA1"),
+ "T2", "mt6397",
+ MTK_EINT_FUNCTION(2, 0),
+ MTK_FUNCTION(0, "GPIO34"),
+ MTK_FUNCTION(1, "SDA1"),
+ MTK_FUNCTION(2, "EINT0_1X"),
+ MTK_FUNCTION(6, "TEST_IN25"),
+ MTK_FUNCTION(7, "TEST_OUT25")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(35, "SCL2"),
+ "T3", "mt6397",
+ MTK_EINT_FUNCTION(2, 1),
+ MTK_FUNCTION(0, "GPIO35"),
+ MTK_FUNCTION(1, "SCL2"),
+ MTK_FUNCTION(2, "EINT1_1X"),
+ MTK_FUNCTION(3, "PWM3_2X"),
+ MTK_FUNCTION(6, "TEST_IN26"),
+ MTK_FUNCTION(7, "TEST_OUT26")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(36, "SDA2"),
+ "U2", "mt6397",
+ MTK_EINT_FUNCTION(2, 2),
+ MTK_FUNCTION(0, "GPIO36"),
+ MTK_FUNCTION(1, "SDA2"),
+ MTK_FUNCTION(2, "EINT2_1X"),
+ MTK_FUNCTION(6, "TEST_IN27"),
+ MTK_FUNCTION(7, "TEST_OUT27")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(37, "HDMISD"),
+ "H6", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO37"),
+ MTK_FUNCTION(1, "HDMISD"),
+ MTK_FUNCTION(6, "TEST_IN28"),
+ MTK_FUNCTION(7, "TEST_OUT28")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(38, "HDMISCK"),
+ "H5", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO38"),
+ MTK_FUNCTION(1, "HDMISCK"),
+ MTK_FUNCTION(6, "TEST_IN29"),
+ MTK_FUNCTION(7, "TEST_OUT29")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(39, "HTPLG"),
+ "H7", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO39"),
+ MTK_FUNCTION(1, "HTPLG"),
+ MTK_FUNCTION(6, "TEST_IN30"),
+ MTK_FUNCTION(7, "TEST_OUT30")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(40, "CEC"),
+ "J9", "mt6397",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO40"),
+ MTK_FUNCTION(1, "CEC"),
+ MTK_FUNCTION(6, "TEST_IN31"),
+ MTK_FUNCTION(7, "TEST_OUT31")
+ ),
+};
+
+#endif /* __PINCTRL_MTK_MT6397_H */
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt8127.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8127.h
new file mode 100644
index 000000000000..212559c147f8
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8127.h
@@ -0,0 +1,1318 @@
+#ifndef __PINCTRL_MTK_MT8127_H
+#define __PINCTRL_MTK_MT8127_H
+
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-mtk-common.h"
+
+static const struct mtk_desc_pin mtk_pins_mt8127[] = {
+ MTK_PIN(
+ PINCTRL_PIN(0, "PWRAP_SPI0_MI"),
+ "P22", "mt8127",
+ MTK_EINT_FUNCTION(0, 22),
+ MTK_FUNCTION(0, "GPIO0"),
+ MTK_FUNCTION(1, "PWRAP_SPIDO"),
+ MTK_FUNCTION(2, "PWRAP_SPIDI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(1, "PWRAP_SPI0_MO"),
+ "M22", "mt8127",
+ MTK_EINT_FUNCTION(0, 23),
+ MTK_FUNCTION(0, "GPIO1"),
+ MTK_FUNCTION(1, "PWRAP_SPIDI"),
+ MTK_FUNCTION(2, "PWRAP_SPIDO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(2, "PWRAP_INT"),
+ "L23", "mt8127",
+ MTK_EINT_FUNCTION(0, 24),
+ MTK_FUNCTION(0, "GPIO2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(3, "PWRAP_SPI0_CK"),
+ "N23", "mt8127",
+ MTK_EINT_FUNCTION(0, 25),
+ MTK_FUNCTION(0, "GPIO3"),
+ MTK_FUNCTION(1, "PWRAP_SPICK_I")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(4, "PWRAP_SPI0_CSN"),
+ "N22", "mt8127",
+ MTK_EINT_FUNCTION(0, 26),
+ MTK_FUNCTION(0, "GPIO4"),
+ MTK_FUNCTION(1, "PWRAP_SPICS_B_I")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(5, "PWRAP_SPI0_CK2"),
+ "L19", "mt8127",
+ MTK_EINT_FUNCTION(0, 27),
+ MTK_FUNCTION(0, "GPIO5"),
+ MTK_FUNCTION(1, "PWRAP_SPICK2_I"),
+ MTK_FUNCTION(2, "ANT_SEL1"),
+ MTK_FUNCTION(3, "VDEC_TEST_CK"),
+ MTK_FUNCTION(7, "DBG_MON_B[0]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(6, "PWRAP_SPI0_CSN2"),
+ "M23", "mt8127",
+ MTK_EINT_FUNCTION(0, 28),
+ MTK_FUNCTION(0, "GPIO6"),
+ MTK_FUNCTION(1, "PWRAP_SPICS2_B_I"),
+ MTK_FUNCTION(2, "ANT_SEL0"),
+ MTK_FUNCTION(3, "MM_TEST_CK"),
+ MTK_FUNCTION(7, "DBG_MON_B[1]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(7, "AUD_CLK_MOSI"),
+ "K23", "mt8127",
+ MTK_EINT_FUNCTION(0, 29),
+ MTK_FUNCTION(0, "GPIO7"),
+ MTK_FUNCTION(1, "AUD_CLK"),
+ MTK_FUNCTION(2, "ADC_CK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(8, "AUD_DAT_MISO"),
+ "K24", "mt8127",
+ MTK_EINT_FUNCTION(0, 30),
+ MTK_FUNCTION(0, "GPIO8"),
+ MTK_FUNCTION(1, "AUD_MISO"),
+ MTK_FUNCTION(2, "ADC_DAT_IN"),
+ MTK_FUNCTION(3, "AUD_MOSI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(9, "AUD_DAT_MOSI"),
+ "K22", "mt8127",
+ MTK_EINT_FUNCTION(0, 31),
+ MTK_FUNCTION(0, "GPIO9"),
+ MTK_FUNCTION(1, "AUD_MOSI"),
+ MTK_FUNCTION(2, "ADC_WS"),
+ MTK_FUNCTION(3, "AUD_MISO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(10, "RTC32K_CK"),
+ "R21", "mt8127",
+ MTK_EINT_FUNCTION(0, 32),
+ MTK_FUNCTION(0, "GPIO10"),
+ MTK_FUNCTION(1, "RTC32K_CK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(11, "WATCHDOG"),
+ "P24", "mt8127",
+ MTK_EINT_FUNCTION(0, 33),
+ MTK_FUNCTION(0, "GPIO11"),
+ MTK_FUNCTION(1, "WATCHDOG")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(12, "SRCLKENA"),
+ "R22", "mt8127",
+ MTK_EINT_FUNCTION(0, 34),
+ MTK_FUNCTION(0, "GPIO12"),
+ MTK_FUNCTION(1, "SRCLKENA")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(13, "SRCLKENAI"),
+ "P23", "mt8127",
+ MTK_EINT_FUNCTION(0, 35),
+ MTK_FUNCTION(0, "GPIO13"),
+ MTK_FUNCTION(1, "SRCLKENAI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(14, "URXD2"),
+ "U19", "mt8127",
+ MTK_EINT_FUNCTION(0, 36),
+ MTK_FUNCTION(0, "GPIO14"),
+ MTK_FUNCTION(1, "URXD2"),
+ MTK_FUNCTION(2, "DPI_D5"),
+ MTK_FUNCTION(3, "UTXD2"),
+ MTK_FUNCTION(5, "SRCCLKENAI2"),
+ MTK_FUNCTION(6, "KROW4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(15, "UTXD2"),
+ "U20", "mt8127",
+ MTK_EINT_FUNCTION(0, 37),
+ MTK_FUNCTION(0, "GPIO15"),
+ MTK_FUNCTION(1, "UTXD2"),
+ MTK_FUNCTION(2, "DPI_HSYNC"),
+ MTK_FUNCTION(3, "URXD2"),
+ MTK_FUNCTION(6, "KROW5")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(16, "URXD3"),
+ "U18", "mt8127",
+ MTK_EINT_FUNCTION(0, 38),
+ MTK_FUNCTION(0, "GPIO16"),
+ MTK_FUNCTION(1, "URXD3"),
+ MTK_FUNCTION(2, "DPI_DE"),
+ MTK_FUNCTION(3, "UTXD3"),
+ MTK_FUNCTION(4, "UCTS2"),
+ MTK_FUNCTION(5, "PWM3"),
+ MTK_FUNCTION(6, "KROW6")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(17, "UTXD3"),
+ "R18", "mt8127",
+ MTK_EINT_FUNCTION(0, 39),
+ MTK_FUNCTION(0, "GPIO17"),
+ MTK_FUNCTION(1, "UTXD3"),
+ MTK_FUNCTION(2, "DPI_VSYNC"),
+ MTK_FUNCTION(3, "URXD3"),
+ MTK_FUNCTION(4, "URTS2"),
+ MTK_FUNCTION(5, "PWM4"),
+ MTK_FUNCTION(6, "KROW7")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(18, "PCM_CLK"),
+ "U22", "mt8127",
+ MTK_EINT_FUNCTION(0, 40),
+ MTK_FUNCTION(0, "GPIO18"),
+ MTK_FUNCTION(1, "PCM_CLK0"),
+ MTK_FUNCTION(2, "DPI_D4"),
+ MTK_FUNCTION(3, "I2SIN1_BCK0"),
+ MTK_FUNCTION(4, "I2SOUT_BCK"),
+ MTK_FUNCTION(5, "CONN_DSP_JCK"),
+ MTK_FUNCTION(6, "IR"),
+ MTK_FUNCTION(7, "DBG_MON_A[0]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(19, "PCM_SYNC"),
+ "U23", "mt8127",
+ MTK_EINT_FUNCTION(0, 41),
+ MTK_FUNCTION(0, "GPIO19"),
+ MTK_FUNCTION(1, "PCM_SYNC"),
+ MTK_FUNCTION(2, "DPI_D3"),
+ MTK_FUNCTION(3, "I2SIN1_LRCK"),
+ MTK_FUNCTION(4, "I2SOUT_LRCK"),
+ MTK_FUNCTION(5, "CONN_DSP_JINTP"),
+ MTK_FUNCTION(6, "EXT_COL"),
+ MTK_FUNCTION(7, "DBG_MON_A[1]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(20, "PCM_RX"),
+ "V22", "mt8127",
+ MTK_EINT_FUNCTION(0, 42),
+ MTK_FUNCTION(0, "GPIO20"),
+ MTK_FUNCTION(1, "PCM_RX"),
+ MTK_FUNCTION(2, "DPI_D1"),
+ MTK_FUNCTION(3, "I2SIN1_DATA_IN"),
+ MTK_FUNCTION(4, "PCM_TX"),
+ MTK_FUNCTION(5, "CONN_DSP_JDI"),
+ MTK_FUNCTION(6, "EXT_MDIO"),
+ MTK_FUNCTION(7, "DBG_MON_A[2]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(21, "PCM_TX"),
+ "U21", "mt8127",
+ MTK_EINT_FUNCTION(0, 43),
+ MTK_FUNCTION(0, "GPIO21"),
+ MTK_FUNCTION(1, "PCM_TX"),
+ MTK_FUNCTION(2, "DPI_D2"),
+ MTK_FUNCTION(3, "I2SOUT_DATA_OUT"),
+ MTK_FUNCTION(4, "PCM_RX"),
+ MTK_FUNCTION(5, "CONN_DSP_JMS"),
+ MTK_FUNCTION(6, "EXT_MDC"),
+ MTK_FUNCTION(7, "DBG_MON_A[3]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(22, "EINT0"),
+ "AB19", "mt8127",
+ MTK_EINT_FUNCTION(0, 0),
+ MTK_FUNCTION(0, "GPIO22"),
+ MTK_FUNCTION(1, "PWM1"),
+ MTK_FUNCTION(2, "DPI_CK"),
+ MTK_FUNCTION(4, "EXT_TXD0"),
+ MTK_FUNCTION(5, "CONN_DSP_JDO"),
+ MTK_FUNCTION(7, "DBG_MON_A[4]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(23, "EINT1"),
+ "AA21", "mt8127",
+ MTK_EINT_FUNCTION(0, 1),
+ MTK_FUNCTION(0, "GPIO23"),
+ MTK_FUNCTION(1, "PWM2"),
+ MTK_FUNCTION(2, "DPI_D12"),
+ MTK_FUNCTION(4, "EXT_TXD1"),
+ MTK_FUNCTION(5, "CONN_MCU_TDO"),
+ MTK_FUNCTION(7, "DBG_MON_A[5]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(24, "EINT2"),
+ "AA19", "mt8127",
+ MTK_EINT_FUNCTION(0, 2),
+ MTK_FUNCTION(0, "GPIO24"),
+ MTK_FUNCTION(1, "CLKM0"),
+ MTK_FUNCTION(2, "DPI_D13"),
+ MTK_FUNCTION(4, "EXT_TXD2"),
+ MTK_FUNCTION(5, "CONN_MCU_DBGACK_N"),
+ MTK_FUNCTION(6, "KCOL4"),
+ MTK_FUNCTION(7, "DBG_MON_A[6]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(25, "EINT3"),
+ "Y19", "mt8127",
+ MTK_EINT_FUNCTION(0, 3),
+ MTK_FUNCTION(0, "GPIO25"),
+ MTK_FUNCTION(1, "CLKM1"),
+ MTK_FUNCTION(2, "DPI_D14"),
+ MTK_FUNCTION(3, "SPI_MI"),
+ MTK_FUNCTION(4, "EXT_TXD3"),
+ MTK_FUNCTION(5, "CONN_MCU_DBGI_N"),
+ MTK_FUNCTION(6, "KCOL5"),
+ MTK_FUNCTION(7, "DBG_MON_A[7]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(26, "EINT4"),
+ "V21", "mt8127",
+ MTK_EINT_FUNCTION(0, 4),
+ MTK_FUNCTION(0, "GPIO26"),
+ MTK_FUNCTION(1, "CLKM2"),
+ MTK_FUNCTION(2, "DPI_D15"),
+ MTK_FUNCTION(3, "SPI_MO"),
+ MTK_FUNCTION(4, "EXT_TXC"),
+ MTK_FUNCTION(5, "CONN_MCU_TCK0"),
+ MTK_FUNCTION(6, "CONN_MCU_AICE_JCKC"),
+ MTK_FUNCTION(7, "DBG_MON_A[8]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(27, "EINT5"),
+ "AB22", "mt8127",
+ MTK_EINT_FUNCTION(0, 5),
+ MTK_FUNCTION(0, "GPIO27"),
+ MTK_FUNCTION(1, "UCTS2"),
+ MTK_FUNCTION(2, "DPI_D16"),
+ MTK_FUNCTION(3, "SPI_CS"),
+ MTK_FUNCTION(4, "EXT_RXER"),
+ MTK_FUNCTION(5, "CONN_MCU_TDI"),
+ MTK_FUNCTION(6, "KCOL6"),
+ MTK_FUNCTION(7, "DBG_MON_A[9]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(28, "EINT6"),
+ "AA23", "mt8127",
+ MTK_EINT_FUNCTION(0, 6),
+ MTK_FUNCTION(0, "GPIO28"),
+ MTK_FUNCTION(1, "URTS2"),
+ MTK_FUNCTION(2, "DPI_D17"),
+ MTK_FUNCTION(3, "SPI_CK"),
+ MTK_FUNCTION(4, "EXT_RXC"),
+ MTK_FUNCTION(5, "CONN_MCU_TRST_B"),
+ MTK_FUNCTION(6, "KCOL7"),
+ MTK_FUNCTION(7, "DBG_MON_A[10]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(29, "EINT7"),
+ "Y23", "mt8127",
+ MTK_EINT_FUNCTION(0, 7),
+ MTK_FUNCTION(0, "GPIO29"),
+ MTK_FUNCTION(1, "UCTS3"),
+ MTK_FUNCTION(2, "DPI_D6"),
+ MTK_FUNCTION(3, "SDA1"),
+ MTK_FUNCTION(4, "EXT_RXDV"),
+ MTK_FUNCTION(5, "CONN_MCU_TMS"),
+ MTK_FUNCTION(6, "CONN_MCU_AICE_JMSC"),
+ MTK_FUNCTION(7, "DBG_MON_A[11]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(30, "EINT8"),
+ "Y24", "mt8127",
+ MTK_EINT_FUNCTION(0, 8),
+ MTK_FUNCTION(0, "GPIO30"),
+ MTK_FUNCTION(1, "URTS3"),
+ MTK_FUNCTION(2, "CLKM3"),
+ MTK_FUNCTION(3, "SCL1"),
+ MTK_FUNCTION(4, "EXT_RXD0"),
+ MTK_FUNCTION(5, "ANT_SEL0"),
+ MTK_FUNCTION(6, "DPI_D7"),
+ MTK_FUNCTION(7, "DBG_MON_B[2]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(31, "EINT9"),
+ "W23", "mt8127",
+ MTK_EINT_FUNCTION(0, 9),
+ MTK_FUNCTION(0, "GPIO31"),
+ MTK_FUNCTION(1, "CLKM4"),
+ MTK_FUNCTION(2, "SDA2"),
+ MTK_FUNCTION(3, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(4, "EXT_RXD1"),
+ MTK_FUNCTION(5, "ANT_SEL1"),
+ MTK_FUNCTION(6, "DPI_D8"),
+ MTK_FUNCTION(7, "DBG_MON_B[3]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(32, "EINT10"),
+ "W24", "mt8127",
+ MTK_EINT_FUNCTION(0, 10),
+ MTK_FUNCTION(0, "GPIO32"),
+ MTK_FUNCTION(1, "CLKM5"),
+ MTK_FUNCTION(2, "SCL2"),
+ MTK_FUNCTION(3, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(4, "EXT_RXD2"),
+ MTK_FUNCTION(5, "ANT_SEL2"),
+ MTK_FUNCTION(6, "DPI_D9"),
+ MTK_FUNCTION(7, "DBG_MON_B[4]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(33, "KPROW0"),
+ "AB24", "mt8127",
+ MTK_EINT_FUNCTION(0, 44),
+ MTK_FUNCTION(0, "GPIO33"),
+ MTK_FUNCTION(1, "KROW0"),
+ MTK_FUNCTION(4, "IMG_TEST_CK"),
+ MTK_FUNCTION(7, "DBG_MON_A[12]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(34, "KPROW1"),
+ "AC24", "mt8127",
+ MTK_EINT_FUNCTION(0, 45),
+ MTK_FUNCTION(0, "GPIO34"),
+ MTK_FUNCTION(1, "KROW1"),
+ MTK_FUNCTION(2, "IDDIG"),
+ MTK_FUNCTION(3, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(4, "MFG_TEST_CK"),
+ MTK_FUNCTION(7, "DBG_MON_B[5]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(35, "KPROW2"),
+ "AD24", "mt8127",
+ MTK_EINT_FUNCTION(0, 46),
+ MTK_FUNCTION(0, "GPIO35"),
+ MTK_FUNCTION(1, "KROW2"),
+ MTK_FUNCTION(2, "DRV_VBUS"),
+ MTK_FUNCTION(3, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(4, "CONN_TEST_CK"),
+ MTK_FUNCTION(7, "DBG_MON_B[6]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(36, "KPCOL0"),
+ "AB23", "mt8127",
+ MTK_EINT_FUNCTION(0, 47),
+ MTK_FUNCTION(0, "GPIO36"),
+ MTK_FUNCTION(1, "KCOL0"),
+ MTK_FUNCTION(7, "DBG_MON_A[13]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(37, "KPCOL1"),
+ "AC22", "mt8127",
+ MTK_EINT_FUNCTION(0, 48),
+ MTK_FUNCTION(0, "GPIO37"),
+ MTK_FUNCTION(1, "KCOL1"),
+ MTK_FUNCTION(7, "DBG_MON_B[7]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(38, "KPCOL2"),
+ "AC23", "mt8127",
+ MTK_EINT_FUNCTION(0, 49),
+ MTK_FUNCTION(0, "GPIO38"),
+ MTK_FUNCTION(1, "KCOL2"),
+ MTK_FUNCTION(2, "IDDIG"),
+ MTK_FUNCTION(3, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(7, "DBG_MON_B[8]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(39, "JTMS"),
+ "V18", "mt8127",
+ MTK_EINT_FUNCTION(0, 50),
+ MTK_FUNCTION(0, "GPIO39"),
+ MTK_FUNCTION(1, "JTMS"),
+ MTK_FUNCTION(2, "CONN_MCU_TMS"),
+ MTK_FUNCTION(3, "CONN_MCU_AICE_JMSC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(40, "JTCK"),
+ "AA18", "mt8127",
+ MTK_EINT_FUNCTION(0, 51),
+ MTK_FUNCTION(0, "GPIO40"),
+ MTK_FUNCTION(1, "JTCK"),
+ MTK_FUNCTION(2, "CONN_MCU_TCK1"),
+ MTK_FUNCTION(3, "CONN_MCU_AICE_JCKC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(41, "JTDI"),
+ "W18", "mt8127",
+ MTK_EINT_FUNCTION(0, 52),
+ MTK_FUNCTION(0, "GPIO41"),
+ MTK_FUNCTION(1, "JTDI"),
+ MTK_FUNCTION(2, "CONN_MCU_TDI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(42, "JTDO"),
+ "Y18", "mt8127",
+ MTK_EINT_FUNCTION(0, 53),
+ MTK_FUNCTION(0, "GPIO42"),
+ MTK_FUNCTION(1, "JTDO"),
+ MTK_FUNCTION(2, "CONN_MCU_TDO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(43, "EINT11"),
+ "W22", "mt8127",
+ MTK_EINT_FUNCTION(0, 11),
+ MTK_FUNCTION(0, "GPIO43"),
+ MTK_FUNCTION(1, "CLKM4"),
+ MTK_FUNCTION(2, "PWM2"),
+ MTK_FUNCTION(3, "KROW3"),
+ MTK_FUNCTION(4, "ANT_SEL3"),
+ MTK_FUNCTION(5, "DPI_D10"),
+ MTK_FUNCTION(6, "EXT_RXD3"),
+ MTK_FUNCTION(7, "DBG_MON_B[9]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(44, "EINT12"),
+ "V23", "mt8127",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO44"),
+ MTK_FUNCTION(1, "CLKM5"),
+ MTK_FUNCTION(2, "PWM0"),
+ MTK_FUNCTION(3, "KCOL3"),
+ MTK_FUNCTION(4, "ANT_SEL4"),
+ MTK_FUNCTION(5, "DPI_D11"),
+ MTK_FUNCTION(6, "EXT_TXEN"),
+ MTK_FUNCTION(7, "DBG_MON_B[10]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(45, "EINT13"),
+ "Y21", "mt8127",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO45"),
+ MTK_FUNCTION(4, "ANT_SEL5"),
+ MTK_FUNCTION(5, "DPI_D0"),
+ MTK_FUNCTION(6, "SPDIF"),
+ MTK_FUNCTION(7, "DBG_MON_B[11]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(46, "EINT14"),
+ "F23", "mt8127",
+ MTK_EINT_FUNCTION(0, 14),
+ MTK_FUNCTION(0, "GPIO46"),
+ MTK_FUNCTION(2, "DAC_DAT_OUT"),
+ MTK_FUNCTION(4, "ANT_SEL1"),
+ MTK_FUNCTION(5, "CONN_MCU_DBGACK_N"),
+ MTK_FUNCTION(6, "NCLE"),
+ MTK_FUNCTION(7, "DBG_MON_A[14]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(47, "EINT15"),
+ "G23", "mt8127",
+ MTK_EINT_FUNCTION(0, 15),
+ MTK_FUNCTION(0, "GPIO47"),
+ MTK_FUNCTION(2, "DAC_WS"),
+ MTK_FUNCTION(4, "ANT_SEL2"),
+ MTK_FUNCTION(5, "CONN_MCU_DBGI_N"),
+ MTK_FUNCTION(6, "NCEB1"),
+ MTK_FUNCTION(7, "DBG_MON_A[15]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(48, "EINT16"),
+ "H23", "mt8127",
+ MTK_EINT_FUNCTION(0, 16),
+ MTK_FUNCTION(0, "GPIO48"),
+ MTK_FUNCTION(2, "DAC_CK"),
+ MTK_FUNCTION(4, "ANT_SEL3"),
+ MTK_FUNCTION(5, "CONN_MCU_TRST_B"),
+ MTK_FUNCTION(6, "NCEB0"),
+ MTK_FUNCTION(7, "DBG_MON_A[16]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(49, "EINT17"),
+ "J22", "mt8127",
+ MTK_EINT_FUNCTION(0, 17),
+ MTK_FUNCTION(0, "GPIO49"),
+ MTK_FUNCTION(1, "UCTS0"),
+ MTK_FUNCTION(3, "CLKM0"),
+ MTK_FUNCTION(4, "IDDIG"),
+ MTK_FUNCTION(5, "ANT_SEL4"),
+ MTK_FUNCTION(6, "NREB"),
+ MTK_FUNCTION(7, "DBG_MON_A[17]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(50, "EINT18"),
+ "AD20", "mt8127",
+ MTK_EINT_FUNCTION(0, 18),
+ MTK_FUNCTION(0, "GPIO50"),
+ MTK_FUNCTION(1, "URTS0"),
+ MTK_FUNCTION(2, "CLKM3"),
+ MTK_FUNCTION(3, "I2SOUT_LRCK"),
+ MTK_FUNCTION(4, "DRV_VBUS"),
+ MTK_FUNCTION(5, "ANT_SEL3"),
+ MTK_FUNCTION(6, "ADC_CK"),
+ MTK_FUNCTION(7, "DBG_MON_B[12]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(51, "EINT19"),
+ "AC21", "mt8127",
+ MTK_EINT_FUNCTION(0, 19),
+ MTK_FUNCTION(0, "GPIO51"),
+ MTK_FUNCTION(1, "UCTS1"),
+ MTK_FUNCTION(3, "I2SOUT_BCK"),
+ MTK_FUNCTION(4, "CLKM1"),
+ MTK_FUNCTION(5, "ANT_SEL4"),
+ MTK_FUNCTION(6, "ADC_DAT_IN"),
+ MTK_FUNCTION(7, "DBG_MON_B[13]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(52, "EINT20"),
+ "V20", "mt8127",
+ MTK_EINT_FUNCTION(0, 20),
+ MTK_FUNCTION(0, "GPIO52"),
+ MTK_FUNCTION(1, "URTS1"),
+ MTK_FUNCTION(2, "PCM_TX"),
+ MTK_FUNCTION(3, "I2SOUT_DATA_OUT"),
+ MTK_FUNCTION(4, "CLKM2"),
+ MTK_FUNCTION(5, "ANT_SEL5"),
+ MTK_FUNCTION(6, "ADC_WS"),
+ MTK_FUNCTION(7, "DBG_MON_B[14]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(53, "SPI_CS"),
+ "AD19", "mt8127",
+ MTK_EINT_FUNCTION(0, 54),
+ MTK_FUNCTION(0, "GPIO53"),
+ MTK_FUNCTION(1, "SPI_CS"),
+ MTK_FUNCTION(3, "I2SIN1_DATA_IN"),
+ MTK_FUNCTION(4, "ADC_CK"),
+ MTK_FUNCTION(7, "DBG_MON_B[15]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(54, "SPI_CK"),
+ "AC18", "mt8127",
+ MTK_EINT_FUNCTION(0, 55),
+ MTK_FUNCTION(0, "GPIO54"),
+ MTK_FUNCTION(1, "SPI_CK"),
+ MTK_FUNCTION(3, "I2SIN1_LRCK"),
+ MTK_FUNCTION(4, "ADC_DAT_IN"),
+ MTK_FUNCTION(7, "DBG_MON_B[16]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(55, "SPI_MI"),
+ "AC19", "mt8127",
+ MTK_EINT_FUNCTION(0, 56),
+ MTK_FUNCTION(0, "GPIO55"),
+ MTK_FUNCTION(1, "SPI_MI"),
+ MTK_FUNCTION(2, "SPI_MO"),
+ MTK_FUNCTION(3, "I2SIN1_BCK1"),
+ MTK_FUNCTION(4, "ADC_WS"),
+ MTK_FUNCTION(7, "DBG_MON_B[17]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(56, "SPI_MO"),
+ "AD18", "mt8127",
+ MTK_EINT_FUNCTION(0, 57),
+ MTK_FUNCTION(0, "GPIO56"),
+ MTK_FUNCTION(1, "SPI_MO"),
+ MTK_FUNCTION(2, "SPI_MI"),
+ MTK_FUNCTION(7, "DBG_MON_B[18]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(57, "SDA1"),
+ "AE23", "mt8127",
+ MTK_EINT_FUNCTION(0, 58),
+ MTK_FUNCTION(0, "GPIO57"),
+ MTK_FUNCTION(1, "SDA1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(58, "SCL1"),
+ "AD23", "mt8127",
+ MTK_EINT_FUNCTION(0, 59),
+ MTK_FUNCTION(0, "GPIO58"),
+ MTK_FUNCTION(1, "SCL1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(59, "DISP_PWM"),
+ "AC20", "mt8127",
+ MTK_EINT_FUNCTION(0, 60),
+ MTK_FUNCTION(0, "GPIO59"),
+ MTK_FUNCTION(1, "DISP_PWM"),
+ MTK_FUNCTION(2, "PWM1"),
+ MTK_FUNCTION(7, "DBG_MON_A[18]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(60, "WB_RSTB"),
+ "AD7", "mt8127",
+ MTK_EINT_FUNCTION(0, 61),
+ MTK_FUNCTION(0, "GPIO60"),
+ MTK_FUNCTION(1, "WB_RSTB"),
+ MTK_FUNCTION(7, "DBG_MON_A[19]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(61, "F2W_DATA"),
+ "Y10", "mt8127",
+ MTK_EINT_FUNCTION(0, 62),
+ MTK_FUNCTION(0, "GPIO61"),
+ MTK_FUNCTION(1, "F2W_DATA"),
+ MTK_FUNCTION(7, "DBG_MON_A[20]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(62, "F2W_CLK"),
+ "W10", "mt8127",
+ MTK_EINT_FUNCTION(0, 63),
+ MTK_FUNCTION(0, "GPIO62"),
+ MTK_FUNCTION(1, "F2W_CK"),
+ MTK_FUNCTION(7, "DBG_MON_A[21]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(63, "WB_SCLK"),
+ "AB7", "mt8127",
+ MTK_EINT_FUNCTION(0, 64),
+ MTK_FUNCTION(0, "GPIO63"),
+ MTK_FUNCTION(1, "WB_SCLK"),
+ MTK_FUNCTION(7, "DBG_MON_A[22]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(64, "WB_SDATA"),
+ "AA7", "mt8127",
+ MTK_EINT_FUNCTION(0, 65),
+ MTK_FUNCTION(0, "GPIO64"),
+ MTK_FUNCTION(1, "WB_SDATA"),
+ MTK_FUNCTION(7, "DBG_MON_A[23]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(65, "WB_SEN"),
+ "Y7", "mt8127",
+ MTK_EINT_FUNCTION(0, 66),
+ MTK_FUNCTION(0, "GPIO65"),
+ MTK_FUNCTION(1, "WB_SEN"),
+ MTK_FUNCTION(7, "DBG_MON_A[24]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(66, "WB_CRTL0"),
+ "AA1", "mt8127",
+ MTK_EINT_FUNCTION(0, 67),
+ MTK_FUNCTION(0, "GPIO66"),
+ MTK_FUNCTION(1, "WB_CRTL0"),
+ MTK_FUNCTION(2, "DFD_NTRST_XI"),
+ MTK_FUNCTION(7, "DBG_MON_A[25]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(67, "WB_CRTL1"),
+ "AA2", "mt8127",
+ MTK_EINT_FUNCTION(0, 68),
+ MTK_FUNCTION(0, "GPIO67"),
+ MTK_FUNCTION(1, "WB_CRTL1"),
+ MTK_FUNCTION(2, "DFD_TMS_XI"),
+ MTK_FUNCTION(7, "DBG_MON_A[26]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(68, "WB_CRTL2"),
+ "Y1", "mt8127",
+ MTK_EINT_FUNCTION(0, 69),
+ MTK_FUNCTION(0, "GPIO68"),
+ MTK_FUNCTION(1, "WB_CRTL2"),
+ MTK_FUNCTION(2, "DFD_TCK_XI"),
+ MTK_FUNCTION(7, "DBG_MON_A[27]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(69, "WB_CRTL3"),
+ "Y2", "mt8127",
+ MTK_EINT_FUNCTION(0, 70),
+ MTK_FUNCTION(0, "GPIO69"),
+ MTK_FUNCTION(1, "WB_CRTL3"),
+ MTK_FUNCTION(2, "DFD_TDI_XI"),
+ MTK_FUNCTION(7, "DBG_MON_A[28]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(70, "WB_CRTL4"),
+ "Y3", "mt8127",
+ MTK_EINT_FUNCTION(0, 71),
+ MTK_FUNCTION(0, "GPIO70"),
+ MTK_FUNCTION(1, "WB_CRTL4"),
+ MTK_FUNCTION(2, "DFD_TDO"),
+ MTK_FUNCTION(7, "DBG_MON_A[29]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(71, "WB_CRTL5"),
+ "Y4", "mt8127",
+ MTK_EINT_FUNCTION(0, 72),
+ MTK_FUNCTION(0, "GPIO71"),
+ MTK_FUNCTION(1, "WB_CRTL5"),
+ MTK_FUNCTION(7, "DBG_MON_A[30]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(72, "I2S_DATA_IN"),
+ "K21", "mt8127",
+ MTK_EINT_FUNCTION(0, 73),
+ MTK_FUNCTION(0, "GPIO72"),
+ MTK_FUNCTION(1, "I2SIN1_DATA_IN"),
+ MTK_FUNCTION(2, "PCM_RX"),
+ MTK_FUNCTION(3, "I2SOUT_DATA_OUT"),
+ MTK_FUNCTION(4, "DAC_DAT_OUT"),
+ MTK_FUNCTION(5, "PWM0"),
+ MTK_FUNCTION(6, "ADC_CK"),
+ MTK_FUNCTION(7, "DBG_MON_B[19]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(73, "I2S_LRCK"),
+ "L21", "mt8127",
+ MTK_EINT_FUNCTION(0, 74),
+ MTK_FUNCTION(0, "GPIO73"),
+ MTK_FUNCTION(1, "I2SIN1_LRCK"),
+ MTK_FUNCTION(2, "PCM_SYNC"),
+ MTK_FUNCTION(3, "I2SOUT_LRCK"),
+ MTK_FUNCTION(4, "DAC_WS"),
+ MTK_FUNCTION(5, "PWM3"),
+ MTK_FUNCTION(6, "ADC_DAT_IN"),
+ MTK_FUNCTION(7, "DBG_MON_B[20]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(74, "I2S_BCK"),
+ "L20", "mt8127",
+ MTK_EINT_FUNCTION(0, 75),
+ MTK_FUNCTION(0, "GPIO74"),
+ MTK_FUNCTION(1, "I2SIN1_BCK2"),
+ MTK_FUNCTION(2, "PCM_CLK1"),
+ MTK_FUNCTION(3, "I2SOUT_BCK"),
+ MTK_FUNCTION(4, "DAC_CK"),
+ MTK_FUNCTION(5, "PWM4"),
+ MTK_FUNCTION(6, "ADC_WS"),
+ MTK_FUNCTION(7, "DBG_MON_B[21]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(75, "SDA0"),
+ "W3", "mt8127",
+ MTK_EINT_FUNCTION(0, 76),
+ MTK_FUNCTION(0, "GPIO75"),
+ MTK_FUNCTION(1, "SDA0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(76, "SCL0"),
+ "W4", "mt8127",
+ MTK_EINT_FUNCTION(0, 77),
+ MTK_FUNCTION(0, "GPIO76"),
+ MTK_FUNCTION(1, "SCL0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(77, "SDA2"),
+ "K19", "mt8127",
+ MTK_EINT_FUNCTION(0, 78),
+ MTK_FUNCTION(0, "GPIO77"),
+ MTK_FUNCTION(1, "SDA2"),
+ MTK_FUNCTION(2, "PWM1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(78, "SCL2"),
+ "K20", "mt8127",
+ MTK_EINT_FUNCTION(0, 79),
+ MTK_FUNCTION(0, "GPIO78"),
+ MTK_FUNCTION(1, "SCL2"),
+ MTK_FUNCTION(2, "PWM2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(79, "URXD0"),
+ "K18", "mt8127",
+ MTK_EINT_FUNCTION(0, 80),
+ MTK_FUNCTION(0, "GPIO79"),
+ MTK_FUNCTION(1, "URXD0"),
+ MTK_FUNCTION(2, "UTXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(80, "UTXD0"),
+ "K17", "mt8127",
+ MTK_EINT_FUNCTION(0, 81),
+ MTK_FUNCTION(0, "GPIO80"),
+ MTK_FUNCTION(1, "UTXD0"),
+ MTK_FUNCTION(2, "URXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(81, "URXD1"),
+ "L17", "mt8127",
+ MTK_EINT_FUNCTION(0, 82),
+ MTK_FUNCTION(0, "GPIO81"),
+ MTK_FUNCTION(1, "URXD1"),
+ MTK_FUNCTION(2, "UTXD1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(82, "UTXD1"),
+ "L18", "mt8127",
+ MTK_EINT_FUNCTION(0, 83),
+ MTK_FUNCTION(0, "GPIO82"),
+ MTK_FUNCTION(1, "UTXD1"),
+ MTK_FUNCTION(2, "URXD1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(83, "LCM_RST"),
+ "W5", "mt8127",
+ MTK_EINT_FUNCTION(0, 84),
+ MTK_FUNCTION(0, "GPIO83"),
+ MTK_FUNCTION(1, "LCM_RST"),
+ MTK_FUNCTION(2, "VDAC_CK_XI"),
+ MTK_FUNCTION(7, "DBG_MON_A[31]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(84, "DSI_TE"),
+ "W6", "mt8127",
+ MTK_EINT_FUNCTION(0, 85),
+ MTK_FUNCTION(0, "GPIO84"),
+ MTK_FUNCTION(1, "DSI_TE"),
+ MTK_FUNCTION(7, "DBG_MON_A[32]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(85, "MSDC2_CMD"),
+ "U7", "mt8127",
+ MTK_EINT_FUNCTION(0, 86),
+ MTK_FUNCTION(0, "GPIO85"),
+ MTK_FUNCTION(1, "MSDC2_CMD"),
+ MTK_FUNCTION(2, "ANT_SEL0"),
+ MTK_FUNCTION(3, "SDA1"),
+ MTK_FUNCTION(6, "I2SOUT_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_B[22]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(86, "MSDC2_CLK"),
+ "T8", "mt8127",
+ MTK_EINT_FUNCTION(0, 87),
+ MTK_FUNCTION(0, "GPIO86"),
+ MTK_FUNCTION(1, "MSDC2_CLK"),
+ MTK_FUNCTION(2, "ANT_SEL1"),
+ MTK_FUNCTION(3, "SCL1"),
+ MTK_FUNCTION(6, "I2SOUT_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_B[23]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(87, "MSDC2_DAT0"),
+ "V3", "mt8127",
+ MTK_EINT_FUNCTION(0, 88),
+ MTK_FUNCTION(0, "GPIO87"),
+ MTK_FUNCTION(1, "MSDC2_DAT0"),
+ MTK_FUNCTION(2, "ANT_SEL2"),
+ MTK_FUNCTION(5, "UTXD0"),
+ MTK_FUNCTION(6, "I2SOUT_DATA_OUT"),
+ MTK_FUNCTION(7, "DBG_MON_B[24]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(88, "MSDC2_DAT1"),
+ "V4", "mt8127",
+ MTK_EINT_FUNCTION(0, 89),
+ MTK_FUNCTION(0, "GPIO88"),
+ MTK_FUNCTION(1, "MSDC2_DAT1"),
+ MTK_FUNCTION(2, "ANT_SEL3"),
+ MTK_FUNCTION(3, "PWM0"),
+ MTK_FUNCTION(5, "URXD0"),
+ MTK_FUNCTION(6, "PWM1"),
+ MTK_FUNCTION(7, "DBG_MON_B[25]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(89, "MSDC2_DAT2"),
+ "U5", "mt8127",
+ MTK_EINT_FUNCTION(0, 90),
+ MTK_FUNCTION(0, "GPIO89"),
+ MTK_FUNCTION(1, "MSDC2_DAT2"),
+ MTK_FUNCTION(2, "ANT_SEL4"),
+ MTK_FUNCTION(3, "SDA2"),
+ MTK_FUNCTION(5, "UTXD1"),
+ MTK_FUNCTION(6, "PWM2"),
+ MTK_FUNCTION(7, "DBG_MON_B[26]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(90, "MSDC2_DAT3"),
+ "U6", "mt8127",
+ MTK_EINT_FUNCTION(0, 91),
+ MTK_FUNCTION(0, "GPIO90"),
+ MTK_FUNCTION(1, "MSDC2_DAT3"),
+ MTK_FUNCTION(2, "ANT_SEL5"),
+ MTK_FUNCTION(3, "SCL2"),
+ MTK_FUNCTION(4, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(5, "URXD1"),
+ MTK_FUNCTION(6, "PWM3"),
+ MTK_FUNCTION(7, "DBG_MON_B[27]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(91, "TDN3"),
+ "U2", "mt8127",
+ MTK_EINT_FUNCTION(0, 92),
+ MTK_FUNCTION(0, "GPI91"),
+ MTK_FUNCTION(1, "TDN3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(92, "TDP3"),
+ "U1", "mt8127",
+ MTK_EINT_FUNCTION(0, 93),
+ MTK_FUNCTION(0, "GPI92"),
+ MTK_FUNCTION(1, "TDP3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(93, "TDN2"),
+ "T2", "mt8127",
+ MTK_EINT_FUNCTION(0, 94),
+ MTK_FUNCTION(0, "GPI93"),
+ MTK_FUNCTION(1, "TDN2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(94, "TDP2"),
+ "T1", "mt8127",
+ MTK_EINT_FUNCTION(0, 95),
+ MTK_FUNCTION(0, "GPI94"),
+ MTK_FUNCTION(1, "TDP2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(95, "TCN"),
+ "R5", "mt8127",
+ MTK_EINT_FUNCTION(0, 96),
+ MTK_FUNCTION(0, "GPI95"),
+ MTK_FUNCTION(1, "TCN")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(96, "TCP"),
+ "R4", "mt8127",
+ MTK_EINT_FUNCTION(0, 97),
+ MTK_FUNCTION(0, "GPI96"),
+ MTK_FUNCTION(1, "TCP")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(97, "TDN1"),
+ "R3", "mt8127",
+ MTK_EINT_FUNCTION(0, 98),
+ MTK_FUNCTION(0, "GPI97"),
+ MTK_FUNCTION(1, "TDN1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(98, "TDP1"),
+ "R2", "mt8127",
+ MTK_EINT_FUNCTION(0, 99),
+ MTK_FUNCTION(0, "GPI98"),
+ MTK_FUNCTION(1, "TDP1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(99, "TDN0"),
+ "P3", "mt8127",
+ MTK_EINT_FUNCTION(0, 100),
+ MTK_FUNCTION(0, "GPI99"),
+ MTK_FUNCTION(1, "TDN0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(100, "TDP0"),
+ "P2", "mt8127",
+ MTK_EINT_FUNCTION(0, 101),
+ MTK_FUNCTION(0, "GPI100"),
+ MTK_FUNCTION(1, "TDP0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(101, "RDN0"),
+ "K1", "mt8127",
+ MTK_EINT_FUNCTION(0, 102),
+ MTK_FUNCTION(0, "GPI101"),
+ MTK_FUNCTION(1, "RDN0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(102, "RDP0"),
+ "K2", "mt8127",
+ MTK_EINT_FUNCTION(0, 103),
+ MTK_FUNCTION(0, "GPI102"),
+ MTK_FUNCTION(1, "RDP0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(103, "RDN1"),
+ "L2", "mt8127",
+ MTK_EINT_FUNCTION(0, 104),
+ MTK_FUNCTION(0, "GPI103"),
+ MTK_FUNCTION(1, "RDN1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(104, "RDP1"),
+ "L3", "mt8127",
+ MTK_EINT_FUNCTION(0, 105),
+ MTK_FUNCTION(0, "GPI104"),
+ MTK_FUNCTION(1, "RDP1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(105, "RCN"),
+ "M4", "mt8127",
+ MTK_EINT_FUNCTION(0, 106),
+ MTK_FUNCTION(0, "GPI105"),
+ MTK_FUNCTION(1, "RCN")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(106, "RCP"),
+ "M5", "mt8127",
+ MTK_EINT_FUNCTION(0, 107),
+ MTK_FUNCTION(0, "GPI106"),
+ MTK_FUNCTION(1, "RCP")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(107, "RDN2"),
+ "M2", "mt8127",
+ MTK_EINT_FUNCTION(0, 108),
+ MTK_FUNCTION(0, "GPI107"),
+ MTK_FUNCTION(1, "RDN2"),
+ MTK_FUNCTION(2, "CMDAT8")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(108, "RDP2"),
+ "M3", "mt8127",
+ MTK_EINT_FUNCTION(0, 109),
+ MTK_FUNCTION(0, "GPI108"),
+ MTK_FUNCTION(1, "RDP2"),
+ MTK_FUNCTION(2, "CMDAT9")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(109, "RDN3"),
+ "N2", "mt8127",
+ MTK_EINT_FUNCTION(0, 110),
+ MTK_FUNCTION(0, "GPI109"),
+ MTK_FUNCTION(1, "RDN3"),
+ MTK_FUNCTION(2, "CMDAT4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(110, "RDP3"),
+ "N3", "mt8127",
+ MTK_EINT_FUNCTION(0, 111),
+ MTK_FUNCTION(0, "GPI110"),
+ MTK_FUNCTION(1, "RDP3"),
+ MTK_FUNCTION(2, "CMDAT5")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(111, "RCN_A"),
+ "J5", "mt8127",
+ MTK_EINT_FUNCTION(0, 112),
+ MTK_FUNCTION(0, "GPI111"),
+ MTK_FUNCTION(1, "RCN_A"),
+ MTK_FUNCTION(2, "CMDAT6")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(112, "RCP_A"),
+ "J4", "mt8127",
+ MTK_EINT_FUNCTION(0, 113),
+ MTK_FUNCTION(0, "GPI112"),
+ MTK_FUNCTION(1, "RCP_A"),
+ MTK_FUNCTION(2, "CMDAT7")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(113, "RDN1_A"),
+ "J2", "mt8127",
+ MTK_EINT_FUNCTION(0, 114),
+ MTK_FUNCTION(0, "GPI113"),
+ MTK_FUNCTION(1, "RDN1_A"),
+ MTK_FUNCTION(2, "CMDAT2"),
+ MTK_FUNCTION(3, "CMCSD2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(114, "RDP1_A"),
+ "J3", "mt8127",
+ MTK_EINT_FUNCTION(0, 115),
+ MTK_FUNCTION(0, "GPI114"),
+ MTK_FUNCTION(1, "RDP1_A"),
+ MTK_FUNCTION(2, "CMDAT3"),
+ MTK_FUNCTION(3, "CMCSD3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(115, "RDN0_A"),
+ "H2", "mt8127",
+ MTK_EINT_FUNCTION(0, 116),
+ MTK_FUNCTION(0, "GPI115"),
+ MTK_FUNCTION(1, "RDN0_A"),
+ MTK_FUNCTION(2, "CMHSYNC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(116, "RDP0_A"),
+ "H3", "mt8127",
+ MTK_EINT_FUNCTION(0, 117),
+ MTK_FUNCTION(0, "GPI116"),
+ MTK_FUNCTION(1, "RDP0_A"),
+ MTK_FUNCTION(2, "CMVSYNC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(117, "CMDAT0"),
+ "G5", "mt8127",
+ MTK_EINT_FUNCTION(0, 118),
+ MTK_FUNCTION(0, "GPIO117"),
+ MTK_FUNCTION(1, "CMDAT0"),
+ MTK_FUNCTION(2, "CMCSD0"),
+ MTK_FUNCTION(3, "ANT_SEL2"),
+ MTK_FUNCTION(7, "DBG_MON_B[28]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(118, "CMDAT1"),
+ "G4", "mt8127",
+ MTK_EINT_FUNCTION(0, 119),
+ MTK_FUNCTION(0, "GPIO118"),
+ MTK_FUNCTION(1, "CMDAT1"),
+ MTK_FUNCTION(2, "CMCSD1"),
+ MTK_FUNCTION(3, "ANT_SEL3"),
+ MTK_FUNCTION(7, "DBG_MON_B[29]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(119, "CMMCLK"),
+ "F3", "mt8127",
+ MTK_EINT_FUNCTION(0, 120),
+ MTK_FUNCTION(0, "GPIO119"),
+ MTK_FUNCTION(1, "CMMCLK"),
+ MTK_FUNCTION(3, "ANT_SEL4"),
+ MTK_FUNCTION(7, "DBG_MON_B[30]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(120, "CMPCLK"),
+ "G6", "mt8127",
+ MTK_EINT_FUNCTION(0, 121),
+ MTK_FUNCTION(0, "GPIO120"),
+ MTK_FUNCTION(1, "CMPCLK"),
+ MTK_FUNCTION(2, "CMCSK"),
+ MTK_FUNCTION(3, "ANT_SEL5"),
+ MTK_FUNCTION(7, "DBG_MON_B[31]")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(121, "MSDC1_CMD"),
+ "E3", "mt8127",
+ MTK_EINT_FUNCTION(0, 122),
+ MTK_FUNCTION(0, "GPIO121"),
+ MTK_FUNCTION(1, "MSDC1_CMD")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(122, "MSDC1_CLK"),
+ "D1", "mt8127",
+ MTK_EINT_FUNCTION(0, 123),
+ MTK_FUNCTION(0, "GPIO122"),
+ MTK_FUNCTION(1, "MSDC1_CLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(123, "MSDC1_DAT0"),
+ "D2", "mt8127",
+ MTK_EINT_FUNCTION(0, 124),
+ MTK_FUNCTION(0, "GPIO123"),
+ MTK_FUNCTION(1, "MSDC1_DAT0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(124, "MSDC1_DAT1"),
+ "D3", "mt8127",
+ MTK_EINT_FUNCTION(0, 125),
+ MTK_FUNCTION(0, "GPIO124"),
+ MTK_FUNCTION(1, "MSDC1_DAT1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(125, "MSDC1_DAT2"),
+ "F2", "mt8127",
+ MTK_EINT_FUNCTION(0, 126),
+ MTK_FUNCTION(0, "GPIO125"),
+ MTK_FUNCTION(1, "MSDC1_DAT2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(126, "MSDC1_DAT3"),
+ "E2", "mt8127",
+ MTK_EINT_FUNCTION(0, 127),
+ MTK_FUNCTION(0, "GPIO126"),
+ MTK_FUNCTION(1, "MSDC1_DAT3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(127, "MSDC0_DAT7"),
+ "C23", "mt8127",
+ MTK_EINT_FUNCTION(0, 128),
+ MTK_FUNCTION(0, "GPIO127"),
+ MTK_FUNCTION(1, "MSDC0_DAT7"),
+ MTK_FUNCTION(4, "NLD7")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(128, "MSDC0_DAT6"),
+ "C24", "mt8127",
+ MTK_EINT_FUNCTION(0, 129),
+ MTK_FUNCTION(0, "GPIO128"),
+ MTK_FUNCTION(1, "MSDC0_DAT6"),
+ MTK_FUNCTION(4, "NLD6")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(129, "MSDC0_DAT5"),
+ "D22", "mt8127",
+ MTK_EINT_FUNCTION(0, 130),
+ MTK_FUNCTION(0, "GPIO129"),
+ MTK_FUNCTION(1, "MSDC0_DAT5"),
+ MTK_FUNCTION(4, "NLD4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(130, "MSDC0_DAT4"),
+ "D24", "mt8127",
+ MTK_EINT_FUNCTION(0, 131),
+ MTK_FUNCTION(0, "GPIO130"),
+ MTK_FUNCTION(1, "MSDC0_DAT4"),
+ MTK_FUNCTION(4, "NLD3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(131, "MSDC0_RSTB"),
+ "F24", "mt8127",
+ MTK_EINT_FUNCTION(0, 132),
+ MTK_FUNCTION(0, "GPIO131"),
+ MTK_FUNCTION(1, "MSDC0_RSTB"),
+ MTK_FUNCTION(4, "NLD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(132, "MSDC0_CMD"),
+ "G20", "mt8127",
+ MTK_EINT_FUNCTION(0, 133),
+ MTK_FUNCTION(0, "GPIO132"),
+ MTK_FUNCTION(1, "MSDC0_CMD"),
+ MTK_FUNCTION(4, "NALE")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(133, "MSDC0_CLK"),
+ "G21", "mt8127",
+ MTK_EINT_FUNCTION(0, 134),
+ MTK_FUNCTION(0, "GPIO133"),
+ MTK_FUNCTION(1, "MSDC0_CLK"),
+ MTK_FUNCTION(4, "NWEB")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(134, "MSDC0_DAT3"),
+ "D23", "mt8127",
+ MTK_EINT_FUNCTION(0, 135),
+ MTK_FUNCTION(0, "GPIO134"),
+ MTK_FUNCTION(1, "MSDC0_DAT3"),
+ MTK_FUNCTION(4, "NLD1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(135, "MSDC0_DAT2"),
+ "E22", "mt8127",
+ MTK_EINT_FUNCTION(0, 136),
+ MTK_FUNCTION(0, "GPIO135"),
+ MTK_FUNCTION(1, "MSDC0_DAT2"),
+ MTK_FUNCTION(4, "NLD5")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(136, "MSDC0_DAT1"),
+ "E23", "mt8127",
+ MTK_EINT_FUNCTION(0, 137),
+ MTK_FUNCTION(0, "GPIO136"),
+ MTK_FUNCTION(1, "MSDC0_DAT1"),
+ MTK_FUNCTION(4, "NLD8")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(137, "MSDC0_DAT0"),
+ "F22", "mt8127",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO137"),
+ MTK_FUNCTION(1, "MSDC0_DAT0"),
+ MTK_FUNCTION(4, "WATCHDOG"),
+ MTK_FUNCTION(5, "NLD2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(138, "CEC"),
+ "AE21", "mt8127",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO138"),
+ MTK_FUNCTION(1, "CEC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(139, "HTPLG"),
+ "AD21", "mt8127",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO139"),
+ MTK_FUNCTION(1, "HTPLG")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(140, "HDMISCK"),
+ "AE22", "mt8127",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO140"),
+ MTK_FUNCTION(1, "HDMISCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(141, "HDMISD"),
+ "AD22", "mt8127",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO141"),
+ MTK_FUNCTION(1, "HDMISD")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(142, "EINT21"),
+ "J23", "mt8127",
+ MTK_EINT_FUNCTION(0, 21),
+ MTK_FUNCTION(0, "GPIO142"),
+ MTK_FUNCTION(1, "NRNB"),
+ MTK_FUNCTION(2, "ANT_SEL0"),
+ MTK_FUNCTION(7, "DBG_MON_B[32]")
+ ),
+};
+
+#endif /* __PINCTRL_MTK_MT8127_H */
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index a70a5fe79d44..84943e4cff09 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -738,9 +738,9 @@ static int meson_pinctrl_probe(struct platform_device *pdev)
pc->desc.npins = pc->data->num_pins;
pc->pcdev = pinctrl_register(&pc->desc, pc->dev, pc);
- if (!pc->pcdev) {
+ if (IS_ERR(pc->pcdev)) {
dev_err(pc->dev, "can't register pinctrl device");
- return -EINVAL;
+ return PTR_ERR(pc->pcdev);
}
ret = meson_gpiolib_register(pc);
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-370.c b/drivers/pinctrl/mvebu/pinctrl-armada-370.c
index 03aa58c4cb85..73dc1bc5f32c 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-370.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-370.c
@@ -52,12 +52,12 @@ static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = {
MPP_FUNCTION(0x2, "uart0", "rxd")),
MPP_MODE(4,
MPP_FUNCTION(0x0, "gpio", NULL),
- MPP_FUNCTION(0x1, "cpu_pd", "vdd")),
+ MPP_FUNCTION(0x1, "vdd", "cpu-pd")),
MPP_MODE(5,
MPP_FUNCTION(0x0, "gpo", NULL),
- MPP_FUNCTION(0x1, "ge0", "txclko"),
+ MPP_FUNCTION(0x1, "ge0", "txclkout"),
MPP_FUNCTION(0x2, "uart1", "txd"),
- MPP_FUNCTION(0x4, "spi1", "clk"),
+ MPP_FUNCTION(0x4, "spi1", "sck"),
MPP_FUNCTION(0x5, "audio", "mclk")),
MPP_MODE(6,
MPP_FUNCTION(0x0, "gpio", NULL),
@@ -68,7 +68,7 @@ static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = {
MPP_MODE(7,
MPP_FUNCTION(0x0, "gpo", NULL),
MPP_FUNCTION(0x1, "ge0", "txd1"),
- MPP_FUNCTION(0x4, "tdm", "tdx"),
+ MPP_FUNCTION(0x4, "tdm", "dtx"),
MPP_FUNCTION(0x5, "audio", "lrclk")),
MPP_MODE(8,
MPP_FUNCTION(0x0, "gpio", NULL),
@@ -207,11 +207,11 @@ static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = {
MPP_FUNCTION(0x2, "spi0", "cs0")),
MPP_MODE(34,
MPP_FUNCTION(0x0, "gpo", NULL),
- MPP_FUNCTION(0x1, "dev", "wen0"),
+ MPP_FUNCTION(0x1, "dev", "we0"),
MPP_FUNCTION(0x2, "spi0", "mosi")),
MPP_MODE(35,
MPP_FUNCTION(0x0, "gpo", NULL),
- MPP_FUNCTION(0x1, "dev", "oen"),
+ MPP_FUNCTION(0x1, "dev", "oe"),
MPP_FUNCTION(0x2, "spi0", "sck")),
MPP_MODE(36,
MPP_FUNCTION(0x0, "gpo", NULL),
@@ -348,13 +348,13 @@ static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = {
MPP_FUNCTION(0x1, "dev", "ale1"),
MPP_FUNCTION(0x2, "uart1", "rxd"),
MPP_FUNCTION(0x3, "sata0", "prsnt"),
- MPP_FUNCTION(0x4, "pcie", "rst-out"),
+ MPP_FUNCTION(0x4, "pcie", "rstout"),
MPP_FUNCTION(0x5, "audio", "sdi")),
MPP_MODE(61,
MPP_FUNCTION(0x0, "gpo", NULL),
- MPP_FUNCTION(0x1, "dev", "wen1"),
+ MPP_FUNCTION(0x1, "dev", "we1"),
MPP_FUNCTION(0x2, "uart1", "txd"),
- MPP_FUNCTION(0x5, "audio", "rclk")),
+ MPP_FUNCTION(0x5, "audio", "lrclk")),
MPP_MODE(62,
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x1, "dev", "a2"),
@@ -370,11 +370,11 @@ static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = {
MPP_MODE(64,
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x1, "spi0", "miso"),
- MPP_FUNCTION(0x2, "spi0-1", "cs1")),
+ MPP_FUNCTION(0x2, "spi0", "cs1")),
MPP_MODE(65,
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x1, "spi0", "mosi"),
- MPP_FUNCTION(0x2, "spi0-1", "cs2")),
+ MPP_FUNCTION(0x2, "spi0", "cs2")),
};
static struct mvebu_pinctrl_soc_info armada_370_pinctrl_info;
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-375.c b/drivers/pinctrl/mvebu/pinctrl-armada-375.c
index ca1e7571fedb..54e9fbd0121f 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-375.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-375.c
@@ -51,7 +51,7 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_MODE(2,
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x1, "dev", "ad4"),
- MPP_FUNCTION(0x2, "ptp", "eventreq"),
+ MPP_FUNCTION(0x2, "ptp", "evreq"),
MPP_FUNCTION(0x3, "led", "c0"),
MPP_FUNCTION(0x4, "audio", "sdi"),
MPP_FUNCTION(0x5, "nand", "io4"),
@@ -59,7 +59,7 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_MODE(3,
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x1, "dev", "ad5"),
- MPP_FUNCTION(0x2, "ptp", "triggen"),
+ MPP_FUNCTION(0x2, "ptp", "trig"),
MPP_FUNCTION(0x3, "led", "p3"),
MPP_FUNCTION(0x4, "audio", "mclk"),
MPP_FUNCTION(0x5, "nand", "io5"),
@@ -81,7 +81,7 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x1, "dev", "ad0"),
MPP_FUNCTION(0x3, "led", "p1"),
- MPP_FUNCTION(0x4, "audio", "rclk"),
+ MPP_FUNCTION(0x4, "audio", "lrclk"),
MPP_FUNCTION(0x5, "nand", "io0")),
MPP_MODE(7,
MPP_FUNCTION(0x0, "gpio", NULL),
@@ -92,19 +92,17 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_FUNCTION(0x5, "nand", "io1")),
MPP_MODE(8,
MPP_FUNCTION(0x0, "gpio", NULL),
- MPP_FUNCTION(0x1, "dev ", "bootcs"),
+ MPP_FUNCTION(0x1, "dev", "bootcs"),
MPP_FUNCTION(0x2, "spi0", "cs0"),
MPP_FUNCTION(0x3, "spi1", "cs0"),
MPP_FUNCTION(0x5, "nand", "ce")),
MPP_MODE(9,
MPP_FUNCTION(0x0, "gpio", NULL),
- MPP_FUNCTION(0x1, "nf", "wen"),
MPP_FUNCTION(0x2, "spi0", "sck"),
MPP_FUNCTION(0x3, "spi1", "sck"),
MPP_FUNCTION(0x5, "nand", "we")),
MPP_MODE(10,
MPP_FUNCTION(0x0, "gpio", NULL),
- MPP_FUNCTION(0x1, "nf", "ren"),
MPP_FUNCTION(0x2, "dram", "vttctrl"),
MPP_FUNCTION(0x3, "led", "c1"),
MPP_FUNCTION(0x5, "nand", "re"),
@@ -122,9 +120,9 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_FUNCTION(0x5, "nand", "ale")),
MPP_MODE(13,
MPP_FUNCTION(0x0, "gpio", NULL),
- MPP_FUNCTION(0x1, "dev", "readyn"),
- MPP_FUNCTION(0x2, "pcie0", "rstoutn"),
- MPP_FUNCTION(0x3, "pcie1", "rstoutn"),
+ MPP_FUNCTION(0x1, "dev", "ready"),
+ MPP_FUNCTION(0x2, "pcie0", "rstout"),
+ MPP_FUNCTION(0x3, "pcie1", "rstout"),
MPP_FUNCTION(0x5, "nand", "rb"),
MPP_FUNCTION(0x6, "spi1", "mosi")),
MPP_MODE(14,
@@ -143,10 +141,10 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_FUNCTION(0x2, "uart0", "rxd")),
MPP_MODE(18,
MPP_FUNCTION(0x0, "gpio", NULL),
- MPP_FUNCTION(0x2, "tdm", "intn")),
+ MPP_FUNCTION(0x2, "tdm", "int")),
MPP_MODE(19,
MPP_FUNCTION(0x0, "gpio", NULL),
- MPP_FUNCTION(0x2, "tdm", "rstn")),
+ MPP_FUNCTION(0x2, "tdm", "rst")),
MPP_MODE(20,
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x2, "tdm", "pclk")),
@@ -203,13 +201,13 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_FUNCTION(0x2, "ge1", "rxclk"),
MPP_FUNCTION(0x3, "sd", "d3"),
MPP_FUNCTION(0x5, "spi0", "sck"),
- MPP_FUNCTION(0x6, "pcie0", "rstoutn")),
+ MPP_FUNCTION(0x6, "pcie0", "rstout")),
MPP_MODE(30,
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x2, "ge1", "txd0"),
MPP_FUNCTION(0x3, "spi1", "cs0"),
MPP_FUNCTION(0x5, "led", "p3"),
- MPP_FUNCTION(0x6, "ptp", "eventreq")),
+ MPP_FUNCTION(0x6, "ptp", "evreq")),
MPP_MODE(31,
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x2, "ge1", "txd1"),
@@ -219,7 +217,7 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x2, "ge1", "txd2"),
MPP_FUNCTION(0x3, "spi1", "sck"),
- MPP_FUNCTION(0x4, "ptp", "triggen"),
+ MPP_FUNCTION(0x4, "ptp", "trig"),
MPP_FUNCTION(0x5, "led", "c0")),
MPP_MODE(33,
MPP_FUNCTION(0x0, "gpio", NULL),
@@ -244,7 +242,7 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_MODE(37,
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x1, "pcie0", "clkreq"),
- MPP_FUNCTION(0x2, "tdm", "intn"),
+ MPP_FUNCTION(0x2, "tdm", "int"),
MPP_FUNCTION(0x4, "ge", "mdc")),
MPP_MODE(38,
MPP_FUNCTION(0x0, "gpio", NULL),
@@ -278,7 +276,7 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_MODE(45,
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x2, "spi0", "cs2"),
- MPP_FUNCTION(0x4, "pcie0", "rstoutn"),
+ MPP_FUNCTION(0x4, "pcie0", "rstout"),
MPP_FUNCTION(0x5, "led", "c2"),
MPP_FUNCTION(0x6, "spi1", "cs2")),
MPP_MODE(46,
@@ -286,13 +284,13 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_FUNCTION(0x1, "led", "p0"),
MPP_FUNCTION(0x2, "ge0", "txd0"),
MPP_FUNCTION(0x3, "ge1", "txd0"),
- MPP_FUNCTION(0x6, "dev", "wen1")),
+ MPP_FUNCTION(0x6, "dev", "we1")),
MPP_MODE(47,
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x1, "led", "p1"),
MPP_FUNCTION(0x2, "ge0", "txd1"),
MPP_FUNCTION(0x3, "ge1", "txd1"),
- MPP_FUNCTION(0x5, "ptp", "triggen"),
+ MPP_FUNCTION(0x5, "ptp", "trig"),
MPP_FUNCTION(0x6, "dev", "ale0")),
MPP_MODE(48,
MPP_FUNCTION(0x0, "gpio", NULL),
@@ -311,7 +309,7 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_FUNCTION(0x1, "led", "c0"),
MPP_FUNCTION(0x2, "ge0", "rxd0"),
MPP_FUNCTION(0x3, "ge1", "rxd0"),
- MPP_FUNCTION(0x5, "ptp", "eventreq"),
+ MPP_FUNCTION(0x5, "ptp", "evreq"),
MPP_FUNCTION(0x6, "dev", "ad12")),
MPP_MODE(51,
MPP_FUNCTION(0x0, "gpio", NULL),
@@ -328,14 +326,14 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_FUNCTION(0x6, "dev", "ad9")),
MPP_MODE(53,
MPP_FUNCTION(0x0, "gpio", NULL),
- MPP_FUNCTION(0x1, "pcie1", "rstoutn"),
+ MPP_FUNCTION(0x1, "pcie1", "rstout"),
MPP_FUNCTION(0x2, "ge0", "rxd3"),
MPP_FUNCTION(0x3, "ge1", "rxd3"),
MPP_FUNCTION(0x5, "i2c0", "sck"),
MPP_FUNCTION(0x6, "dev", "ad10")),
MPP_MODE(54,
MPP_FUNCTION(0x0, "gpio", NULL),
- MPP_FUNCTION(0x1, "pcie0", "rstoutn"),
+ MPP_FUNCTION(0x1, "pcie0", "rstout"),
MPP_FUNCTION(0x2, "ge0", "rxctl"),
MPP_FUNCTION(0x3, "ge1", "rxctl"),
MPP_FUNCTION(0x6, "dev", "ad11")),
@@ -353,7 +351,7 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x2, "ge0", "txctl"),
MPP_FUNCTION(0x3, "ge1", "txctl"),
- MPP_FUNCTION(0x6, "dev", "wen0")),
+ MPP_FUNCTION(0x6, "dev", "we0")),
MPP_MODE(58,
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x4, "led", "c0")),
@@ -379,9 +377,9 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_FUNCTION(0x6, "dev", "ad15")),
MPP_MODE(63,
MPP_FUNCTION(0x0, "gpio", NULL),
- MPP_FUNCTION(0x2, "ptp", "triggen"),
+ MPP_FUNCTION(0x2, "ptp", "trig"),
MPP_FUNCTION(0x4, "led", "p2"),
- MPP_FUNCTION(0x6, "dev", "burst")),
+ MPP_FUNCTION(0x6, "dev", "burst/last")),
MPP_MODE(64,
MPP_FUNCTION(0x0, "gpio", NULL),
MPP_FUNCTION(0x2, "dram", "vttctrl"),
@@ -391,9 +389,9 @@ static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
MPP_FUNCTION(0x1, "sata1", "prsnt")),
MPP_MODE(66,
MPP_FUNCTION(0x0, "gpio", NULL),
- MPP_FUNCTION(0x2, "ptp", "eventreq"),
+ MPP_FUNCTION(0x2, "ptp", "evreq"),
MPP_FUNCTION(0x4, "spi1", "cs3"),
- MPP_FUNCTION(0x5, "pcie0", "rstoutn"),
+ MPP_FUNCTION(0x5, "pcie0", "rstout"),
MPP_FUNCTION(0x6, "dev", "cs3")),
};
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c
index 83bbcc72be1f..6ec82c62dff7 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c
@@ -94,56 +94,58 @@ static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "ge0", "rxd0", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
MPP_VAR_FUNCTION(4, "spi0", "cs1", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "dev", "ad14", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "dev", "ad14", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "pcie3", "clkreq", V_88F6810_PLUS)),
MPP_MODE(13,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "ge0", "rxd1", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "pcie0", "clkreq", V_88F6810_PLUS),
MPP_VAR_FUNCTION(3, "pcie1", "clkreq", V_88F6820_PLUS),
MPP_VAR_FUNCTION(4, "spi0", "cs2", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "dev", "ad15", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "dev", "ad15", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "pcie2", "clkreq", V_88F6810_PLUS)),
MPP_MODE(14,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "ge0", "rxd2", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "ptp", "clk", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(3, "m", "vtt_ctrl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "dram", "vttctrl", V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "spi0", "cs3", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "dev", "wen1", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "dev", "we1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "pcie3", "clkreq", V_88F6810_PLUS)),
MPP_MODE(15,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "ge0", "rxd3", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "ge", "mdc slave", V_88F6810_PLUS),
MPP_VAR_FUNCTION(3, "pcie0", "rstout", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(4, "spi0", "mosi", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "pcie1", "rstout", V_88F6820_PLUS)),
+ MPP_VAR_FUNCTION(4, "spi0", "mosi", V_88F6810_PLUS)),
MPP_MODE(16,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "ge0", "rxctl", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "ge", "mdio slave", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(3, "m", "decc_err", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "dram", "deccerr", V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "spi0", "miso", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "pcie0", "clkreq", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "pcie0", "clkreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "pcie1", "clkreq", V_88F6820_PLUS)),
MPP_MODE(17,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "ge0", "rxclk", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "ptp", "clk", V_88F6810_PLUS),
MPP_VAR_FUNCTION(3, "ua1", "rxd", V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "spi0", "sck", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "sata1", "prsnt", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "sata0", "prsnt", V_88F6810_PLUS)),
MPP_MODE(18,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "ge0", "rxerr", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(2, "ptp", "trig_gen", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "trig", V_88F6810_PLUS),
MPP_VAR_FUNCTION(3, "ua1", "txd", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(4, "spi0", "cs0", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "pcie1", "rstout", V_88F6820_PLUS)),
+ MPP_VAR_FUNCTION(4, "spi0", "cs0", V_88F6810_PLUS)),
MPP_MODE(19,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "ge0", "col", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(2, "ptp", "event_req", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(3, "pcie0", "clkreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "evreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ge0", "txerr", V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "sata1", "prsnt", V_88F6810_PLUS),
MPP_VAR_FUNCTION(5, "ua0", "cts", V_88F6810_PLUS),
MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6810_PLUS)),
@@ -151,7 +153,6 @@ static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "ge0", "txclk", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "ptp", "clk", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
MPP_VAR_FUNCTION(4, "sata0", "prsnt", V_88F6810_PLUS),
MPP_VAR_FUNCTION(5, "ua0", "rts", V_88F6810_PLUS),
MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6810_PLUS)),
@@ -161,7 +162,8 @@ static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
MPP_VAR_FUNCTION(2, "ge1", "rxd0", V_88F6810_PLUS),
MPP_VAR_FUNCTION(3, "sata0", "prsnt", V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "sd0", "cmd", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "dev", "bootcs", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "dev", "bootcs", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "sata1", "prsnt", V_88F6810_PLUS)),
MPP_MODE(22,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "spi0", "mosi", V_88F6810_PLUS),
@@ -209,7 +211,7 @@ static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
MPP_MODE(30,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "ge1", "txd2", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "dev", "oen", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "dev", "oe", V_88F6810_PLUS)),
MPP_MODE(31,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "ge1", "txd3", V_88F6810_PLUS),
@@ -217,10 +219,10 @@ static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
MPP_MODE(32,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "ge1", "txctl", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "dev", "wen0", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "dev", "we0", V_88F6810_PLUS)),
MPP_MODE(33,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
- MPP_VAR_FUNCTION(1, "m", "decc_err", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "dram", "deccerr", V_88F6810_PLUS),
MPP_VAR_FUNCTION(5, "dev", "ad3", V_88F6810_PLUS)),
MPP_MODE(34,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
@@ -231,7 +233,7 @@ static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
MPP_VAR_FUNCTION(5, "dev", "a1", V_88F6810_PLUS)),
MPP_MODE(36,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
- MPP_VAR_FUNCTION(1, "ptp", "trig_gen", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ptp", "trig", V_88F6810_PLUS),
MPP_VAR_FUNCTION(5, "dev", "a0", V_88F6810_PLUS)),
MPP_MODE(37,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
@@ -241,7 +243,7 @@ static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
MPP_VAR_FUNCTION(5, "dev", "ad8", V_88F6810_PLUS)),
MPP_MODE(38,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
- MPP_VAR_FUNCTION(1, "ptp", "event_req", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ptp", "evreq", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "ge1", "rxd1", V_88F6810_PLUS),
MPP_VAR_FUNCTION(3, "ref", "clk_out0", V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "sd0", "d0", V_88F6810_PLUS),
@@ -266,7 +268,8 @@ static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
MPP_VAR_FUNCTION(2, "ge1", "rxctl", V_88F6810_PLUS),
MPP_VAR_FUNCTION(3, "ua0", "cts", V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "spi1", "cs3", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "dev", "burst/last", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "dev", "burst/last", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "nand", "rb0", V_88F6810_PLUS)),
MPP_MODE(42,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "ua1", "txd", V_88F6810_PLUS),
@@ -275,84 +278,82 @@ static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
MPP_MODE(43,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "pcie0", "clkreq", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(2, "m", "vtt_ctrl", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(3, "m", "decc_err", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(4, "pcie0", "rstout", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "dev", "clkout", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(2, "dram", "vttctrl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "dram", "deccerr", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "cs2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "clkout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "nand", "rb1", V_88F6810_PLUS)),
MPP_MODE(44,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6810_PLUS),
MPP_VAR_FUNCTION(3, "sata2", "prsnt", V_88F6828),
- MPP_VAR_FUNCTION(4, "sata3", "prsnt", V_88F6828),
- MPP_VAR_FUNCTION(5, "pcie0", "rstout", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(4, "sata3", "prsnt", V_88F6828)),
MPP_MODE(45,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "ref", "clk_out0", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
- MPP_VAR_FUNCTION(4, "pcie2", "rstout", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "pcie3", "rstout", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6810_PLUS)),
MPP_MODE(46,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "ref", "clk_out1", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
- MPP_VAR_FUNCTION(4, "pcie2", "rstout", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "pcie3", "rstout", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6810_PLUS)),
MPP_MODE(47,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6810_PLUS),
MPP_VAR_FUNCTION(3, "sata2", "prsnt", V_88F6828),
- MPP_VAR_FUNCTION(4, "spi1", "cs2", V_88F6810_PLUS),
MPP_VAR_FUNCTION(5, "sata3", "prsnt", V_88F6828)),
MPP_MODE(48,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(2, "m", "vtt_ctrl", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(3, "tdm2c", "pclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "dram", "vttctrl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm", "pclk", V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "audio", "mclk", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "sd0", "d4", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "sd0", "d4", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "pcie0", "clkreq", V_88F6810_PLUS)),
MPP_MODE(49,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "sata2", "prsnt", V_88F6828),
MPP_VAR_FUNCTION(2, "sata3", "prsnt", V_88F6828),
- MPP_VAR_FUNCTION(3, "tdm2c", "fsync", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm", "fsync", V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "audio", "lrclk", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "sd0", "d5", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "sd0", "d5", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "pcie1", "clkreq", V_88F6820_PLUS)),
MPP_MODE(50,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(2, "pcie1", "rstout", V_88F6820_PLUS),
- MPP_VAR_FUNCTION(3, "tdm2c", "drx", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm", "drx", V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "audio", "extclk", V_88F6810_PLUS),
MPP_VAR_FUNCTION(5, "sd0", "cmd", V_88F6810_PLUS)),
MPP_MODE(51,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
- MPP_VAR_FUNCTION(3, "tdm2c", "dtx", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm", "dtx", V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "audio", "sdo", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "m", "decc_err", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "dram", "deccerr", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ptp", "trig", V_88F6810_PLUS)),
MPP_MODE(52,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(2, "pcie1", "rstout", V_88F6820_PLUS),
- MPP_VAR_FUNCTION(3, "tdm2c", "intn", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm", "int", V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "audio", "sdi", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "sd0", "d6", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "sd0", "d6", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ptp", "clk", V_88F6810_PLUS)),
MPP_MODE(53,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "sata1", "prsnt", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "sata0", "prsnt", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(3, "tdm2c", "rstn", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm", "rst", V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "audio", "bclk", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "sd0", "d7", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "sd0", "d7", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ptp", "evreq", V_88F6810_PLUS)),
MPP_MODE(54,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6810_PLUS),
MPP_VAR_FUNCTION(3, "pcie0", "rstout", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(4, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "ge0", "txerr", V_88F6810_PLUS),
MPP_VAR_FUNCTION(5, "sd0", "d3", V_88F6810_PLUS)),
MPP_MODE(55,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
@@ -360,29 +361,32 @@ static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
MPP_VAR_FUNCTION(2, "ge", "mdio", V_88F6810_PLUS),
MPP_VAR_FUNCTION(3, "pcie1", "clkreq", V_88F6820_PLUS),
MPP_VAR_FUNCTION(4, "spi1", "cs1", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "sd0", "d0", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "sd0", "d0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6810_PLUS)),
MPP_MODE(56,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "ua1", "rts", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "ge", "mdc", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(3, "m", "decc_err", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(4, "spi1", "mosi", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(3, "dram", "deccerr", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "mosi", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6810_PLUS)),
MPP_MODE(57,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "spi1", "sck", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "sd0", "clk", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "sd0", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6810_PLUS)),
MPP_MODE(58,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "pcie1", "clkreq", V_88F6820_PLUS),
MPP_VAR_FUNCTION(2, "i2c1", "sck", V_88F6810_PLUS),
MPP_VAR_FUNCTION(3, "pcie2", "clkreq", V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "spi1", "miso", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "sd0", "d1", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "sd0", "d1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6810_PLUS)),
MPP_MODE(59,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "i2c1", "sda", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
MPP_VAR_FUNCTION(4, "spi1", "cs0", V_88F6810_PLUS),
MPP_VAR_FUNCTION(5, "sd0", "d2", V_88F6810_PLUS)),
};
@@ -411,7 +415,7 @@ static struct mvebu_mpp_ctrl armada_38x_mpp_controls[] = {
static struct pinctrl_gpio_range armada_38x_mpp_gpio_ranges[] = {
MPP_GPIO_RANGE(0, 0, 0, 32),
- MPP_GPIO_RANGE(1, 32, 32, 27),
+ MPP_GPIO_RANGE(1, 32, 32, 28),
};
static int armada_38x_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-39x.c b/drivers/pinctrl/mvebu/pinctrl-armada-39x.c
index 42491624d660..fcfe9b478a2e 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-39x.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-39x.c
@@ -36,8 +36,10 @@ static int armada_39x_mpp_ctrl_set(unsigned pid, unsigned long config)
enum {
V_88F6920 = BIT(0),
- V_88F6928 = BIT(1),
- V_88F6920_PLUS = (V_88F6920 | V_88F6928),
+ V_88F6925 = BIT(1),
+ V_88F6928 = BIT(2),
+ V_88F6920_PLUS = (V_88F6920 | V_88F6925 | V_88F6928),
+ V_88F6925_PLUS = (V_88F6925 | V_88F6928),
};
static struct mvebu_mpp_mode armada_39x_mpp_modes[] = {
@@ -82,7 +84,7 @@ static struct mvebu_mpp_mode armada_39x_mpp_modes[] = {
MPP_MODE(10,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "ad12", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(7, "ptp", "event", V_88F6920_PLUS)),
+ MPP_VAR_FUNCTION(7, "ptp", "evreq", V_88F6920_PLUS)),
MPP_MODE(11,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "ad13", V_88F6920_PLUS),
@@ -95,11 +97,12 @@ static struct mvebu_mpp_mode armada_39x_mpp_modes[] = {
MPP_MODE(13,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "ad15", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(6, "pcie2", "clkreq", V_88F6920_PLUS),
MPP_VAR_FUNCTION(7, "led", "data", V_88F6920_PLUS)),
MPP_MODE(14,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(3, "m", "vtt", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(5, "dev", "wen1", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(3, "dram", "vttctrl", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "we1", V_88F6920_PLUS),
MPP_VAR_FUNCTION(7, "ua1", "txd", V_88F6920_PLUS)),
MPP_MODE(15,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
@@ -108,13 +111,16 @@ static struct mvebu_mpp_mode armada_39x_mpp_modes[] = {
MPP_VAR_FUNCTION(7, "i2c1", "sck", V_88F6920_PLUS)),
MPP_MODE(16,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(3, "m", "decc", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(3, "dram", "deccerr", V_88F6920_PLUS),
MPP_VAR_FUNCTION(4, "spi0", "miso", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "pcie0", "clkreq", V_88F6920_PLUS),
MPP_VAR_FUNCTION(7, "i2c1", "sda", V_88F6920_PLUS)),
MPP_MODE(17,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(3, "ua1", "rxd", V_88F6920_PLUS),
MPP_VAR_FUNCTION(4, "spi0", "sck", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "sata1", "prsnt", V_88F6925_PLUS),
+ MPP_VAR_FUNCTION(6, "sata0", "prsnt", V_88F6925_PLUS),
MPP_VAR_FUNCTION(7, "smi", "mdio", V_88F6920_PLUS)),
MPP_MODE(18,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
@@ -123,22 +129,23 @@ static struct mvebu_mpp_mode armada_39x_mpp_modes[] = {
MPP_VAR_FUNCTION(7, "i2c2", "sck", V_88F6920_PLUS)),
MPP_MODE(19,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(4, "sata1", "present", V_88F6928),
+ MPP_VAR_FUNCTION(4, "sata1", "prsnt", V_88F6925_PLUS),
MPP_VAR_FUNCTION(5, "ua0", "cts", V_88F6920_PLUS),
MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6920_PLUS),
MPP_VAR_FUNCTION(7, "i2c2", "sda", V_88F6920_PLUS)),
MPP_MODE(20,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(4, "sata0", "present", V_88F6928),
+ MPP_VAR_FUNCTION(4, "sata0", "prsnt", V_88F6925_PLUS),
MPP_VAR_FUNCTION(5, "ua0", "rts", V_88F6920_PLUS),
MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6920_PLUS),
MPP_VAR_FUNCTION(7, "smi", "mdc", V_88F6920_PLUS)),
MPP_MODE(21,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(1, "spi0", "cs1", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(3, "sata0", "present", V_88F6928),
- MPP_VAR_FUNCTION(4, "sd", "cmd", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(3, "sata0", "prsnt", V_88F6925_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "cmd", V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "bootcs", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(6, "sata1", "prsnt", V_88F6925_PLUS),
MPP_VAR_FUNCTION(8, "ge", "rxd0", V_88F6920_PLUS)),
MPP_MODE(22,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
@@ -153,31 +160,31 @@ static struct mvebu_mpp_mode armada_39x_mpp_modes[] = {
MPP_VAR_FUNCTION(1, "spi0", "miso", V_88F6920_PLUS),
MPP_VAR_FUNCTION(2, "ua0", "cts", V_88F6920_PLUS),
MPP_VAR_FUNCTION(3, "ua1", "rxd", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(4, "sd", "d4", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(5, "dev", "readyn", V_88F6920_PLUS)),
+ MPP_VAR_FUNCTION(4, "sd0", "d4", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ready", V_88F6920_PLUS)),
MPP_MODE(25,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(1, "spi0", "cs0", V_88F6920_PLUS),
MPP_VAR_FUNCTION(2, "ua0", "rts", V_88F6920_PLUS),
MPP_VAR_FUNCTION(3, "ua1", "txd", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(4, "sd", "d5", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d5", V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "cs0", V_88F6920_PLUS)),
MPP_MODE(26,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(1, "spi0", "cs2", V_88F6920_PLUS),
MPP_VAR_FUNCTION(3, "i2c1", "sck", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(4, "sd", "d6", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d6", V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "cs1", V_88F6920_PLUS)),
MPP_MODE(27,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(1, "spi0", "cs3", V_88F6920_PLUS),
MPP_VAR_FUNCTION(3, "i2c1", "sda", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(4, "sd", "d7", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d7", V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "cs2", V_88F6920_PLUS),
MPP_VAR_FUNCTION(8, "ge", "txclkout", V_88F6920_PLUS)),
MPP_MODE(28,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(4, "sd", "clk", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "clk", V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "ad5", V_88F6920_PLUS),
MPP_VAR_FUNCTION(8, "ge", "txd0", V_88F6920_PLUS)),
MPP_MODE(29,
@@ -186,7 +193,7 @@ static struct mvebu_mpp_mode armada_39x_mpp_modes[] = {
MPP_VAR_FUNCTION(8, "ge", "txd1", V_88F6920_PLUS)),
MPP_MODE(30,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(5, "dev", "oen", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "oe", V_88F6920_PLUS),
MPP_VAR_FUNCTION(8, "ge", "txd2", V_88F6920_PLUS)),
MPP_MODE(31,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
@@ -194,45 +201,45 @@ static struct mvebu_mpp_mode armada_39x_mpp_modes[] = {
MPP_VAR_FUNCTION(8, "ge", "txd3", V_88F6920_PLUS)),
MPP_MODE(32,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(5, "dev", "wen0", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "we0", V_88F6920_PLUS),
MPP_VAR_FUNCTION(8, "ge", "txctl", V_88F6920_PLUS)),
MPP_MODE(33,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(1, "m", "decc", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(1, "dram", "deccerr", V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "ad3", V_88F6920_PLUS)),
MPP_MODE(34,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "ad1", V_88F6920_PLUS)),
MPP_MODE(35,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(1, "ref", "clk", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(1, "ref", "clk_out1", V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "a1", V_88F6920_PLUS)),
MPP_MODE(36,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "a0", V_88F6920_PLUS)),
MPP_MODE(37,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(4, "sd", "d3", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d3", V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "ad8", V_88F6920_PLUS),
MPP_VAR_FUNCTION(8, "ge", "rxclk", V_88F6920_PLUS)),
MPP_MODE(38,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(3, "ref", "clk", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(4, "sd", "d0", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(3, "ref", "clk_out0", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d0", V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "ad4", V_88F6920_PLUS),
MPP_VAR_FUNCTION(8, "ge", "rxd1", V_88F6920_PLUS)),
MPP_MODE(39,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(1, "i2c1", "sck", V_88F6920_PLUS),
MPP_VAR_FUNCTION(3, "ua0", "cts", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(4, "sd", "d1", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d1", V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "a2", V_88F6920_PLUS),
MPP_VAR_FUNCTION(8, "ge", "rxd2", V_88F6920_PLUS)),
MPP_MODE(40,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(1, "i2c1", "sda", V_88F6920_PLUS),
MPP_VAR_FUNCTION(3, "ua0", "rts", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(4, "sd", "d2", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d2", V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "ad6", V_88F6920_PLUS),
MPP_VAR_FUNCTION(8, "ge", "rxd3", V_88F6920_PLUS)),
MPP_MODE(41,
@@ -240,8 +247,8 @@ static struct mvebu_mpp_mode armada_39x_mpp_modes[] = {
MPP_VAR_FUNCTION(1, "ua1", "rxd", V_88F6920_PLUS),
MPP_VAR_FUNCTION(3, "ua0", "cts", V_88F6920_PLUS),
MPP_VAR_FUNCTION(4, "spi1", "cs3", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(5, "dev", "burstn", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(6, "nd", "rbn0", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "burst/last", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(6, "nand", "rb0", V_88F6920_PLUS),
MPP_VAR_FUNCTION(8, "ge", "rxctl", V_88F6920_PLUS)),
MPP_MODE(42,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
@@ -251,113 +258,119 @@ static struct mvebu_mpp_mode armada_39x_mpp_modes[] = {
MPP_MODE(43,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(1, "pcie0", "clkreq", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(2, "m", "vtt", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(3, "m", "decc", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(2, "dram", "vttctrl", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(3, "dram", "deccerr", V_88F6920_PLUS),
MPP_VAR_FUNCTION(4, "spi1", "cs2", V_88F6920_PLUS),
MPP_VAR_FUNCTION(5, "dev", "clkout", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(6, "nd", "rbn1", V_88F6920_PLUS)),
+ MPP_VAR_FUNCTION(6, "nand", "rb1", V_88F6920_PLUS)),
MPP_MODE(44,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(1, "sata0", "present", V_88F6928),
- MPP_VAR_FUNCTION(2, "sata1", "present", V_88F6928),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6925_PLUS),
+ MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6925_PLUS),
+ MPP_VAR_FUNCTION(3, "sata2", "prsnt", V_88F6928),
+ MPP_VAR_FUNCTION(4, "sata3", "prsnt", V_88F6928),
MPP_VAR_FUNCTION(7, "led", "clk", V_88F6920_PLUS)),
MPP_MODE(45,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(1, "ref", "clk", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(1, "ref", "clk_out0", V_88F6920_PLUS),
MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6920_PLUS),
MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6920_PLUS)),
MPP_MODE(46,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(1, "ref", "clk", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(1, "ref", "clk_out1", V_88F6920_PLUS),
MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6920_PLUS),
MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6920_PLUS),
MPP_VAR_FUNCTION(7, "led", "stb", V_88F6920_PLUS)),
MPP_MODE(47,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(1, "sata0", "present", V_88F6928),
- MPP_VAR_FUNCTION(2, "sata1", "present", V_88F6928),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6925_PLUS),
+ MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6925_PLUS),
+ MPP_VAR_FUNCTION(3, "sata2", "prsnt", V_88F6928),
+ MPP_VAR_FUNCTION(5, "sata3", "prsnt", V_88F6928),
MPP_VAR_FUNCTION(7, "led", "data", V_88F6920_PLUS)),
MPP_MODE(48,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(1, "sata0", "present", V_88F6928),
- MPP_VAR_FUNCTION(2, "m", "vtt", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6925_PLUS),
+ MPP_VAR_FUNCTION(2, "dram", "vttctrl", V_88F6920_PLUS),
MPP_VAR_FUNCTION(3, "tdm", "pclk", V_88F6928),
MPP_VAR_FUNCTION(4, "audio", "mclk", V_88F6928),
- MPP_VAR_FUNCTION(5, "sd", "d4", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d4", V_88F6920_PLUS),
MPP_VAR_FUNCTION(6, "pcie0", "clkreq", V_88F6920_PLUS),
MPP_VAR_FUNCTION(7, "ua1", "txd", V_88F6920_PLUS)),
MPP_MODE(49,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(1, "sata2", "prsnt", V_88F6928),
+ MPP_VAR_FUNCTION(2, "sata3", "prsnt", V_88F6928),
MPP_VAR_FUNCTION(3, "tdm", "fsync", V_88F6928),
MPP_VAR_FUNCTION(4, "audio", "lrclk", V_88F6928),
- MPP_VAR_FUNCTION(5, "sd", "d5", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d5", V_88F6920_PLUS),
MPP_VAR_FUNCTION(7, "ua2", "rxd", V_88F6920_PLUS)),
MPP_MODE(50,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6920_PLUS),
MPP_VAR_FUNCTION(3, "tdm", "drx", V_88F6928),
MPP_VAR_FUNCTION(4, "audio", "extclk", V_88F6928),
- MPP_VAR_FUNCTION(5, "sd", "cmd", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "cmd", V_88F6920_PLUS),
MPP_VAR_FUNCTION(7, "ua2", "rxd", V_88F6920_PLUS)),
MPP_MODE(51,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(3, "tdm", "dtx", V_88F6928),
MPP_VAR_FUNCTION(4, "audio", "sdo", V_88F6928),
- MPP_VAR_FUNCTION(5, "m", "decc", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "dram", "deccerr", V_88F6920_PLUS),
MPP_VAR_FUNCTION(7, "ua2", "txd", V_88F6920_PLUS)),
MPP_MODE(52,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(3, "tdm", "intn", V_88F6928),
+ MPP_VAR_FUNCTION(3, "tdm", "int", V_88F6928),
MPP_VAR_FUNCTION(4, "audio", "sdi", V_88F6928),
- MPP_VAR_FUNCTION(5, "sd", "d6", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d6", V_88F6920_PLUS),
MPP_VAR_FUNCTION(7, "i2c3", "sck", V_88F6920_PLUS)),
MPP_MODE(53,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(1, "sata1", "present", V_88F6928),
- MPP_VAR_FUNCTION(2, "sata0", "present", V_88F6928),
- MPP_VAR_FUNCTION(3, "tdm", "rstn", V_88F6928),
+ MPP_VAR_FUNCTION(1, "sata1", "prsnt", V_88F6925_PLUS),
+ MPP_VAR_FUNCTION(2, "sata0", "prsnt", V_88F6925_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm", "rst", V_88F6928),
MPP_VAR_FUNCTION(4, "audio", "bclk", V_88F6928),
- MPP_VAR_FUNCTION(5, "sd", "d7", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d7", V_88F6920_PLUS),
MPP_VAR_FUNCTION(7, "i2c3", "sda", V_88F6920_PLUS)),
MPP_MODE(54,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
- MPP_VAR_FUNCTION(1, "sata0", "present", V_88F6928),
- MPP_VAR_FUNCTION(2, "sata1", "present", V_88F6928),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6925_PLUS),
+ MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6925_PLUS),
MPP_VAR_FUNCTION(3, "pcie0", "rstout", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(5, "sd", "d3", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d3", V_88F6920_PLUS),
MPP_VAR_FUNCTION(7, "ua3", "txd", V_88F6920_PLUS)),
MPP_MODE(55,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(1, "ua1", "cts", V_88F6920_PLUS),
MPP_VAR_FUNCTION(4, "spi1", "cs1", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(5, "sd", "d0", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d0", V_88F6920_PLUS),
MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6920_PLUS),
MPP_VAR_FUNCTION(7, "ua3", "rxd", V_88F6920_PLUS)),
MPP_MODE(56,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(1, "ua1", "rts", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(3, "m", "decc", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(3, "dram", "deccerr", V_88F6920_PLUS),
MPP_VAR_FUNCTION(4, "spi1", "mosi", V_88F6920_PLUS),
MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6920_PLUS)),
MPP_MODE(57,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(4, "spi1", "sck", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(5, "sd", "clk", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "clk", V_88F6920_PLUS),
MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6920_PLUS)),
MPP_MODE(58,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(2, "i2c1", "sck", V_88F6920_PLUS),
MPP_VAR_FUNCTION(3, "pcie2", "clkreq", V_88F6920_PLUS),
MPP_VAR_FUNCTION(4, "spi1", "miso", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(5, "sd", "d1", V_88F6920_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d1", V_88F6920_PLUS),
MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6920_PLUS)),
MPP_MODE(59,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS),
MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6920_PLUS),
MPP_VAR_FUNCTION(2, "i2c1", "sda", V_88F6920_PLUS),
MPP_VAR_FUNCTION(4, "spi1", "cs0", V_88F6920_PLUS),
- MPP_VAR_FUNCTION(5, "sd", "d2", V_88F6920_PLUS)),
+ MPP_VAR_FUNCTION(5, "sd0", "d2", V_88F6920_PLUS)),
};
static struct mvebu_pinctrl_soc_info armada_39x_pinctrl_info;
@@ -368,6 +381,10 @@ static const struct of_device_id armada_39x_pinctrl_of_match[] = {
.data = (void *) V_88F6920,
},
{
+ .compatible = "marvell,mv88f6925-pinctrl",
+ .data = (void *) V_88F6925,
+ },
+ {
.compatible = "marvell,mv88f6928-pinctrl",
.data = (void *) V_88F6928,
},
@@ -380,7 +397,7 @@ static struct mvebu_mpp_ctrl armada_39x_mpp_controls[] = {
static struct pinctrl_gpio_range armada_39x_mpp_gpio_ranges[] = {
MPP_GPIO_RANGE(0, 0, 0, 32),
- MPP_GPIO_RANGE(1, 32, 32, 27),
+ MPP_GPIO_RANGE(1, 32, 32, 28),
};
static int armada_39x_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-xp.c b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
index 578db9f033b2..bf70e0953576 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
@@ -14,10 +14,7 @@
* available: mv78230, mv78260 and mv78460. From a pin muxing
* perspective, the mv78230 has 49 MPP pins. The mv78260 and mv78460
* both have 67 MPP pins (more GPIOs and address lines for the memory
- * bus mainly). The only difference between the mv78260 and the
- * mv78460 in terms of pin muxing is the addition of two functions on
- * pins 43 and 56 to access the VDD of the CPU2 and 3 (mv78260 has two
- * cores, mv78460 has four cores).
+ * bus mainly).
*/
#include <linux/err.h>
@@ -57,7 +54,7 @@ enum armada_xp_variant {
static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
MPP_MODE(0,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x1, "ge0", "txclko", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "txclkout", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x4, "lcd", "d0", V_MV78230_PLUS)),
MPP_MODE(1,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
@@ -106,17 +103,19 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
MPP_MODE(12,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "ge0", "txd4", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x2, "ge1", "clkout", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "ge1", "txclkout", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x4, "lcd", "d12", V_MV78230_PLUS)),
MPP_MODE(13,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "ge0", "txd5", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x2, "ge1", "txd0", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "spi1", "mosi", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x4, "lcd", "d13", V_MV78230_PLUS)),
MPP_MODE(14,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "ge0", "txd6", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x2, "ge1", "txd1", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "spi1", "sck", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x4, "lcd", "d14", V_MV78230_PLUS)),
MPP_MODE(15,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
@@ -127,11 +126,13 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "ge0", "txclk", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x2, "ge1", "txd3", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "spi1", "cs0", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x4, "lcd", "d16", V_MV78230_PLUS)),
MPP_MODE(17,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "ge0", "col", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x2, "ge1", "txctl", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "spi1", "miso", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x4, "lcd", "d17", V_MV78230_PLUS)),
MPP_MODE(18,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
@@ -155,7 +156,7 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "ge0", "rxd5", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x2, "ge1", "rxd3", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x3, "mem", "bat", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "dram", "bat", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x4, "lcd", "d21", V_MV78230_PLUS)),
MPP_MODE(22,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
@@ -172,20 +173,17 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
MPP_MODE(24,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "sata1", "prsnt", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x2, "nf", "bootcs-re", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x3, "tdm", "rst", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x4, "lcd", "hsync", V_MV78230_PLUS)),
MPP_MODE(25,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "sata0", "prsnt", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x2, "nf", "bootcs-we", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x3, "tdm", "pclk", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x4, "lcd", "vsync", V_MV78230_PLUS)),
MPP_MODE(26,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x3, "tdm", "fsync", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x4, "lcd", "clk", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x5, "vdd", "cpu1-pd", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x4, "lcd", "clk", V_MV78230_PLUS)),
MPP_MODE(27,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "ptp", "trig", V_MV78230_PLUS),
@@ -200,8 +198,7 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "ptp", "clk", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x3, "tdm", "int0", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x4, "lcd", "ref-clk", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x5, "vdd", "cpu0-pd", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x4, "lcd", "ref-clk", V_MV78230_PLUS)),
MPP_MODE(30,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "sd0", "clk", V_MV78230_PLUS),
@@ -209,23 +206,23 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
MPP_MODE(31,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "sd0", "cmd", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x3, "tdm", "int2", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x5, "vdd", "cpu0-pd", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x3, "tdm", "int2", V_MV78230_PLUS)),
MPP_MODE(32,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "sd0", "d0", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x3, "tdm", "int3", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x5, "vdd", "cpu1-pd", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x3, "tdm", "int3", V_MV78230_PLUS)),
MPP_MODE(33,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "sd0", "d1", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x3, "tdm", "int4", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x4, "mem", "bat", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x4, "dram", "bat", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x5, "dram", "vttctrl", V_MV78230_PLUS)),
MPP_MODE(34,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "sd0", "d2", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x2, "sata0", "prsnt", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x3, "tdm", "int5", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x3, "tdm", "int5", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "dram", "deccerr", V_MV78230_PLUS)),
MPP_MODE(35,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "sd0", "d3", V_MV78230_PLUS),
@@ -233,74 +230,80 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
MPP_VAR_FUNCTION(0x3, "tdm", "int6", V_MV78230_PLUS)),
MPP_MODE(36,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x1, "spi", "mosi", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x1, "spi0", "mosi", V_MV78230_PLUS)),
MPP_MODE(37,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x1, "spi", "miso", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x1, "spi0", "miso", V_MV78230_PLUS)),
MPP_MODE(38,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x1, "spi", "sck", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x1, "spi0", "sck", V_MV78230_PLUS)),
MPP_MODE(39,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x1, "spi", "cs0", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x1, "spi0", "cs0", V_MV78230_PLUS)),
MPP_MODE(40,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x1, "spi", "cs1", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "spi0", "cs1", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x2, "uart2", "cts", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x3, "vdd", "cpu1-pd", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x4, "lcd", "vga-hsync", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x5, "pcie", "clkreq0", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x5, "pcie", "clkreq0", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x6, "spi1", "cs1", V_MV78230_PLUS)),
MPP_MODE(41,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x1, "spi", "cs2", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "spi0", "cs2", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x2, "uart2", "rts", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x3, "sata1", "prsnt", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x4, "lcd", "vga-vsync", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x5, "pcie", "clkreq1", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x5, "pcie", "clkreq1", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x6, "spi1", "cs2", V_MV78230_PLUS)),
MPP_MODE(42,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "uart2", "rxd", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x2, "uart0", "cts", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x3, "tdm", "int7", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x4, "tdm-1", "timer", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x5, "vdd", "cpu0-pd", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x4, "tdm", "timer", V_MV78230_PLUS)),
MPP_MODE(43,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "uart2", "txd", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x2, "uart0", "rts", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x3, "spi", "cs3", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "spi0", "cs3", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x4, "pcie", "rstout", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x5, "vdd", "cpu2-3-pd", V_MV78460)),
+ MPP_VAR_FUNCTION(0x6, "spi1", "cs3", V_MV78230_PLUS)),
MPP_MODE(44,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "uart2", "cts", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x2, "uart3", "rxd", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x3, "spi", "cs4", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x4, "mem", "bat", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x5, "pcie", "clkreq2", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x3, "spi0", "cs4", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "dram", "bat", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x5, "pcie", "clkreq2", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x6, "spi1", "cs4", V_MV78230_PLUS)),
MPP_MODE(45,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "uart2", "rts", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x2, "uart3", "txd", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x3, "spi", "cs5", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x4, "sata1", "prsnt", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x3, "spi0", "cs5", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "sata1", "prsnt", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x5, "dram", "vttctrl", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x6, "spi1", "cs5", V_MV78230_PLUS)),
MPP_MODE(46,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "uart3", "rts", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x2, "uart1", "rts", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x3, "spi", "cs6", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x4, "sata0", "prsnt", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x3, "spi0", "cs6", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "sata0", "prsnt", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x6, "spi1", "cs6", V_MV78230_PLUS)),
MPP_MODE(47,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x1, "uart3", "cts", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x2, "uart1", "cts", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x3, "spi", "cs7", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "spi0", "cs7", V_MV78230_PLUS),
MPP_VAR_FUNCTION(0x4, "ref", "clkout", V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x5, "pcie", "clkreq3", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x5, "pcie", "clkreq3", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x6, "spi1", "cs7", V_MV78230_PLUS)),
MPP_MODE(48,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x1, "tclk", NULL, V_MV78230_PLUS),
- MPP_VAR_FUNCTION(0x2, "dev", "burst/last", V_MV78230_PLUS)),
+ MPP_VAR_FUNCTION(0x1, "dev", "clkout", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "dev", "burst/last", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "nand", "rb", V_MV78230_PLUS)),
MPP_MODE(49,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
MPP_VAR_FUNCTION(0x1, "dev", "we3", V_MV78260_PLUS)),
@@ -321,16 +324,13 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
MPP_VAR_FUNCTION(0x1, "dev", "ad19", V_MV78260_PLUS)),
MPP_MODE(55,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
- MPP_VAR_FUNCTION(0x1, "dev", "ad20", V_MV78260_PLUS),
- MPP_VAR_FUNCTION(0x2, "vdd", "cpu0-pd", V_MV78260_PLUS)),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad20", V_MV78260_PLUS)),
MPP_MODE(56,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
- MPP_VAR_FUNCTION(0x1, "dev", "ad21", V_MV78260_PLUS),
- MPP_VAR_FUNCTION(0x2, "vdd", "cpu1-pd", V_MV78260_PLUS)),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad21", V_MV78260_PLUS)),
MPP_MODE(57,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
- MPP_VAR_FUNCTION(0x1, "dev", "ad22", V_MV78260_PLUS),
- MPP_VAR_FUNCTION(0x2, "vdd", "cpu2-3-pd", V_MV78460)),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad22", V_MV78260_PLUS)),
MPP_MODE(58,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
MPP_VAR_FUNCTION(0x1, "dev", "ad23", V_MV78260_PLUS)),
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
index f3b426cdaf8f..77d2221d379d 100644
--- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
@@ -706,9 +706,9 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
}
pctl->pctldev = pinctrl_register(&pctl->desc, &pdev->dev, pctl);
- if (!pctl->pctldev) {
+ if (IS_ERR(pctl->pctldev)) {
dev_err(&pdev->dev, "unable to register pinctrl driver\n");
- return -EINVAL;
+ return PTR_ERR(pctl->pctldev);
}
dev_info(&pdev->dev, "registered pinctrl driver\n");
diff --git a/drivers/pinctrl/nomadik/pinctrl-ab8505.c b/drivers/pinctrl/nomadik/pinctrl-ab8505.c
index bf0ef4ac376f..42c6e1f7886b 100644
--- a/drivers/pinctrl/nomadik/pinctrl-ab8505.c
+++ b/drivers/pinctrl/nomadik/pinctrl-ab8505.c
@@ -286,7 +286,7 @@ alternate_functions ab8505_alternate_functions[AB8505_GPIO_MAX_NUMBER + 1] = {
ALTERNATE_FUNCTIONS(9, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO9, bit 0 reserved */
ALTERNATE_FUNCTIONS(10, 1, 0, UNUSED, 1, 0, 0), /* GPIO10, altA and altB controlled by bit 0 */
ALTERNATE_FUNCTIONS(11, 2, 1, UNUSED, 0, 0, 0), /* GPIO11, altA controlled by bit 2 */
- ALTERNATE_FUNCTIONS(12, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO12, bit3 reseved */
+ ALTERNATE_FUNCTIONS(12, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO12, bit3 reserved */
ALTERNATE_FUNCTIONS(13, 4, 3, 4, 1, 0, 2), /* GPIO13, altA altB and altC controlled by bit 3 and 4 */
ALTERNATE_FUNCTIONS(14, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */
ALTERNATE_FUNCTIONS(15, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO15, bit 6 reserved */
diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c
index 23db4c9ac76c..557d0f2a3031 100644
--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c
+++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c
@@ -787,6 +787,7 @@ static const struct pinmux_ops abx500_pinmux_ops = {
.set_mux = abx500_pmx_set,
.gpio_request_enable = abx500_gpio_request_enable,
.gpio_disable_free = abx500_gpio_disable_free,
+ .strict = true,
};
static int abx500_get_groups_cnt(struct pinctrl_dev *pctldev)
@@ -1234,10 +1235,10 @@ static int abx500_gpio_probe(struct platform_device *pdev)
abx500_pinctrl_desc.pins = pct->soc->pins;
abx500_pinctrl_desc.npins = pct->soc->npins;
pct->pctldev = pinctrl_register(&abx500_pinctrl_desc, &pdev->dev, pct);
- if (!pct->pctldev) {
+ if (IS_ERR(pct->pctldev)) {
dev_err(&pdev->dev,
"could not register abx500 pinctrl driver\n");
- ret = -EINVAL;
+ ret = PTR_ERR(pct->pctldev);
goto out_rem_chip;
}
dev_info(&pdev->dev, "registered pin controller\n");
diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
index a6a22054c0ba..809d88445db5 100644
--- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c
+++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
@@ -246,6 +246,7 @@ enum nmk_gpio_slpm {
struct nmk_gpio_chip {
struct gpio_chip chip;
+ struct irq_chip irqchip;
void __iomem *addr;
struct clk *clk;
unsigned int bank;
@@ -842,18 +843,6 @@ static void nmk_gpio_irq_shutdown(struct irq_data *d)
clk_disable(nmk_chip->clk);
}
-static struct irq_chip nmk_gpio_irq_chip = {
- .name = "Nomadik-GPIO",
- .irq_ack = nmk_gpio_irq_ack,
- .irq_mask = nmk_gpio_irq_mask,
- .irq_unmask = nmk_gpio_irq_unmask,
- .irq_set_type = nmk_gpio_irq_set_type,
- .irq_set_wake = nmk_gpio_irq_set_wake,
- .irq_startup = nmk_gpio_irq_startup,
- .irq_shutdown = nmk_gpio_irq_shutdown,
- .flags = IRQCHIP_MASK_ON_SUSPEND,
-};
-
static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
u32 status)
{
@@ -1077,18 +1066,6 @@ static inline void nmk_gpio_dbg_show_one(struct seq_file *s,
#define nmk_gpio_dbg_show NULL
#endif
-/* This structure is replicated for each GPIO block allocated at probe time */
-static struct gpio_chip nmk_gpio_template = {
- .request = nmk_gpio_request,
- .free = nmk_gpio_free,
- .direction_input = nmk_gpio_make_input,
- .get = nmk_gpio_get_input,
- .direction_output = nmk_gpio_make_output,
- .set = nmk_gpio_set_output,
- .dbg_show = nmk_gpio_dbg_show,
- .can_sleep = false,
-};
-
void nmk_gpio_clocks_enable(void)
{
int i;
@@ -1190,6 +1167,7 @@ static int nmk_gpio_probe(struct platform_device *dev)
struct device_node *np = dev->dev.of_node;
struct nmk_gpio_chip *nmk_chip;
struct gpio_chip *chip;
+ struct irq_chip *irqchip;
struct resource *res;
struct clk *clk;
int latent_irq;
@@ -1236,19 +1214,40 @@ static int nmk_gpio_probe(struct platform_device *dev)
nmk_chip->bank = dev->id;
nmk_chip->clk = clk;
nmk_chip->addr = base;
- nmk_chip->chip = nmk_gpio_template;
nmk_chip->parent_irq = irq;
nmk_chip->latent_parent_irq = latent_irq;
nmk_chip->sleepmode = supports_sleepmode;
spin_lock_init(&nmk_chip->lock);
chip = &nmk_chip->chip;
+ chip->request = nmk_gpio_request;
+ chip->free = nmk_gpio_free;
+ chip->direction_input = nmk_gpio_make_input;
+ chip->get = nmk_gpio_get_input;
+ chip->direction_output = nmk_gpio_make_output;
+ chip->set = nmk_gpio_set_output;
+ chip->dbg_show = nmk_gpio_dbg_show;
+ chip->can_sleep = false;
chip->base = dev->id * NMK_GPIO_PER_CHIP;
chip->ngpio = NMK_GPIO_PER_CHIP;
chip->label = dev_name(&dev->dev);
chip->dev = &dev->dev;
chip->owner = THIS_MODULE;
+ irqchip = &nmk_chip->irqchip;
+ irqchip->irq_ack = nmk_gpio_irq_ack;
+ irqchip->irq_mask = nmk_gpio_irq_mask;
+ irqchip->irq_unmask = nmk_gpio_irq_unmask;
+ irqchip->irq_set_type = nmk_gpio_irq_set_type;
+ irqchip->irq_set_wake = nmk_gpio_irq_set_wake;
+ irqchip->irq_startup = nmk_gpio_irq_startup;
+ irqchip->irq_shutdown = nmk_gpio_irq_shutdown;
+ irqchip->flags = IRQCHIP_MASK_ON_SUSPEND;
+ irqchip->name = kasprintf(GFP_KERNEL, "nmk%u-%u-%u",
+ dev->id,
+ chip->base,
+ chip->base + chip->ngpio - 1);
+
clk_enable(nmk_chip->clk);
nmk_chip->lowemi = readl_relaxed(nmk_chip->addr + NMK_GPIO_LOWEMI);
clk_disable(nmk_chip->clk);
@@ -1269,8 +1268,8 @@ static int nmk_gpio_probe(struct platform_device *dev)
* handler will perform the actual work of handling the parent
* interrupt.
*/
- ret = gpiochip_irqchip_add(&nmk_chip->chip,
- &nmk_gpio_irq_chip,
+ ret = gpiochip_irqchip_add(chip,
+ irqchip,
0,
handle_edge_irq,
IRQ_TYPE_EDGE_FALLING);
@@ -1280,13 +1279,13 @@ static int nmk_gpio_probe(struct platform_device *dev)
return -ENODEV;
}
/* Then register the chain on the parent IRQ */
- gpiochip_set_chained_irqchip(&nmk_chip->chip,
- &nmk_gpio_irq_chip,
+ gpiochip_set_chained_irqchip(chip,
+ irqchip,
nmk_chip->parent_irq,
nmk_gpio_irq_handler);
if (nmk_chip->latent_parent_irq > 0)
- gpiochip_set_chained_irqchip(&nmk_chip->chip,
- &nmk_gpio_irq_chip,
+ gpiochip_set_chained_irqchip(chip,
+ irqchip,
nmk_chip->latent_parent_irq,
nmk_gpio_latent_irq_handler);
@@ -1803,6 +1802,7 @@ static const struct pinmux_ops nmk_pinmux_ops = {
.set_mux = nmk_pmx_set,
.gpio_request_enable = nmk_gpio_request_enable,
.gpio_disable_free = nmk_gpio_disable_free,
+ .strict = true,
};
static int nmk_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
@@ -2029,9 +2029,9 @@ static int nmk_pinctrl_probe(struct platform_device *pdev)
npct->dev = &pdev->dev;
npct->pctl = pinctrl_register(&nmk_pinctrl_desc, &pdev->dev, npct);
- if (!npct->pctl) {
+ if (IS_ERR(npct->pctl)) {
dev_err(&pdev->dev, "could not register Nomadik pinctrl driver\n");
- return -EINVAL;
+ return PTR_ERR(npct->pctl);
}
/* We will handle a range of GPIO pins */
diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c
index 8434439c5017..873433da0f2c 100644
--- a/drivers/pinctrl/pinctrl-adi2.c
+++ b/drivers/pinctrl/pinctrl-adi2.c
@@ -703,6 +703,7 @@ static struct pinmux_ops adi_pinmux_ops = {
.get_function_name = adi_pinmux_get_func_name,
.get_function_groups = adi_pinmux_get_groups,
.gpio_request_enable = adi_pinmux_request_gpio,
+ .strict = true,
};
@@ -1069,9 +1070,9 @@ static int adi_pinctrl_probe(struct platform_device *pdev)
/* Now register the pin controller and all pins it handles */
pinctrl->pctl = pinctrl_register(&adi_pinmux_desc, &pdev->dev, pinctrl);
- if (!pinctrl->pctl) {
+ if (IS_ERR(pinctrl->pctl)) {
dev_err(&pdev->dev, "could not register pinctrl ADI2 driver\n");
- return -EINVAL;
+ return PTR_ERR(pinctrl->pctl);
}
platform_set_drvdata(pdev, pinctrl);
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index 7de3b64bf142..d8e3f7c7fea3 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -789,9 +789,9 @@ static int amd_gpio_probe(struct platform_device *pdev)
amd_pinctrl_desc.name = dev_name(&pdev->dev);
gpio_dev->pctrl = pinctrl_register(&amd_pinctrl_desc,
&pdev->dev, gpio_dev);
- if (!gpio_dev->pctrl) {
+ if (IS_ERR(gpio_dev->pctrl)) {
dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
- return -ENODEV;
+ return PTR_ERR(gpio_dev->pctrl);
}
ret = gpiochip_add(&gpio_dev->gc);
@@ -855,7 +855,6 @@ MODULE_DEVICE_TABLE(acpi, amd_gpio_acpi_match);
static struct platform_driver amd_gpio_driver = {
.driver = {
.name = "amd_gpio",
- .owner = THIS_MODULE,
.acpi_match_table = ACPI_PTR(amd_gpio_acpi_match),
},
.probe = amd_gpio_probe,
diff --git a/drivers/pinctrl/pinctrl-as3722.c b/drivers/pinctrl/pinctrl-as3722.c
index db0571ffbe99..4747e08f5389 100644
--- a/drivers/pinctrl/pinctrl-as3722.c
+++ b/drivers/pinctrl/pinctrl-as3722.c
@@ -586,9 +586,9 @@ static int as3722_pinctrl_probe(struct platform_device *pdev)
as3722_pinctrl_desc.npins = ARRAY_SIZE(as3722_pins_desc);
as_pci->pctl = pinctrl_register(&as3722_pinctrl_desc,
&pdev->dev, as_pci);
- if (!as_pci->pctl) {
+ if (IS_ERR(as_pci->pctl)) {
dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
- return -EINVAL;
+ return PTR_ERR(as_pci->pctl);
}
as_pci->gpio_chip = as3722_gpio_chip;
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 2f797cb7e205..a0824477072b 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -1238,9 +1238,9 @@ static int at91_pinctrl_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info);
info->pctl = pinctrl_register(&at91_pinctrl_desc, &pdev->dev, info);
- if (!info->pctl) {
+ if (IS_ERR(info->pctl)) {
dev_err(&pdev->dev, "could not register AT91 pinctrl driver\n");
- return -EINVAL;
+ return PTR_ERR(info->pctl);
}
/* We will handle a range of GPIO pins */
@@ -1326,6 +1326,21 @@ static void at91_gpio_set(struct gpio_chip *chip, unsigned offset,
writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR));
}
+static void at91_gpio_set_multiple(struct gpio_chip *chip,
+ unsigned long *mask, unsigned long *bits)
+{
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ void __iomem *pio = at91_gpio->regbase;
+
+#define BITS_MASK(bits) (((bits) == 32) ? ~0U : (BIT(bits) - 1))
+ /* Mask additionally to ngpio as not all GPIO controllers have 32 pins */
+ uint32_t set_mask = (*mask & *bits) & BITS_MASK(chip->ngpio);
+ uint32_t clear_mask = (*mask & ~(*bits)) & BITS_MASK(chip->ngpio);
+
+ writel_relaxed(set_mask, pio + PIO_SODR);
+ writel_relaxed(clear_mask, pio + PIO_CODR);
+}
+
static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int val)
{
@@ -1685,6 +1700,7 @@ static struct gpio_chip at91_gpio_template = {
.get = at91_gpio_get,
.direction_output = at91_gpio_direction_output,
.set = at91_gpio_set,
+ .set_multiple = at91_gpio_set_multiple,
.dbg_show = at91_gpio_dbg_show,
.can_sleep = false,
.ngpio = MAX_NB_GPIO_PER_BANK,
diff --git a/drivers/pinctrl/pinctrl-lantiq.c b/drivers/pinctrl/pinctrl-lantiq.c
index 296e5b37f768..fc38a8540544 100644
--- a/drivers/pinctrl/pinctrl-lantiq.c
+++ b/drivers/pinctrl/pinctrl-lantiq.c
@@ -337,9 +337,9 @@ int ltq_pinctrl_register(struct platform_device *pdev,
info->dev = &pdev->dev;
info->pctrl = pinctrl_register(desc, &pdev->dev, info);
- if (!info->pctrl) {
+ if (IS_ERR(info->pctrl)) {
dev_err(&pdev->dev, "failed to register LTQ pinmux driver\n");
- return -EINVAL;
+ return PTR_ERR(info->pctrl);
}
platform_set_drvdata(pdev, info);
return 0;
diff --git a/drivers/pinctrl/pinctrl-lpc18xx.c b/drivers/pinctrl/pinctrl-lpc18xx.c
new file mode 100644
index 000000000000..ef0b697639a7
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-lpc18xx.c
@@ -0,0 +1,1220 @@
+/*
+ * Pinctrl driver for NXP LPC18xx/LPC43xx System Control Unit (SCU)
+ *
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf-generic.h>
+
+#include "core.h"
+#include "pinctrl-utils.h"
+
+/* LPC18XX SCU analog function registers */
+#define LPC18XX_SCU_REG_ENAIO0 0xc88
+#define LPC18XX_SCU_REG_ENAIO1 0xc8c
+#define LPC18XX_SCU_REG_ENAIO2 0xc90
+#define LPC18XX_SCU_REG_ENAIO2_DAC BIT(0)
+
+/* LPC18XX SCU pin register definitions */
+#define LPC18XX_SCU_PIN_MODE_MASK 0x7
+#define LPC18XX_SCU_PIN_EPD BIT(3)
+#define LPC18XX_SCU_PIN_EPUN BIT(4)
+#define LPC18XX_SCU_PIN_EHS BIT(5)
+#define LPC18XX_SCU_PIN_EZI BIT(6)
+#define LPC18XX_SCU_PIN_ZIF BIT(7)
+#define LPC18XX_SCU_PIN_EHD_MASK 0x300
+#define LPC18XX_SCU_PIN_EHD_POS 8
+
+#define LPC18XX_SCU_I2C0_EFP BIT(0)
+#define LPC18XX_SCU_I2C0_EHD BIT(2)
+#define LPC18XX_SCU_I2C0_EZI BIT(3)
+#define LPC18XX_SCU_I2C0_ZIF BIT(7)
+#define LPC18XX_SCU_I2C0_SCL_SHIFT 0
+#define LPC18XX_SCU_I2C0_SDA_SHIFT 8
+
+#define LPC18XX_SCU_FUNC_PER_PIN 8
+
+/* LPC18xx pin types */
+enum {
+ TYPE_ND, /* Normal-drive */
+ TYPE_HD, /* High-drive */
+ TYPE_HS, /* High-speed */
+ TYPE_I2C0,
+ TYPE_USB1,
+};
+
+/* LPC18xx pin functions */
+enum {
+ FUNC_R, /* Reserved */
+ FUNC_ADC,
+ FUNC_ADCTRIG,
+ FUNC_CAN0,
+ FUNC_CAN1,
+ FUNC_CGU_OUT,
+ FUNC_CLKIN,
+ FUNC_CLKOUT,
+ FUNC_CTIN,
+ FUNC_CTOUT,
+ FUNC_DAC,
+ FUNC_EMC,
+ FUNC_EMC_ALT,
+ FUNC_ENET,
+ FUNC_ENET_ALT,
+ FUNC_GPIO,
+ FUNC_I2C0,
+ FUNC_I2C1,
+ FUNC_I2S0_RX_MCLK,
+ FUNC_I2S0_RX_SCK,
+ FUNC_I2S0_RX_SDA,
+ FUNC_I2S0_RX_WS,
+ FUNC_I2S0_TX_MCLK,
+ FUNC_I2S0_TX_SCK,
+ FUNC_I2S0_TX_SDA,
+ FUNC_I2S0_TX_WS,
+ FUNC_I2S1,
+ FUNC_LCD,
+ FUNC_LCD_ALT,
+ FUNC_MCTRL,
+ FUNC_NMI,
+ FUNC_QEI,
+ FUNC_SDMMC,
+ FUNC_SGPIO,
+ FUNC_SPI,
+ FUNC_SPIFI,
+ FUNC_SSP0,
+ FUNC_SSP0_ALT,
+ FUNC_SSP1,
+ FUNC_TIMER0,
+ FUNC_TIMER1,
+ FUNC_TIMER2,
+ FUNC_TIMER3,
+ FUNC_TRACE,
+ FUNC_UART0,
+ FUNC_UART1,
+ FUNC_UART2,
+ FUNC_UART3,
+ FUNC_USB0,
+ FUNC_USB1,
+ FUNC_MAX
+};
+
+static const char *const lpc18xx_function_names[] = {
+ [FUNC_R] = "reserved",
+ [FUNC_ADC] = "adc",
+ [FUNC_ADCTRIG] = "adctrig",
+ [FUNC_CAN0] = "can0",
+ [FUNC_CAN1] = "can1",
+ [FUNC_CGU_OUT] = "cgu_out",
+ [FUNC_CLKIN] = "clkin",
+ [FUNC_CLKOUT] = "clkout",
+ [FUNC_CTIN] = "ctin",
+ [FUNC_CTOUT] = "ctout",
+ [FUNC_DAC] = "dac",
+ [FUNC_EMC] = "emc",
+ [FUNC_EMC_ALT] = "emc_alt",
+ [FUNC_ENET] = "enet",
+ [FUNC_ENET_ALT] = "enet_alt",
+ [FUNC_GPIO] = "gpio",
+ [FUNC_I2C0] = "i2c0",
+ [FUNC_I2C1] = "i2c1",
+ [FUNC_I2S0_RX_MCLK] = "i2s0_rx_mclk",
+ [FUNC_I2S0_RX_SCK] = "i2s0_rx_sck",
+ [FUNC_I2S0_RX_SDA] = "i2s0_rx_sda",
+ [FUNC_I2S0_RX_WS] = "i2s0_rx_ws",
+ [FUNC_I2S0_TX_MCLK] = "i2s0_tx_mclk",
+ [FUNC_I2S0_TX_SCK] = "i2s0_tx_sck",
+ [FUNC_I2S0_TX_SDA] = "i2s0_tx_sda",
+ [FUNC_I2S0_TX_WS] = "i2s0_tx_ws",
+ [FUNC_I2S1] = "i2s1",
+ [FUNC_LCD] = "lcd",
+ [FUNC_LCD_ALT] = "lcd_alt",
+ [FUNC_MCTRL] = "mctrl",
+ [FUNC_NMI] = "nmi",
+ [FUNC_QEI] = "qei",
+ [FUNC_SDMMC] = "sdmmc",
+ [FUNC_SGPIO] = "sgpio",
+ [FUNC_SPI] = "spi",
+ [FUNC_SPIFI] = "spifi",
+ [FUNC_SSP0] = "ssp0",
+ [FUNC_SSP0_ALT] = "ssp0_alt",
+ [FUNC_SSP1] = "ssp1",
+ [FUNC_TIMER0] = "timer0",
+ [FUNC_TIMER1] = "timer1",
+ [FUNC_TIMER2] = "timer2",
+ [FUNC_TIMER3] = "timer3",
+ [FUNC_TRACE] = "trace",
+ [FUNC_UART0] = "uart0",
+ [FUNC_UART1] = "uart1",
+ [FUNC_UART2] = "uart2",
+ [FUNC_UART3] = "uart3",
+ [FUNC_USB0] = "usb0",
+ [FUNC_USB1] = "usb1",
+};
+
+struct lpc18xx_pmx_func {
+ const char **groups;
+ unsigned ngroups;
+};
+
+struct lpc18xx_scu_data {
+ struct pinctrl_dev *pctl;
+ void __iomem *base;
+ struct clk *clk;
+ struct lpc18xx_pmx_func func[FUNC_MAX];
+};
+
+struct lpc18xx_pin_caps {
+ unsigned int offset;
+ unsigned char functions[LPC18XX_SCU_FUNC_PER_PIN];
+ unsigned char analog;
+ unsigned char type;
+};
+
+/* Analog pins are required to have both bias and input disabled */
+#define LPC18XX_SCU_ANALOG_PIN_CFG 0x10
+
+/* Macros to maniupluate analog member in lpc18xx_pin_caps */
+#define LPC18XX_ANALOG_PIN BIT(7)
+#define LPC18XX_ANALOG_ADC(a) ((a >> 5) & 0x3)
+#define LPC18XX_ANALOG_BIT_MASK 0x1f
+#define ADC0 (LPC18XX_ANALOG_PIN | (0x00 << 5))
+#define ADC1 (LPC18XX_ANALOG_PIN | (0x01 << 5))
+#define DAC LPC18XX_ANALOG_PIN
+
+#define LPC_P(port, pin, f0, f1, f2, f3, f4, f5, f6, f7, a, t) \
+static struct lpc18xx_pin_caps lpc18xx_pin_p##port##_##pin = { \
+ .offset = 0x##port * 32 * 4 + pin * 4, \
+ .functions = { \
+ FUNC_##f0, FUNC_##f1, FUNC_##f2, \
+ FUNC_##f3, FUNC_##f4, FUNC_##f5, \
+ FUNC_##f6, FUNC_##f7, \
+ }, \
+ .analog = a, \
+ .type = TYPE_##t, \
+}
+
+#define LPC_N(pname, off, f0, f1, f2, f3, f4, f5, f6, f7, a, t) \
+static struct lpc18xx_pin_caps lpc18xx_pin_##pname = { \
+ .offset = off, \
+ .functions = { \
+ FUNC_##f0, FUNC_##f1, FUNC_##f2, \
+ FUNC_##f3, FUNC_##f4, FUNC_##f5, \
+ FUNC_##f6, FUNC_##f7, \
+ }, \
+ .analog = a, \
+ .type = TYPE_##t, \
+}
+
+
+/* Pinmuxing table taken from data sheet */
+/* Pin FUNC0 FUNC1 FUNC2 FUNC3 FUNC4 FUNC5 FUNC6 FUNC7 ANALOG TYPE */
+LPC_P(0,0, GPIO, SSP1, ENET, SGPIO, R, R, I2S0_TX_WS,I2S1, 0, ND);
+LPC_P(0,1, GPIO, SSP1,ENET_ALT,SGPIO, R, R, ENET, I2S1, 0, ND);
+LPC_P(1,0, GPIO, CTIN, EMC, R, R, SSP0, SGPIO, R, 0, ND);
+LPC_P(1,1, GPIO, CTOUT, EMC, SGPIO, R, SSP0, R, R, 0, ND);
+LPC_P(1,2, GPIO, CTOUT, EMC, SGPIO, R, SSP0, R, R, 0, ND);
+LPC_P(1,3, GPIO, CTOUT, SGPIO, EMC, USB0, SSP1, R, SDMMC, 0, ND);
+LPC_P(1,4, GPIO, CTOUT, SGPIO, EMC, USB0, SSP1, R, SDMMC, 0, ND);
+LPC_P(1,5, GPIO, CTOUT, R, EMC, USB0, SSP1, SGPIO, SDMMC, 0, ND);
+LPC_P(1,6, GPIO, CTIN, R, EMC, R, R, SGPIO, SDMMC, 0, ND);
+LPC_P(1,7, GPIO, UART1, CTOUT, EMC, USB0, R, R, R, 0, ND);
+LPC_P(1,8, GPIO, UART1, CTOUT, EMC, R, R, R, SDMMC, 0, ND);
+LPC_P(1,9, GPIO, UART1, CTOUT, EMC, R, R, R, SDMMC, 0, ND);
+LPC_P(1,10, GPIO, UART1, CTOUT, EMC, R, R, R, SDMMC, 0, ND);
+LPC_P(1,11, GPIO, UART1, CTOUT, EMC, R, R, R, SDMMC, 0, ND);
+LPC_P(1,12, GPIO, UART1, R, EMC, TIMER0, R, SGPIO, SDMMC, 0, ND);
+LPC_P(1,13, GPIO, UART1, R, EMC, TIMER0, R, SGPIO, SDMMC, 0, ND);
+LPC_P(1,14, GPIO, UART1, R, EMC, TIMER0, R, SGPIO, R, 0, ND);
+LPC_P(1,15, GPIO, UART2, SGPIO, ENET, TIMER0, R, R, R, 0, ND);
+LPC_P(1,16, GPIO, UART2, SGPIO,ENET_ALT,TIMER0, R, R, ENET, 0, ND);
+LPC_P(1,17, GPIO, UART2, R, ENET, TIMER0, CAN1, SGPIO, R, 0, HD);
+LPC_P(1,18, GPIO, UART2, R, ENET, TIMER0, CAN1, SGPIO, R, 0, ND);
+LPC_P(1,19, ENET, SSP1, R, R, CLKOUT, R, I2S0_RX_MCLK,I2S1, 0, ND);
+LPC_P(1,20, GPIO, SSP1, R, ENET, TIMER0, R, SGPIO, R, 0, ND);
+LPC_P(2,0, SGPIO, UART0, EMC, USB0, GPIO, R, TIMER3, ENET, 0, ND);
+LPC_P(2,1, SGPIO, UART0, EMC, USB0, GPIO, R, TIMER3, R, 0, ND);
+LPC_P(2,2, SGPIO, UART0, EMC, USB0, GPIO, CTIN, TIMER3, R, 0, ND);
+LPC_P(2,3, SGPIO, I2C1, UART3, CTIN, GPIO, R, TIMER3, USB0, 0, HD);
+LPC_P(2,4, SGPIO, I2C1, UART3, CTIN, GPIO, R, TIMER3, USB0, 0, HD);
+LPC_P(2,5, SGPIO, CTIN, USB1, ADCTRIG, GPIO, R, TIMER3, USB0, 0, HD);
+LPC_P(2,6, SGPIO, UART0, EMC, USB0, GPIO, CTIN, TIMER3, R, 0, ND);
+LPC_P(2,7, GPIO, CTOUT, UART3, EMC, R, R, TIMER3, R, 0, ND);
+LPC_P(2,8, SGPIO, CTOUT, UART3, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(2,9, GPIO, CTOUT, UART3, EMC, R, R, R, R, 0, ND);
+LPC_P(2,10, GPIO, CTOUT, UART2, EMC, R, R, R, R, 0, ND);
+LPC_P(2,11, GPIO, CTOUT, UART2, EMC, R, R, R, R, 0, ND);
+LPC_P(2,12, GPIO, CTOUT, R, EMC, R, R, R, UART2, 0, ND);
+LPC_P(2,13, GPIO, CTIN, R, EMC, R, R, R, UART2, 0, ND);
+LPC_P(3,0, I2S0_RX_SCK, I2S0_RX_MCLK, I2S0_TX_SCK, I2S0_TX_MCLK,SSP0,R,R,R, 0, ND);
+LPC_P(3,1, I2S0_TX_WS, I2S0_RX_WS,CAN0,USB1,GPIO, R, LCD, R, 0, ND);
+LPC_P(3,2, I2S0_TX_SDA, I2S0_RX_SDA,CAN0,USB1,GPIO, R, LCD, R, 0, ND);
+LPC_P(3,3, R, SPI, SSP0, SPIFI, CGU_OUT,R, I2S0_TX_MCLK, I2S1, 0, HS);
+LPC_P(3,4, GPIO, R, R, SPIFI, UART1, I2S0_TX_WS, I2S1, LCD, 0, ND);
+LPC_P(3,5, GPIO, R, R, SPIFI, UART1, I2S0_TX_SDA,I2S1, LCD, 0, ND);
+LPC_P(3,6, GPIO, SPI, SSP0, SPIFI, R, SSP0_ALT, R, R, 0, ND);
+LPC_P(3,7, R, SPI, SSP0, SPIFI, GPIO, SSP0_ALT, R, R, 0, ND);
+LPC_P(3,8, R, SPI, SSP0, SPIFI, GPIO, SSP0_ALT, R, R, 0, ND);
+LPC_P(4,0, GPIO, MCTRL, NMI, R, R, LCD, UART3, R, 0, ND);
+LPC_P(4,1, GPIO, CTOUT, LCD, R, R, LCD_ALT, UART3, ENET, ADC0|1, ND);
+LPC_P(4,2, GPIO, CTOUT, LCD, R, R, LCD_ALT, UART3, SGPIO, 0, ND);
+LPC_P(4,3, GPIO, CTOUT, LCD, R, R, LCD_ALT, UART3, SGPIO, ADC0|0, ND);
+LPC_P(4,4, GPIO, CTOUT, LCD, R, R, LCD_ALT, UART3, SGPIO, DAC, ND);
+LPC_P(4,5, GPIO, CTOUT, LCD, R, R, R, R, SGPIO, 0, ND);
+LPC_P(4,6, GPIO, CTOUT, LCD, R, R, R, R, SGPIO, 0, ND);
+LPC_P(4,7, LCD, CLKIN, R, R, R, R, I2S1,I2S0_TX_SCK, 0, ND);
+LPC_P(4,8, R, CTIN, LCD, R, GPIO, LCD_ALT, CAN1, SGPIO, 0, ND);
+LPC_P(4,9, R, CTIN, LCD, R, GPIO, LCD_ALT, CAN1, SGPIO, 0, ND);
+LPC_P(4,10, R, CTIN, LCD, R, GPIO, LCD_ALT, R, SGPIO, 0, ND);
+LPC_P(5,0, GPIO, MCTRL, EMC, R, UART1, TIMER1, R, R, 0, ND);
+LPC_P(5,1, GPIO, MCTRL, EMC, R, UART1, TIMER1, R, R, 0, ND);
+LPC_P(5,2, GPIO, MCTRL, EMC, R, UART1, TIMER1, R, R, 0, ND);
+LPC_P(5,3, GPIO, MCTRL, EMC, R, UART1, TIMER1, R, R, 0, ND);
+LPC_P(5,4, GPIO, MCTRL, EMC, R, UART1, TIMER1, R, R, 0, ND);
+LPC_P(5,5, GPIO, MCTRL, EMC, R, UART1, TIMER1, R, R, 0, ND);
+LPC_P(5,6, GPIO, MCTRL, EMC, R, UART1, TIMER1, R, R, 0, ND);
+LPC_P(5,7, GPIO, MCTRL, EMC, R, UART1, TIMER1, R, R, 0, ND);
+LPC_P(6,0, R, I2S0_RX_MCLK,R, R, I2S0_RX_SCK, R, R, R, 0, ND);
+LPC_P(6,1, GPIO, EMC, UART0, I2S0_RX_WS, R, TIMER2, R, R, 0, ND);
+LPC_P(6,2, GPIO, EMC, UART0, I2S0_RX_SDA, R, TIMER2, R, R, 0, ND);
+LPC_P(6,3, GPIO, USB0, SGPIO, EMC, R, TIMER2, R, R, 0, ND);
+LPC_P(6,4, GPIO, CTIN, UART0, EMC, R, R, R, R, 0, ND);
+LPC_P(6,5, GPIO, CTOUT, UART0, EMC, R, R, R, R, 0, ND);
+LPC_P(6,6, GPIO, EMC, SGPIO, USB0, R, TIMER2, R, R, 0, ND);
+LPC_P(6,7, R, EMC, SGPIO, USB0, GPIO, TIMER2, R, R, 0, ND);
+LPC_P(6,8, R, EMC, SGPIO, USB0, GPIO, TIMER2, R, R, 0, ND);
+LPC_P(6,9, GPIO, R, R, EMC, R, TIMER2, R, R, 0, ND);
+LPC_P(6,10, GPIO, MCTRL, R, EMC, R, R, R, R, 0, ND);
+LPC_P(6,11, GPIO, R, R, EMC, R, TIMER2, R, R, 0, ND);
+LPC_P(6,12, GPIO, CTOUT, R, EMC, R, R, R, R, 0, ND);
+LPC_P(7,0, GPIO, CTOUT, R, LCD, R, R, R, SGPIO, 0, ND);
+LPC_P(7,1, GPIO, CTOUT,I2S0_TX_WS,LCD,LCD_ALT, R, UART2, SGPIO, 0, ND);
+LPC_P(7,2, GPIO, CTIN,I2S0_TX_SDA,LCD,LCD_ALT, R, UART2, SGPIO, 0, ND);
+LPC_P(7,3, GPIO, CTIN, R, LCD,LCD_ALT, R, R, R, 0, ND);
+LPC_P(7,4, GPIO, CTOUT, R, LCD,LCD_ALT, TRACE, R, R, ADC0|4, ND);
+LPC_P(7,5, GPIO, CTOUT, R, LCD,LCD_ALT, TRACE, R, R, ADC0|3, ND);
+LPC_P(7,6, GPIO, CTOUT, R, LCD, R, TRACE, R, R, 0, ND);
+LPC_P(7,7, GPIO, CTOUT, R, LCD, R, TRACE, ENET, SGPIO, ADC1|6, ND);
+LPC_P(8,0, GPIO, USB0, R, MCTRL, SGPIO, R, R, TIMER0, 0, HD);
+LPC_P(8,1, GPIO, USB0, R, MCTRL, SGPIO, R, R, TIMER0, 0, HD);
+LPC_P(8,2, GPIO, USB0, R, MCTRL, SGPIO, R, R, TIMER0, 0, HD);
+LPC_P(8,3, GPIO, USB1, R, LCD, LCD_ALT, R, R, TIMER0, 0, ND);
+LPC_P(8,4, GPIO, USB1, R, LCD, LCD_ALT, R, R, TIMER0, 0, ND);
+LPC_P(8,5, GPIO, USB1, R, LCD, LCD_ALT, R, R, TIMER0, 0, ND);
+LPC_P(8,6, GPIO, USB1, R, LCD, LCD_ALT, R, R, TIMER0, 0, ND);
+LPC_P(8,7, GPIO, USB1, R, LCD, LCD_ALT, R, R, TIMER0, 0, ND);
+LPC_P(8,8, R, USB1, R, R, R, R,CGU_OUT, I2S1, 0, ND);
+LPC_P(9,0, GPIO, MCTRL, R, R, R, ENET, SGPIO, SSP0, 0, ND);
+LPC_P(9,1, GPIO, MCTRL, R, R, I2S0_TX_WS,ENET, SGPIO, SSP0, 0, ND);
+LPC_P(9,2, GPIO, MCTRL, R, R, I2S0_TX_SDA,ENET,SGPIO, SSP0, 0, ND);
+LPC_P(9,3, GPIO, MCTRL, USB1, R, R, ENET, SGPIO, UART3, 0, ND);
+LPC_P(9,4, R, MCTRL, USB1, R, GPIO, ENET, SGPIO, UART3, 0, ND);
+LPC_P(9,5, R, MCTRL, USB1, R, GPIO, ENET, SGPIO, UART0, 0, ND);
+LPC_P(9,6, GPIO, MCTRL, USB1, R, R, ENET, SGPIO, UART0, 0, ND);
+LPC_P(a,0, R, R, R, R, R, I2S1, CGU_OUT, R, 0, ND);
+LPC_P(a,1, GPIO, QEI, R, UART2, R, R, R, R, 0, HD);
+LPC_P(a,2, GPIO, QEI, R, UART2, R, R, R, R, 0, HD);
+LPC_P(a,3, GPIO, QEI, R, R, R, R, R, R, 0, HD);
+LPC_P(a,4, R, CTOUT, R, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(b,0, R, CTOUT, LCD, R, GPIO, R, R, R, 0, ND);
+LPC_P(b,1, R, USB1, LCD, R, GPIO, CTOUT, R, R, 0, ND);
+LPC_P(b,2, R, USB1, LCD, R, GPIO, CTOUT, R, R, 0, ND);
+LPC_P(b,3, R, USB1, LCD, R, GPIO, CTOUT, R, R, 0, ND);
+LPC_P(b,4, R, USB1, LCD, R, GPIO, CTIN, R, R, 0, ND);
+LPC_P(b,5, R, USB1, LCD, R, GPIO, CTIN, LCD_ALT, R, 0, ND);
+LPC_P(b,6, R, USB1, LCD, R, GPIO, CTIN, LCD_ALT, R, ADC0|6, ND);
+LPC_P(c,0, R, USB1, R, ENET, LCD, R, R, SDMMC, ADC1|1, ND);
+LPC_P(c,1, USB1, R, UART1, ENET, GPIO, R, TIMER3, SDMMC, 0, ND);
+LPC_P(c,2, USB1, R, UART1, ENET, GPIO, R, R, SDMMC, 0, ND);
+LPC_P(c,3, USB1, R, UART1, ENET, GPIO, R, R, SDMMC, ADC1|0, ND);
+LPC_P(c,4, R, USB1, R, ENET, GPIO, R, TIMER3, SDMMC, 0, ND);
+LPC_P(c,5, R, USB1, R, ENET, GPIO, R, TIMER3, SDMMC, 0, ND);
+LPC_P(c,6, R, USB1, R, ENET, GPIO, R, TIMER3, SDMMC, 0, ND);
+LPC_P(c,7, R, USB1, R, ENET, GPIO, R, TIMER3, SDMMC, 0, ND);
+LPC_P(c,8, R, USB1, R, ENET, GPIO, R, TIMER3, SDMMC, 0, ND);
+LPC_P(c,9, R, USB1, R, ENET, GPIO, R, TIMER3, SDMMC, 0, ND);
+LPC_P(c,10, R, USB1, UART1, R, GPIO, R, TIMER3, SDMMC, 0, ND);
+LPC_P(c,11, R, USB1, UART1, R, GPIO, R, R, SDMMC, 0, ND);
+LPC_P(c,12, R, R, UART1, R, GPIO, SGPIO, I2S0_TX_SDA,SDMMC, 0, ND);
+LPC_P(c,13, R, R, UART1, R, GPIO, SGPIO, I2S0_TX_WS, SDMMC, 0, ND);
+LPC_P(c,14, R, R, UART1, R, GPIO, SGPIO, ENET, SDMMC, 0, ND);
+LPC_P(d,0, R, CTOUT, EMC, R, GPIO, R, R, SGPIO, 0, ND);
+LPC_P(d,1, R, R, EMC, R, GPIO, SDMMC, R, SGPIO, 0, ND);
+LPC_P(d,2, R, CTOUT, EMC, R, GPIO, R, R, SGPIO, 0, ND);
+LPC_P(d,3, R, CTOUT, EMC, R, GPIO, R, R, SGPIO, 0, ND);
+LPC_P(d,4, R, CTOUT, EMC, R, GPIO, R, R, SGPIO, 0, ND);
+LPC_P(d,5, R, CTOUT, EMC, R, GPIO, R, R, SGPIO, 0, ND);
+LPC_P(d,6, R, CTOUT, EMC, R, GPIO, R, R, SGPIO, 0, ND);
+LPC_P(d,7, R, CTIN, EMC, R, GPIO, R, R, SGPIO, 0, ND);
+LPC_P(d,8, R, CTIN, EMC, R, GPIO, R, R, SGPIO, 0, ND);
+LPC_P(d,9, R, CTOUT, EMC, R, GPIO, R, R, SGPIO, 0, ND);
+LPC_P(d,10, R, CTIN, EMC, R, GPIO, R, R, R, 0, ND);
+LPC_P(d,11, R, R, EMC, R, GPIO, USB1, CTOUT, R, 0, ND);
+LPC_P(d,12, R, R, EMC, R, GPIO, R, CTOUT, R, 0, ND);
+LPC_P(d,13, R, CTIN, EMC, R, GPIO, R, CTOUT, R, 0, ND);
+LPC_P(d,14, R, R, EMC, R, GPIO, R, CTOUT, R, 0, ND);
+LPC_P(d,15, R, R, EMC, R, GPIO, SDMMC, CTOUT, R, 0, ND);
+LPC_P(d,16, R, R, EMC, R, GPIO, SDMMC, CTOUT, R, 0, ND);
+LPC_P(e,0, R, R, R, EMC, GPIO, CAN1, R, R, 0, ND);
+LPC_P(e,1, R, R, R, EMC, GPIO, CAN1, R, R, 0, ND);
+LPC_P(e,2,ADCTRIG, CAN0, R, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(e,3, R, CAN0,ADCTRIG, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(e,4, R, NMI, R, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(e,5, R, CTOUT, UART1, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(e,6, R, CTOUT, UART1, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(e,7, R, CTOUT, UART1, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(e,8, R, CTOUT, UART1, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(e,9, R, CTIN, UART1, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(e,10, R, CTIN, UART1, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(e,11, R, CTOUT, UART1, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(e,12, R, CTOUT, UART1, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(e,13, R, CTOUT, I2C1, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(e,14, R, R, R, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(e,15, R, CTOUT, I2C1, EMC, GPIO, R, R, R, 0, ND);
+LPC_P(f,0, SSP0, CLKIN, R, R, R, R, R, I2S1, 0, ND);
+LPC_P(f,1, R, R, SSP0, R, GPIO, R, SGPIO, R, 0, ND);
+LPC_P(f,2, R, UART3, SSP0, R, GPIO, R, SGPIO, R, 0, ND);
+LPC_P(f,3, R, UART3, SSP0, R, GPIO, R, SGPIO, R, 0, ND);
+LPC_P(f,4, SSP1, CLKIN, TRACE, R, R, R, I2S0_TX_MCLK,I2S0_RX_SCK, 0, ND);
+LPC_P(f,5, R, UART3, SSP1, TRACE, GPIO, R, SGPIO, R, ADC1|4, ND);
+LPC_P(f,6, R, UART3, SSP1, TRACE, GPIO, R, SGPIO, I2S1, ADC1|3, ND);
+LPC_P(f,7, R, UART3, SSP1, TRACE, GPIO, R, SGPIO, I2S1, ADC1|7, ND);
+LPC_P(f,8, R, UART0, CTIN, TRACE, GPIO, R, SGPIO, R, ADC0|2, ND);
+LPC_P(f,9, R, UART0, CTOUT, R, GPIO, R, SGPIO, R, ADC1|2, ND);
+LPC_P(f,10, R, UART0, R, R, GPIO, R, SDMMC, R, ADC0|5, ND);
+LPC_P(f,11, R, UART0, R, R, GPIO, R, SDMMC, R, ADC1|5, ND);
+
+/* Pin Offset FUNC0 FUNC1 FUNC2 FUNC3 FUNC4 FUNC5 FUNC6 FUNC7 ANALOG TYPE */
+LPC_N(clk0, 0xc00, EMC, CLKOUT, R, R, SDMMC, EMC_ALT, SSP1, ENET, 0, HS);
+LPC_N(clk1, 0xc04, EMC, CLKOUT, R, R, R, CGU_OUT, R, I2S1, 0, HS);
+LPC_N(clk2, 0xc08, EMC, CLKOUT, R, R, SDMMC, EMC_ALT,I2S0_TX_MCLK,I2S1, 0, HS);
+LPC_N(clk3, 0xc0c, EMC, CLKOUT, R, R, R, CGU_OUT, R, I2S1, 0, HS);
+LPC_N(usb1_dm, 0xc80, R, R, R, R, R, R, R, R, 0, USB1);
+LPC_N(usb1_dp, 0xc80, R, R, R, R, R, R, R, R, 0, USB1);
+LPC_N(i2c0_scl, 0xc84, R, R, R, R, R, R, R, R, 0, I2C0);
+LPC_N(i2c0_sda, 0xc84, R, R, R, R, R, R, R, R, 0, I2C0);
+
+#define LPC18XX_PIN_P(port, pin) { \
+ .number = 0x##port * 32 + pin, \
+ .name = "p"#port"_"#pin, \
+ .drv_data = &lpc18xx_pin_p##port##_##pin \
+}
+
+/* Pin numbers for special pins */
+enum {
+ PIN_CLK0 = 600,
+ PIN_CLK1,
+ PIN_CLK2,
+ PIN_CLK3,
+ PIN_USB1_DM,
+ PIN_USB1_DP,
+ PIN_I2C0_SCL,
+ PIN_I2C0_SDA,
+};
+
+#define LPC18XX_PIN(pname, n) { \
+ .number = n, \
+ .name = #pname, \
+ .drv_data = &lpc18xx_pin_##pname \
+}
+
+static const struct pinctrl_pin_desc lpc18xx_pins[] = {
+ LPC18XX_PIN_P(0,0),
+ LPC18XX_PIN_P(0,1),
+ LPC18XX_PIN_P(1,0),
+ LPC18XX_PIN_P(1,1),
+ LPC18XX_PIN_P(1,2),
+ LPC18XX_PIN_P(1,3),
+ LPC18XX_PIN_P(1,4),
+ LPC18XX_PIN_P(1,5),
+ LPC18XX_PIN_P(1,6),
+ LPC18XX_PIN_P(1,7),
+ LPC18XX_PIN_P(1,8),
+ LPC18XX_PIN_P(1,9),
+ LPC18XX_PIN_P(1,10),
+ LPC18XX_PIN_P(1,11),
+ LPC18XX_PIN_P(1,12),
+ LPC18XX_PIN_P(1,13),
+ LPC18XX_PIN_P(1,14),
+ LPC18XX_PIN_P(1,15),
+ LPC18XX_PIN_P(1,16),
+ LPC18XX_PIN_P(1,17),
+ LPC18XX_PIN_P(1,18),
+ LPC18XX_PIN_P(1,19),
+ LPC18XX_PIN_P(1,20),
+ LPC18XX_PIN_P(2,0),
+ LPC18XX_PIN_P(2,1),
+ LPC18XX_PIN_P(2,2),
+ LPC18XX_PIN_P(2,3),
+ LPC18XX_PIN_P(2,4),
+ LPC18XX_PIN_P(2,5),
+ LPC18XX_PIN_P(2,6),
+ LPC18XX_PIN_P(2,7),
+ LPC18XX_PIN_P(2,8),
+ LPC18XX_PIN_P(2,9),
+ LPC18XX_PIN_P(2,10),
+ LPC18XX_PIN_P(2,11),
+ LPC18XX_PIN_P(2,12),
+ LPC18XX_PIN_P(2,13),
+ LPC18XX_PIN_P(3,0),
+ LPC18XX_PIN_P(3,1),
+ LPC18XX_PIN_P(3,2),
+ LPC18XX_PIN_P(3,3),
+ LPC18XX_PIN_P(3,4),
+ LPC18XX_PIN_P(3,5),
+ LPC18XX_PIN_P(3,6),
+ LPC18XX_PIN_P(3,7),
+ LPC18XX_PIN_P(3,8),
+ LPC18XX_PIN_P(4,0),
+ LPC18XX_PIN_P(4,1),
+ LPC18XX_PIN_P(4,2),
+ LPC18XX_PIN_P(4,3),
+ LPC18XX_PIN_P(4,4),
+ LPC18XX_PIN_P(4,5),
+ LPC18XX_PIN_P(4,6),
+ LPC18XX_PIN_P(4,7),
+ LPC18XX_PIN_P(4,8),
+ LPC18XX_PIN_P(4,9),
+ LPC18XX_PIN_P(4,10),
+ LPC18XX_PIN_P(5,0),
+ LPC18XX_PIN_P(5,1),
+ LPC18XX_PIN_P(5,2),
+ LPC18XX_PIN_P(5,3),
+ LPC18XX_PIN_P(5,4),
+ LPC18XX_PIN_P(5,5),
+ LPC18XX_PIN_P(5,6),
+ LPC18XX_PIN_P(5,7),
+ LPC18XX_PIN_P(6,0),
+ LPC18XX_PIN_P(6,1),
+ LPC18XX_PIN_P(6,2),
+ LPC18XX_PIN_P(6,3),
+ LPC18XX_PIN_P(6,4),
+ LPC18XX_PIN_P(6,5),
+ LPC18XX_PIN_P(6,6),
+ LPC18XX_PIN_P(6,7),
+ LPC18XX_PIN_P(6,8),
+ LPC18XX_PIN_P(6,9),
+ LPC18XX_PIN_P(6,10),
+ LPC18XX_PIN_P(6,11),
+ LPC18XX_PIN_P(6,12),
+ LPC18XX_PIN_P(7,0),
+ LPC18XX_PIN_P(7,1),
+ LPC18XX_PIN_P(7,2),
+ LPC18XX_PIN_P(7,3),
+ LPC18XX_PIN_P(7,4),
+ LPC18XX_PIN_P(7,5),
+ LPC18XX_PIN_P(7,6),
+ LPC18XX_PIN_P(7,7),
+ LPC18XX_PIN_P(8,0),
+ LPC18XX_PIN_P(8,1),
+ LPC18XX_PIN_P(8,2),
+ LPC18XX_PIN_P(8,3),
+ LPC18XX_PIN_P(8,4),
+ LPC18XX_PIN_P(8,5),
+ LPC18XX_PIN_P(8,6),
+ LPC18XX_PIN_P(8,7),
+ LPC18XX_PIN_P(8,8),
+ LPC18XX_PIN_P(9,0),
+ LPC18XX_PIN_P(9,1),
+ LPC18XX_PIN_P(9,2),
+ LPC18XX_PIN_P(9,3),
+ LPC18XX_PIN_P(9,4),
+ LPC18XX_PIN_P(9,5),
+ LPC18XX_PIN_P(9,6),
+ LPC18XX_PIN_P(a,0),
+ LPC18XX_PIN_P(a,1),
+ LPC18XX_PIN_P(a,2),
+ LPC18XX_PIN_P(a,3),
+ LPC18XX_PIN_P(a,4),
+ LPC18XX_PIN_P(b,0),
+ LPC18XX_PIN_P(b,1),
+ LPC18XX_PIN_P(b,2),
+ LPC18XX_PIN_P(b,3),
+ LPC18XX_PIN_P(b,4),
+ LPC18XX_PIN_P(b,5),
+ LPC18XX_PIN_P(b,6),
+ LPC18XX_PIN_P(c,0),
+ LPC18XX_PIN_P(c,1),
+ LPC18XX_PIN_P(c,2),
+ LPC18XX_PIN_P(c,3),
+ LPC18XX_PIN_P(c,4),
+ LPC18XX_PIN_P(c,5),
+ LPC18XX_PIN_P(c,6),
+ LPC18XX_PIN_P(c,7),
+ LPC18XX_PIN_P(c,8),
+ LPC18XX_PIN_P(c,9),
+ LPC18XX_PIN_P(c,10),
+ LPC18XX_PIN_P(c,11),
+ LPC18XX_PIN_P(c,12),
+ LPC18XX_PIN_P(c,13),
+ LPC18XX_PIN_P(c,14),
+ LPC18XX_PIN_P(d,0),
+ LPC18XX_PIN_P(d,1),
+ LPC18XX_PIN_P(d,2),
+ LPC18XX_PIN_P(d,3),
+ LPC18XX_PIN_P(d,4),
+ LPC18XX_PIN_P(d,5),
+ LPC18XX_PIN_P(d,6),
+ LPC18XX_PIN_P(d,7),
+ LPC18XX_PIN_P(d,8),
+ LPC18XX_PIN_P(d,9),
+ LPC18XX_PIN_P(d,10),
+ LPC18XX_PIN_P(d,11),
+ LPC18XX_PIN_P(d,12),
+ LPC18XX_PIN_P(d,13),
+ LPC18XX_PIN_P(d,14),
+ LPC18XX_PIN_P(d,15),
+ LPC18XX_PIN_P(d,16),
+ LPC18XX_PIN_P(e,0),
+ LPC18XX_PIN_P(e,1),
+ LPC18XX_PIN_P(e,2),
+ LPC18XX_PIN_P(e,3),
+ LPC18XX_PIN_P(e,4),
+ LPC18XX_PIN_P(e,5),
+ LPC18XX_PIN_P(e,6),
+ LPC18XX_PIN_P(e,7),
+ LPC18XX_PIN_P(e,8),
+ LPC18XX_PIN_P(e,9),
+ LPC18XX_PIN_P(e,10),
+ LPC18XX_PIN_P(e,11),
+ LPC18XX_PIN_P(e,12),
+ LPC18XX_PIN_P(e,13),
+ LPC18XX_PIN_P(e,14),
+ LPC18XX_PIN_P(e,15),
+ LPC18XX_PIN_P(f,0),
+ LPC18XX_PIN_P(f,1),
+ LPC18XX_PIN_P(f,2),
+ LPC18XX_PIN_P(f,3),
+ LPC18XX_PIN_P(f,4),
+ LPC18XX_PIN_P(f,5),
+ LPC18XX_PIN_P(f,6),
+ LPC18XX_PIN_P(f,7),
+ LPC18XX_PIN_P(f,8),
+ LPC18XX_PIN_P(f,9),
+ LPC18XX_PIN_P(f,10),
+ LPC18XX_PIN_P(f,11),
+
+ LPC18XX_PIN(clk0, PIN_CLK0),
+ LPC18XX_PIN(clk1, PIN_CLK1),
+ LPC18XX_PIN(clk2, PIN_CLK2),
+ LPC18XX_PIN(clk3, PIN_CLK3),
+ LPC18XX_PIN(usb1_dm, PIN_USB1_DM),
+ LPC18XX_PIN(usb1_dp, PIN_USB1_DP),
+ LPC18XX_PIN(i2c0_scl, PIN_I2C0_SCL),
+ LPC18XX_PIN(i2c0_sda, PIN_I2C0_SDA),
+};
+
+static int lpc18xx_pconf_get_usb1(enum pin_config_param param, int *arg, u32 reg)
+{
+ /* TODO */
+ return -ENOTSUPP;
+}
+
+static int lpc18xx_pconf_get_i2c0(enum pin_config_param param, int *arg, u32 reg,
+ unsigned pin)
+{
+ u8 shift;
+
+ if (pin == PIN_I2C0_SCL)
+ shift = LPC18XX_SCU_I2C0_SCL_SHIFT;
+ else
+ shift = LPC18XX_SCU_I2C0_SDA_SHIFT;
+
+ switch (param) {
+ case PIN_CONFIG_INPUT_ENABLE:
+ if (reg & (LPC18XX_SCU_I2C0_EZI << shift))
+ *arg = 1;
+ else
+ return -EINVAL;
+ break;
+
+ case PIN_CONFIG_SLEW_RATE:
+ if (reg & (LPC18XX_SCU_I2C0_EHD << shift))
+ *arg = 1;
+ else
+ *arg = 0;
+ break;
+
+ case PIN_CONFIG_INPUT_SCHMITT:
+ if (reg & (LPC18XX_SCU_I2C0_EFP << shift))
+ *arg = 3;
+ else
+ *arg = 50;
+ break;
+
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ if (reg & (LPC18XX_SCU_I2C0_ZIF << shift))
+ return -EINVAL;
+ else
+ *arg = 1;
+ break;
+
+ default:
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int lpc18xx_pconf_get_pin(enum pin_config_param param, int *arg, u32 reg,
+ struct lpc18xx_pin_caps *pin_cap)
+{
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ if ((!(reg & LPC18XX_SCU_PIN_EPD)) && (reg & LPC18XX_SCU_PIN_EPUN))
+ ;
+ else
+ return -EINVAL;
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (reg & LPC18XX_SCU_PIN_EPUN)
+ return -EINVAL;
+ else
+ *arg = 1;
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (reg & LPC18XX_SCU_PIN_EPD)
+ *arg = 1;
+ else
+ return -EINVAL;
+ break;
+
+ case PIN_CONFIG_INPUT_ENABLE:
+ if (reg & LPC18XX_SCU_PIN_EZI)
+ *arg = 1;
+ else
+ return -EINVAL;
+ break;
+
+ case PIN_CONFIG_SLEW_RATE:
+ if (pin_cap->type == TYPE_HD)
+ return -ENOTSUPP;
+
+ if (reg & LPC18XX_SCU_PIN_EHS)
+ *arg = 1;
+ else
+ *arg = 0;
+ break;
+
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ if (reg & LPC18XX_SCU_PIN_ZIF)
+ return -EINVAL;
+ else
+ *arg = 1;
+ break;
+
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ if (pin_cap->type != TYPE_HD)
+ return -ENOTSUPP;
+
+ *arg = (reg & LPC18XX_SCU_PIN_EHD_MASK) >> LPC18XX_SCU_PIN_EHD_POS;
+ switch (*arg) {
+ case 3: *arg += 5;
+ case 2: *arg += 5;
+ case 1: *arg += 3;
+ case 0: *arg += 4;
+ }
+ break;
+
+ default:
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static struct lpc18xx_pin_caps *lpc18xx_get_pin_caps(unsigned pin)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lpc18xx_pins); i++) {
+ if (lpc18xx_pins[i].number == pin)
+ return lpc18xx_pins[i].drv_data;
+ }
+
+ return NULL;
+}
+
+static int lpc18xx_pconf_get(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *config)
+{
+ struct lpc18xx_scu_data *scu = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ struct lpc18xx_pin_caps *pin_cap;
+ int ret, arg = 0;
+ u32 reg;
+
+ pin_cap = lpc18xx_get_pin_caps(pin);
+ if (!pin_cap)
+ return -EINVAL;
+
+ reg = readl(scu->base + pin_cap->offset);
+
+ if (pin_cap->type == TYPE_I2C0)
+ ret = lpc18xx_pconf_get_i2c0(param, &arg, reg, pin);
+ else if (pin_cap->type == TYPE_USB1)
+ ret = lpc18xx_pconf_get_usb1(param, &arg, reg);
+ else
+ ret = lpc18xx_pconf_get_pin(param, &arg, reg, pin_cap);
+
+ if (ret < 0)
+ return ret;
+
+ *config = pinconf_to_config_packed(param, (u16)arg);
+
+ return 0;
+}
+
+static int lpc18xx_pconf_set_usb1(struct pinctrl_dev *pctldev,
+ enum pin_config_param param,
+ u16 param_val, u32 *reg)
+{
+ /* TODO */
+ return -ENOTSUPP;
+}
+
+static int lpc18xx_pconf_set_i2c0(struct pinctrl_dev *pctldev,
+ enum pin_config_param param,
+ u16 param_val, u32 *reg,
+ unsigned pin)
+{
+ u8 shift;
+
+ if (pin == PIN_I2C0_SCL)
+ shift = LPC18XX_SCU_I2C0_SCL_SHIFT;
+ else
+ shift = LPC18XX_SCU_I2C0_SDA_SHIFT;
+
+ switch (param) {
+ case PIN_CONFIG_INPUT_ENABLE:
+ if (param_val)
+ *reg |= (LPC18XX_SCU_I2C0_EZI << shift);
+ else
+ *reg &= ~(LPC18XX_SCU_I2C0_EZI << shift);
+ break;
+
+ case PIN_CONFIG_SLEW_RATE:
+ if (param_val)
+ *reg |= (LPC18XX_SCU_I2C0_EHD << shift);
+ else
+ *reg &= ~(LPC18XX_SCU_I2C0_EHD << shift);
+ break;
+
+ case PIN_CONFIG_INPUT_SCHMITT:
+ if (param_val == 3)
+ *reg |= (LPC18XX_SCU_I2C0_EFP << shift);
+ else if (param_val == 50)
+ *reg &= ~(LPC18XX_SCU_I2C0_EFP << shift);
+ else
+ return -ENOTSUPP;
+ break;
+
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ if (param)
+ *reg &= ~(LPC18XX_SCU_I2C0_ZIF << shift);
+ else
+ *reg |= (LPC18XX_SCU_I2C0_ZIF << shift);
+ break;
+
+ default:
+ dev_err(pctldev->dev, "Property not supported\n");
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int lpc18xx_pconf_set_pin(struct pinctrl_dev *pctldev,
+ enum pin_config_param param,
+ u16 param_val, u32 *reg,
+ struct lpc18xx_pin_caps *pin_cap)
+{
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ *reg &= ~LPC18XX_SCU_PIN_EPD;
+ *reg |= LPC18XX_SCU_PIN_EPUN;
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_UP:
+ *reg &= ~LPC18XX_SCU_PIN_EPUN;
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ *reg |= LPC18XX_SCU_PIN_EPD;
+ break;
+
+ case PIN_CONFIG_INPUT_ENABLE:
+ if (param_val)
+ *reg |= LPC18XX_SCU_PIN_EZI;
+ else
+ *reg &= ~LPC18XX_SCU_PIN_EZI;
+ break;
+
+ case PIN_CONFIG_SLEW_RATE:
+ if (pin_cap->type == TYPE_HD) {
+ dev_err(pctldev->dev, "Slew rate unsupported on high-drive pins\n");
+ return -ENOTSUPP;
+ }
+
+ if (param_val == 0)
+ *reg &= ~LPC18XX_SCU_PIN_EHS;
+ else
+ *reg |= LPC18XX_SCU_PIN_EHS;
+ break;
+
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ if (param)
+ *reg &= ~LPC18XX_SCU_PIN_ZIF;
+ else
+ *reg |= LPC18XX_SCU_PIN_ZIF;
+ break;
+
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ if (pin_cap->type != TYPE_HD) {
+ dev_err(pctldev->dev, "Drive strength available only on high-drive pins\n");
+ return -ENOTSUPP;
+ }
+ *reg &= ~LPC18XX_SCU_PIN_EHD_MASK;
+
+ switch (param_val) {
+ case 20: param_val -= 5;
+ case 14: param_val -= 5;
+ case 8: param_val -= 3;
+ case 4: param_val -= 4;
+ break;
+ default:
+ dev_err(pctldev->dev, "Drive strength %u unsupported\n", param_val);
+ return -ENOTSUPP;
+ }
+ *reg |= param_val << LPC18XX_SCU_PIN_EHD_POS;
+ break;
+
+ default:
+ dev_err(pctldev->dev, "Property not supported\n");
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int lpc18xx_pconf_set(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *configs, unsigned num_configs)
+{
+ struct lpc18xx_scu_data *scu = pinctrl_dev_get_drvdata(pctldev);
+ struct lpc18xx_pin_caps *pin_cap;
+ enum pin_config_param param;
+ u16 param_val;
+ u32 reg;
+ int ret;
+ int i;
+
+ pin_cap = lpc18xx_get_pin_caps(pin);
+ if (!pin_cap)
+ return -EINVAL;
+
+ reg = readl(scu->base + pin_cap->offset);
+
+ for (i = 0; i < num_configs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ param_val = pinconf_to_config_argument(configs[i]);
+
+ if (pin_cap->type == TYPE_I2C0)
+ ret = lpc18xx_pconf_set_i2c0(pctldev, param, param_val, &reg, pin);
+ else if (pin_cap->type == TYPE_USB1)
+ ret = lpc18xx_pconf_set_usb1(pctldev, param, param_val, &reg);
+ else
+ ret = lpc18xx_pconf_set_pin(pctldev, param, param_val, &reg, pin_cap);
+
+ if (ret)
+ return ret;
+ }
+
+ writel(reg, scu->base + pin_cap->offset);
+
+ return 0;
+}
+
+static const struct pinconf_ops lpc18xx_pconf_ops = {
+ .is_generic = true,
+ .pin_config_get = lpc18xx_pconf_get,
+ .pin_config_set = lpc18xx_pconf_set,
+};
+
+static int lpc18xx_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(lpc18xx_function_names);
+}
+
+static const char *lpc18xx_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned function)
+{
+ return lpc18xx_function_names[function];
+}
+
+static int lpc18xx_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+ unsigned function,
+ const char *const **groups,
+ unsigned *const num_groups)
+{
+ struct lpc18xx_scu_data *scu = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = scu->func[function].groups;
+ *num_groups = scu->func[function].ngroups;
+
+ return 0;
+}
+
+static int lpc18xx_pmx_set(struct pinctrl_dev *pctldev, unsigned function,
+ unsigned group)
+{
+ struct lpc18xx_scu_data *scu = pinctrl_dev_get_drvdata(pctldev);
+ struct lpc18xx_pin_caps *pin = lpc18xx_pins[group].drv_data;
+ int func;
+ u32 reg;
+
+ /* Dedicated USB1 and I2C0 pins doesn't support muxing */
+ if (pin->type == TYPE_USB1) {
+ if (function == FUNC_USB1)
+ return 0;
+
+ goto fail;
+ }
+
+ if (pin->type == TYPE_I2C0) {
+ if (function == FUNC_I2C0)
+ return 0;
+
+ goto fail;
+ }
+
+ if (function == FUNC_ADC && (pin->analog & LPC18XX_ANALOG_PIN)) {
+ u32 offset;
+
+ writel(LPC18XX_SCU_ANALOG_PIN_CFG, scu->base + pin->offset);
+
+ if (LPC18XX_ANALOG_ADC(pin->analog) == 0)
+ offset = LPC18XX_SCU_REG_ENAIO0;
+ else
+ offset = LPC18XX_SCU_REG_ENAIO1;
+
+ reg = readl(scu->base + offset);
+ reg |= pin->analog & LPC18XX_ANALOG_BIT_MASK;
+ writel(reg, scu->base + offset);
+
+ return 0;
+ }
+
+ if (function == FUNC_DAC && (pin->analog & LPC18XX_ANALOG_PIN)) {
+ writel(LPC18XX_SCU_ANALOG_PIN_CFG, scu->base + pin->offset);
+
+ reg = readl(scu->base + LPC18XX_SCU_REG_ENAIO2);
+ reg |= LPC18XX_SCU_REG_ENAIO2_DAC;
+ writel(reg, scu->base + LPC18XX_SCU_REG_ENAIO2);
+
+ return 0;
+ }
+
+ for (func = 0; func < LPC18XX_SCU_FUNC_PER_PIN; func++) {
+ if (function == pin->functions[func])
+ break;
+ }
+
+ if (func >= LPC18XX_SCU_FUNC_PER_PIN)
+ goto fail;
+
+ reg = readl(scu->base + pin->offset);
+ reg &= ~LPC18XX_SCU_PIN_MODE_MASK;
+ writel(reg | func, scu->base + pin->offset);
+
+ return 0;
+fail:
+ dev_err(pctldev->dev, "Pin %s can't be %s\n", lpc18xx_pins[group].name,
+ lpc18xx_function_names[function]);
+ return -EINVAL;
+}
+
+static const struct pinmux_ops lpc18xx_pmx_ops = {
+ .get_functions_count = lpc18xx_pmx_get_funcs_count,
+ .get_function_name = lpc18xx_pmx_get_func_name,
+ .get_function_groups = lpc18xx_pmx_get_func_groups,
+ .set_mux = lpc18xx_pmx_set,
+};
+
+static int lpc18xx_pctl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(lpc18xx_pins);
+}
+
+static const char *lpc18xx_pctl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned group)
+{
+ return lpc18xx_pins[group].name;
+}
+
+static int lpc18xx_pctl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned group,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ *pins = &lpc18xx_pins[group].number;
+ *num_pins = 1;
+
+ return 0;
+}
+
+static const struct pinctrl_ops lpc18xx_pctl_ops = {
+ .get_groups_count = lpc18xx_pctl_get_groups_count,
+ .get_group_name = lpc18xx_pctl_get_group_name,
+ .get_group_pins = lpc18xx_pctl_get_group_pins,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+ .dt_free_map = pinctrl_utils_dt_free_map,
+};
+
+static struct pinctrl_desc lpc18xx_scu_desc = {
+ .name = "lpc18xx/43xx-scu",
+ .pins = lpc18xx_pins,
+ .npins = ARRAY_SIZE(lpc18xx_pins),
+ .pctlops = &lpc18xx_pctl_ops,
+ .pmxops = &lpc18xx_pmx_ops,
+ .confops = &lpc18xx_pconf_ops,
+ .owner = THIS_MODULE,
+};
+
+static bool lpc18xx_valid_pin_function(unsigned pin, unsigned function)
+{
+ struct lpc18xx_pin_caps *p = lpc18xx_pins[pin].drv_data;
+ int i;
+
+ if (function == FUNC_DAC && p->analog == DAC)
+ return true;
+
+ if (function == FUNC_ADC && p->analog)
+ return true;
+
+ if (function == FUNC_I2C0 && p->type == TYPE_I2C0)
+ return true;
+
+ if (function == FUNC_USB1 && p->type == TYPE_USB1)
+ return true;
+
+ for (i = 0; i < LPC18XX_SCU_FUNC_PER_PIN; i++) {
+ if (function == p->functions[i])
+ return true;
+ }
+
+ return false;
+}
+
+static int lpc18xx_create_group_func_map(struct device *dev,
+ struct lpc18xx_scu_data *scu)
+{
+ u16 pins[ARRAY_SIZE(lpc18xx_pins)];
+ int func, ngroups, i;
+
+ for (func = 0; func < FUNC_MAX; ngroups = 0, func++) {
+
+ for (i = 0; i < ARRAY_SIZE(lpc18xx_pins); i++) {
+ if (lpc18xx_valid_pin_function(i, func))
+ pins[ngroups++] = i;
+ }
+
+ scu->func[func].ngroups = ngroups;
+ scu->func[func].groups = devm_kzalloc(dev, ngroups *
+ sizeof(char *), GFP_KERNEL);
+ if (!scu->func[func].groups)
+ return -ENOMEM;
+
+ for (i = 0; i < ngroups; i++)
+ scu->func[func].groups[i] = lpc18xx_pins[pins[i]].name;
+ }
+
+ return 0;
+}
+
+static int lpc18xx_scu_probe(struct platform_device *pdev)
+{
+ struct lpc18xx_scu_data *scu;
+ struct resource *res;
+ int ret;
+
+ scu = devm_kzalloc(&pdev->dev, sizeof(*scu), GFP_KERNEL);
+ if (!scu)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ scu->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(scu->base))
+ return PTR_ERR(scu->base);
+
+ scu->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(scu->clk)) {
+ dev_err(&pdev->dev, "Input clock not found.\n");
+ return PTR_ERR(scu->clk);
+ }
+
+ ret = lpc18xx_create_group_func_map(&pdev->dev, scu);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to create group func map.\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(scu->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to enable clock.\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, scu);
+
+ scu->pctl = pinctrl_register(&lpc18xx_scu_desc, &pdev->dev, scu);
+ if (IS_ERR(scu->pctl)) {
+ dev_err(&pdev->dev, "Could not register pinctrl driver\n");
+ clk_disable_unprepare(scu->clk);
+ return PTR_ERR(scu->pctl);
+ }
+
+ return 0;
+}
+
+static int lpc18xx_scu_remove(struct platform_device *pdev)
+{
+ struct lpc18xx_scu_data *scu = platform_get_drvdata(pdev);
+
+ pinctrl_unregister(scu->pctl);
+ clk_disable_unprepare(scu->clk);
+
+ return 0;
+}
+
+static const struct of_device_id lpc18xx_scu_match[] = {
+ { .compatible = "nxp,lpc1850-scu" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, lpc18xx_scu_match);
+
+static struct platform_driver lpc18xx_scu_driver = {
+ .probe = lpc18xx_scu_probe,
+ .remove = lpc18xx_scu_remove,
+ .driver = {
+ .name = "lpc18xx-scu",
+ .of_match_table = lpc18xx_scu_match,
+ },
+};
+module_platform_driver(lpc18xx_scu_driver);
+
+MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
+MODULE_DESCRIPTION("Pinctrl driver for NXP LPC18xx/43xx SCU");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-palmas.c b/drivers/pinctrl/pinctrl-palmas.c
index 2631df0504bd..f7e168044baf 100644
--- a/drivers/pinctrl/pinctrl-palmas.c
+++ b/drivers/pinctrl/pinctrl-palmas.c
@@ -1044,9 +1044,9 @@ static int palmas_pinctrl_probe(struct platform_device *pdev)
palmas_pinctrl_desc.pins = palmas_pins_desc;
palmas_pinctrl_desc.npins = ARRAY_SIZE(palmas_pins_desc);
pci->pctl = pinctrl_register(&palmas_pinctrl_desc, &pdev->dev, pci);
- if (!pci->pctl) {
+ if (IS_ERR(pci->pctl)) {
dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
- return -ENODEV;
+ return PTR_ERR(pci->pctl);
}
return 0;
}
diff --git a/drivers/pinctrl/pinctrl-pistachio.c b/drivers/pinctrl/pinctrl-pistachio.c
new file mode 100644
index 000000000000..63100be81015
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-pistachio.c
@@ -0,0 +1,1504 @@
+/*
+ * Pistachio SoC pinctrl driver
+ *
+ * Copyright (C) 2014 Imagination Technologies Ltd.
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "pinctrl-utils.h"
+
+#define PADS_SCHMITT_EN0 0x000
+#define PADS_SCHMITT_EN_REG(pin) (PADS_SCHMITT_EN0 + 0x4 * ((pin) / 32))
+#define PADS_SCHMITT_EN_BIT(pin) BIT((pin) % 32)
+
+#define PADS_PU_PD0 0x040
+#define PADS_PU_PD_REG(pin) (PADS_PU_PD0 + 0x4 * ((pin) / 16))
+#define PADS_PU_PD_SHIFT(pin) (2 * ((pin) % 16))
+#define PADS_PU_PD_MASK 0x3
+#define PADS_PU_PD_HIGHZ 0x0
+#define PADS_PU_PD_UP 0x1
+#define PADS_PU_PD_DOWN 0x2
+#define PADS_PU_PD_BUS 0x3
+
+#define PADS_FUNCTION_SELECT0 0x0c0
+#define PADS_FUNCTION_SELECT1 0x0c4
+#define PADS_FUNCTION_SELECT2 0x0c8
+#define PADS_SCENARIO_SELECT 0x0f8
+
+#define PADS_SLEW_RATE0 0x100
+#define PADS_SLEW_RATE_REG(pin) (PADS_SLEW_RATE0 + 0x4 * ((pin) / 32))
+#define PADS_SLEW_RATE_BIT(pin) BIT((pin) % 32)
+
+#define PADS_DRIVE_STRENGTH0 0x120
+#define PADS_DRIVE_STRENGTH_REG(pin) \
+ (PADS_DRIVE_STRENGTH0 + 0x4 * ((pin) / 16))
+#define PADS_DRIVE_STRENGTH_SHIFT(pin) (2 * ((pin) % 16))
+#define PADS_DRIVE_STRENGTH_MASK 0x3
+#define PADS_DRIVE_STRENGTH_2MA 0x0
+#define PADS_DRIVE_STRENGTH_4MA 0x1
+#define PADS_DRIVE_STRENGTH_8MA 0x2
+#define PADS_DRIVE_STRENGTH_12MA 0x3
+
+#define GPIO_BANK_BASE(bank) (0x200 + 0x24 * (bank))
+
+#define GPIO_BIT_EN 0x00
+#define GPIO_OUTPUT_EN 0x04
+#define GPIO_OUTPUT 0x08
+#define GPIO_INPUT 0x0c
+#define GPIO_INPUT_POLARITY 0x10
+#define GPIO_INTERRUPT_TYPE 0x14
+#define GPIO_INTERRUPT_TYPE_LEVEL 0x0
+#define GPIO_INTERRUPT_TYPE_EDGE 0x1
+#define GPIO_INTERRUPT_EDGE 0x18
+#define GPIO_INTERRUPT_EDGE_SINGLE 0x0
+#define GPIO_INTERRUPT_EDGE_DUAL 0x1
+#define GPIO_INTERRUPT_EN 0x1c
+#define GPIO_INTERRUPT_STATUS 0x20
+
+struct pistachio_function {
+ const char *name;
+ const char * const *groups;
+ unsigned int ngroups;
+ const int *scenarios;
+ unsigned int nscenarios;
+ unsigned int scenario_reg;
+ unsigned int scenario_shift;
+ unsigned int scenario_mask;
+};
+
+struct pistachio_pin_group {
+ const char *name;
+ unsigned int pin;
+ int mux_option[3];
+ int mux_reg;
+ int mux_shift;
+ int mux_mask;
+};
+
+struct pistachio_gpio_bank {
+ struct pistachio_pinctrl *pctl;
+ void __iomem *base;
+ unsigned int pin_base;
+ unsigned int npins;
+ struct gpio_chip gpio_chip;
+ struct irq_chip irq_chip;
+};
+
+struct pistachio_pinctrl {
+ struct device *dev;
+ void __iomem *base;
+ struct pinctrl_dev *pctldev;
+ const struct pinctrl_pin_desc *pins;
+ unsigned int npins;
+ const struct pistachio_function *functions;
+ unsigned int nfunctions;
+ const struct pistachio_pin_group *groups;
+ unsigned int ngroups;
+ struct pistachio_gpio_bank *gpio_banks;
+ unsigned int nbanks;
+};
+
+#define PISTACHIO_PIN_MFIO(p) (p)
+#define PISTACHIO_PIN_TCK 90
+#define PISTACHIO_PIN_TRSTN 91
+#define PISTACHIO_PIN_TDI 92
+#define PISTACHIO_PIN_TMS 93
+#define PISTACHIO_PIN_TDO 94
+#define PISTACHIO_PIN_JTAG_COMPLY 95
+#define PISTACHIO_PIN_SAFE_MODE 96
+#define PISTACHIO_PIN_POR_DISABLE 97
+#define PISTACHIO_PIN_RESETN 98
+
+#define MFIO_PIN_DESC(p) PINCTRL_PIN(PISTACHIO_PIN_MFIO(p), "mfio" #p)
+
+static const struct pinctrl_pin_desc pistachio_pins[] = {
+ MFIO_PIN_DESC(0),
+ MFIO_PIN_DESC(1),
+ MFIO_PIN_DESC(2),
+ MFIO_PIN_DESC(3),
+ MFIO_PIN_DESC(4),
+ MFIO_PIN_DESC(5),
+ MFIO_PIN_DESC(6),
+ MFIO_PIN_DESC(7),
+ MFIO_PIN_DESC(8),
+ MFIO_PIN_DESC(9),
+ MFIO_PIN_DESC(10),
+ MFIO_PIN_DESC(11),
+ MFIO_PIN_DESC(12),
+ MFIO_PIN_DESC(13),
+ MFIO_PIN_DESC(14),
+ MFIO_PIN_DESC(15),
+ MFIO_PIN_DESC(16),
+ MFIO_PIN_DESC(17),
+ MFIO_PIN_DESC(18),
+ MFIO_PIN_DESC(19),
+ MFIO_PIN_DESC(20),
+ MFIO_PIN_DESC(21),
+ MFIO_PIN_DESC(22),
+ MFIO_PIN_DESC(23),
+ MFIO_PIN_DESC(24),
+ MFIO_PIN_DESC(25),
+ MFIO_PIN_DESC(26),
+ MFIO_PIN_DESC(27),
+ MFIO_PIN_DESC(28),
+ MFIO_PIN_DESC(29),
+ MFIO_PIN_DESC(30),
+ MFIO_PIN_DESC(31),
+ MFIO_PIN_DESC(32),
+ MFIO_PIN_DESC(33),
+ MFIO_PIN_DESC(34),
+ MFIO_PIN_DESC(35),
+ MFIO_PIN_DESC(36),
+ MFIO_PIN_DESC(37),
+ MFIO_PIN_DESC(38),
+ MFIO_PIN_DESC(39),
+ MFIO_PIN_DESC(40),
+ MFIO_PIN_DESC(41),
+ MFIO_PIN_DESC(42),
+ MFIO_PIN_DESC(43),
+ MFIO_PIN_DESC(44),
+ MFIO_PIN_DESC(45),
+ MFIO_PIN_DESC(46),
+ MFIO_PIN_DESC(47),
+ MFIO_PIN_DESC(48),
+ MFIO_PIN_DESC(49),
+ MFIO_PIN_DESC(50),
+ MFIO_PIN_DESC(51),
+ MFIO_PIN_DESC(52),
+ MFIO_PIN_DESC(53),
+ MFIO_PIN_DESC(54),
+ MFIO_PIN_DESC(55),
+ MFIO_PIN_DESC(56),
+ MFIO_PIN_DESC(57),
+ MFIO_PIN_DESC(58),
+ MFIO_PIN_DESC(59),
+ MFIO_PIN_DESC(60),
+ MFIO_PIN_DESC(61),
+ MFIO_PIN_DESC(62),
+ MFIO_PIN_DESC(63),
+ MFIO_PIN_DESC(64),
+ MFIO_PIN_DESC(65),
+ MFIO_PIN_DESC(66),
+ MFIO_PIN_DESC(67),
+ MFIO_PIN_DESC(68),
+ MFIO_PIN_DESC(69),
+ MFIO_PIN_DESC(70),
+ MFIO_PIN_DESC(71),
+ MFIO_PIN_DESC(72),
+ MFIO_PIN_DESC(73),
+ MFIO_PIN_DESC(74),
+ MFIO_PIN_DESC(75),
+ MFIO_PIN_DESC(76),
+ MFIO_PIN_DESC(77),
+ MFIO_PIN_DESC(78),
+ MFIO_PIN_DESC(79),
+ MFIO_PIN_DESC(80),
+ MFIO_PIN_DESC(81),
+ MFIO_PIN_DESC(82),
+ MFIO_PIN_DESC(83),
+ MFIO_PIN_DESC(84),
+ MFIO_PIN_DESC(85),
+ MFIO_PIN_DESC(86),
+ MFIO_PIN_DESC(87),
+ MFIO_PIN_DESC(88),
+ MFIO_PIN_DESC(89),
+ PINCTRL_PIN(PISTACHIO_PIN_TCK, "tck"),
+ PINCTRL_PIN(PISTACHIO_PIN_TRSTN, "trstn"),
+ PINCTRL_PIN(PISTACHIO_PIN_TDI, "tdi"),
+ PINCTRL_PIN(PISTACHIO_PIN_TMS, "tms"),
+ PINCTRL_PIN(PISTACHIO_PIN_TDO, "tdo"),
+ PINCTRL_PIN(PISTACHIO_PIN_JTAG_COMPLY, "jtag_comply"),
+ PINCTRL_PIN(PISTACHIO_PIN_SAFE_MODE, "safe_mode"),
+ PINCTRL_PIN(PISTACHIO_PIN_POR_DISABLE, "por_disable"),
+ PINCTRL_PIN(PISTACHIO_PIN_RESETN, "resetn"),
+};
+
+static const char * const pistachio_spim0_groups[] = {
+ "mfio1", "mfio2", "mfio8", "mfio9", "mfio10", "mfio28", "mfio29",
+ "mfio30", "mfio55", "mfio56", "mfio57",
+};
+
+static const char * const pistachio_spim1_groups[] = {
+ "mfio0", "mfio1", "mfio2", "mfio3", "mfio4", "mfio5", "mfio6",
+ "mfio7", "mfio31", "mfio55", "mfio56", "mfio57", "mfio58",
+};
+
+static const char * const pistachio_spis_groups[] = {
+ "mfio11", "mfio12", "mfio13", "mfio14",
+};
+
+static const char *const pistachio_sdhost_groups[] = {
+ "mfio15", "mfio16", "mfio17", "mfio18", "mfio19", "mfio20",
+ "mfio21", "mfio22", "mfio23", "mfio24", "mfio25", "mfio26",
+ "mfio27",
+};
+
+static const char * const pistachio_i2c0_groups[] = {
+ "mfio28", "mfio29",
+};
+
+static const char * const pistachio_i2c1_groups[] = {
+ "mfio30", "mfio31",
+};
+
+static const char * const pistachio_i2c2_groups[] = {
+ "mfio32", "mfio33",
+};
+
+static const char * const pistachio_i2c3_groups[] = {
+ "mfio34", "mfio35",
+};
+
+static const char * const pistachio_audio_clk_in_groups[] = {
+ "mfio36",
+};
+
+static const char * const pistachio_i2s_out_groups[] = {
+ "mfio36", "mfio37", "mfio38", "mfio39", "mfio40", "mfio41",
+ "mfio42", "mfio43", "mfio44",
+};
+
+static const char * const pistachio_debug_raw_cca_ind_groups[] = {
+ "mfio37",
+};
+
+static const char * const pistachio_debug_ed_sec20_cca_ind_groups[] = {
+ "mfio38",
+};
+
+static const char * const pistachio_debug_ed_sec40_cca_ind_groups[] = {
+ "mfio39",
+};
+
+static const char * const pistachio_debug_agc_done_0_groups[] = {
+ "mfio40",
+};
+
+static const char * const pistachio_debug_agc_done_1_groups[] = {
+ "mfio41",
+};
+
+static const char * const pistachio_debug_ed_cca_ind_groups[] = {
+ "mfio42",
+};
+
+static const char * const pistachio_debug_s2l_done_groups[] = {
+ "mfio43",
+};
+
+static const char * const pistachio_i2s_dac_clk_groups[] = {
+ "mfio45",
+};
+
+static const char * const pistachio_audio_sync_groups[] = {
+ "mfio45",
+};
+
+static const char * const pistachio_audio_trigger_groups[] = {
+ "mfio46",
+};
+
+static const char * const pistachio_i2s_in_groups[] = {
+ "mfio47", "mfio48", "mfio49", "mfio50", "mfio51", "mfio52",
+ "mfio53", "mfio54",
+};
+
+static const char * const pistachio_uart0_groups[] = {
+ "mfio55", "mfio56", "mfio57", "mfio58",
+};
+
+static const char * const pistachio_uart1_groups[] = {
+ "mfio59", "mfio60", "mfio1", "mfio2",
+};
+
+static const char * const pistachio_spdif_out_groups[] = {
+ "mfio61",
+};
+
+static const char * const pistachio_spdif_in_groups[] = {
+ "mfio62", "mfio54",
+};
+static const int pistachio_spdif_in_scenarios[] = {
+ PISTACHIO_PIN_MFIO(62),
+ PISTACHIO_PIN_MFIO(54),
+};
+
+static const char * const pistachio_eth_groups[] = {
+ "mfio63", "mfio64", "mfio65", "mfio66", "mfio67", "mfio68",
+ "mfio69", "mfio70", "mfio71",
+};
+
+static const char * const pistachio_ir_groups[] = {
+ "mfio72",
+};
+
+static const char * const pistachio_pwmpdm_groups[] = {
+ "mfio73", "mfio74", "mfio75", "mfio76",
+};
+
+static const char * const pistachio_mips_trace_clk_groups[] = {
+ "mfio15", "mfio63", "mfio73",
+};
+
+static const char * const pistachio_mips_trace_dint_groups[] = {
+ "mfio16", "mfio64", "mfio74",
+};
+static const int pistachio_mips_trace_dint_scenarios[] = {
+ PISTACHIO_PIN_MFIO(16),
+ PISTACHIO_PIN_MFIO(64),
+ PISTACHIO_PIN_MFIO(74),
+};
+
+static const char * const pistachio_mips_trace_trigout_groups[] = {
+ "mfio17", "mfio65", "mfio75",
+};
+
+static const char * const pistachio_mips_trace_trigin_groups[] = {
+ "mfio18", "mfio66", "mfio76",
+};
+static const int pistachio_mips_trace_trigin_scenarios[] = {
+ PISTACHIO_PIN_MFIO(18),
+ PISTACHIO_PIN_MFIO(66),
+ PISTACHIO_PIN_MFIO(76),
+};
+
+static const char * const pistachio_mips_trace_dm_groups[] = {
+ "mfio19", "mfio67", "mfio77",
+};
+
+static const char * const pistachio_mips_probe_n_groups[] = {
+ "mfio20", "mfio68", "mfio78",
+};
+static const int pistachio_mips_probe_n_scenarios[] = {
+ PISTACHIO_PIN_MFIO(20),
+ PISTACHIO_PIN_MFIO(68),
+ PISTACHIO_PIN_MFIO(78),
+};
+
+static const char * const pistachio_mips_trace_data_groups[] = {
+ "mfio15", "mfio16", "mfio17", "mfio18", "mfio19", "mfio20",
+ "mfio21", "mfio22", "mfio63", "mfio64", "mfio65", "mfio66",
+ "mfio67", "mfio68", "mfio69", "mfio70", "mfio79", "mfio80",
+ "mfio81", "mfio82", "mfio83", "mfio84", "mfio85", "mfio86",
+};
+
+static const char * const pistachio_sram_debug_groups[] = {
+ "mfio73", "mfio74",
+};
+
+static const char * const pistachio_rom_debug_groups[] = {
+ "mfio75", "mfio76",
+};
+
+static const char * const pistachio_rpu_debug_groups[] = {
+ "mfio77", "mfio78",
+};
+
+static const char * const pistachio_mips_debug_groups[] = {
+ "mfio79", "mfio80",
+};
+
+static const char * const pistachio_eth_debug_groups[] = {
+ "mfio81", "mfio82",
+};
+
+static const char * const pistachio_usb_debug_groups[] = {
+ "mfio83", "mfio84",
+};
+
+static const char * const pistachio_sdhost_debug_groups[] = {
+ "mfio85", "mfio86",
+};
+
+static const char * const pistachio_socif_debug_groups[] = {
+ "mfio87", "mfio88",
+};
+
+static const char * const pistachio_mdc_debug_groups[] = {
+ "mfio77", "mfio78",
+};
+
+static const char * const pistachio_ddr_debug_groups[] = {
+ "mfio79", "mfio80",
+};
+
+static const char * const pistachio_dreq0_groups[] = {
+ "mfio81",
+};
+
+static const char * const pistachio_dreq1_groups[] = {
+ "mfio82",
+};
+
+static const char * const pistachio_dreq2_groups[] = {
+ "mfio87",
+};
+
+static const char * const pistachio_dreq3_groups[] = {
+ "mfio88",
+};
+
+static const char * const pistachio_dreq4_groups[] = {
+ "mfio89",
+};
+
+static const char * const pistachio_dreq5_groups[] = {
+ "mfio89",
+};
+
+static const char * const pistachio_mips_pll_lock_groups[] = {
+ "mfio83",
+};
+
+static const char * const pistachio_sys_pll_lock_groups[] = {
+ "mfio84",
+};
+
+static const char * const pistachio_wifi_pll_lock_groups[] = {
+ "mfio85",
+};
+
+static const char * const pistachio_bt_pll_lock_groups[] = {
+ "mfio86",
+};
+
+static const char * const pistachio_rpu_v_pll_lock_groups[] = {
+ "mfio87",
+};
+
+static const char * const pistachio_rpu_l_pll_lock_groups[] = {
+ "mfio88",
+};
+
+static const char * const pistachio_audio_pll_lock_groups[] = {
+ "mfio89",
+};
+
+#define FUNCTION(_name) \
+ { \
+ .name = #_name, \
+ .groups = pistachio_##_name##_groups, \
+ .ngroups = ARRAY_SIZE(pistachio_##_name##_groups), \
+ }
+
+#define FUNCTION_SCENARIO(_name, _reg, _shift, _mask) \
+ { \
+ .name = #_name, \
+ .groups = pistachio_##_name##_groups, \
+ .ngroups = ARRAY_SIZE(pistachio_##_name##_groups), \
+ .scenarios = pistachio_##_name##_scenarios, \
+ .nscenarios = ARRAY_SIZE(pistachio_##_name##_scenarios),\
+ .scenario_reg = _reg, \
+ .scenario_shift = _shift, \
+ .scenario_mask = _mask, \
+ }
+
+enum pistachio_mux_option {
+ PISTACHIO_FUNCTION_NONE = -1,
+ PISTACHIO_FUNCTION_SPIM0,
+ PISTACHIO_FUNCTION_SPIM1,
+ PISTACHIO_FUNCTION_SPIS,
+ PISTACHIO_FUNCTION_SDHOST,
+ PISTACHIO_FUNCTION_I2C0,
+ PISTACHIO_FUNCTION_I2C1,
+ PISTACHIO_FUNCTION_I2C2,
+ PISTACHIO_FUNCTION_I2C3,
+ PISTACHIO_FUNCTION_AUDIO_CLK_IN,
+ PISTACHIO_FUNCTION_I2S_OUT,
+ PISTACHIO_FUNCTION_I2S_DAC_CLK,
+ PISTACHIO_FUNCTION_AUDIO_SYNC,
+ PISTACHIO_FUNCTION_AUDIO_TRIGGER,
+ PISTACHIO_FUNCTION_I2S_IN,
+ PISTACHIO_FUNCTION_UART0,
+ PISTACHIO_FUNCTION_UART1,
+ PISTACHIO_FUNCTION_SPDIF_OUT,
+ PISTACHIO_FUNCTION_SPDIF_IN,
+ PISTACHIO_FUNCTION_ETH,
+ PISTACHIO_FUNCTION_IR,
+ PISTACHIO_FUNCTION_PWMPDM,
+ PISTACHIO_FUNCTION_MIPS_TRACE_CLK,
+ PISTACHIO_FUNCTION_MIPS_TRACE_DINT,
+ PISTACHIO_FUNCTION_MIPS_TRACE_TRIGOUT,
+ PISTACHIO_FUNCTION_MIPS_TRACE_TRIGIN,
+ PISTACHIO_FUNCTION_MIPS_TRACE_DM,
+ PISTACHIO_FUNCTION_MIPS_TRACE_PROBE_N,
+ PISTACHIO_FUNCTION_MIPS_TRACE_DATA,
+ PISTACHIO_FUNCTION_SRAM_DEBUG,
+ PISTACHIO_FUNCTION_ROM_DEBUG,
+ PISTACHIO_FUNCTION_RPU_DEBUG,
+ PISTACHIO_FUNCTION_MIPS_DEBUG,
+ PISTACHIO_FUNCTION_ETH_DEBUG,
+ PISTACHIO_FUNCTION_USB_DEBUG,
+ PISTACHIO_FUNCTION_SDHOST_DEBUG,
+ PISTACHIO_FUNCTION_SOCIF_DEBUG,
+ PISTACHIO_FUNCTION_MDC_DEBUG,
+ PISTACHIO_FUNCTION_DDR_DEBUG,
+ PISTACHIO_FUNCTION_DREQ0,
+ PISTACHIO_FUNCTION_DREQ1,
+ PISTACHIO_FUNCTION_DREQ2,
+ PISTACHIO_FUNCTION_DREQ3,
+ PISTACHIO_FUNCTION_DREQ4,
+ PISTACHIO_FUNCTION_DREQ5,
+ PISTACHIO_FUNCTION_MIPS_PLL_LOCK,
+ PISTACHIO_FUNCTION_SYS_PLL_LOCK,
+ PISTACHIO_FUNCTION_WIFI_PLL_LOCK,
+ PISTACHIO_FUNCTION_BT_PLL_LOCK,
+ PISTACHIO_FUNCTION_RPU_V_PLL_LOCK,
+ PISTACHIO_FUNCTION_RPU_L_PLL_LOCK,
+ PISTACHIO_FUNCTION_AUDIO_PLL_LOCK,
+ PISTACHIO_FUNCTION_DEBUG_RAW_CCA_IND,
+ PISTACHIO_FUNCTION_DEBUG_ED_SEC20_CCA_IND,
+ PISTACHIO_FUNCTION_DEBUG_ED_SEC40_CCA_IND,
+ PISTACHIO_FUNCTION_DEBUG_AGC_DONE_0,
+ PISTACHIO_FUNCTION_DEBUG_AGC_DONE_1,
+ PISTACHIO_FUNCTION_DEBUG_ED_CCA_IND,
+ PISTACHIO_FUNCTION_DEBUG_S2L_DONE,
+};
+
+static const struct pistachio_function pistachio_functions[] = {
+ FUNCTION(spim0),
+ FUNCTION(spim1),
+ FUNCTION(spis),
+ FUNCTION(sdhost),
+ FUNCTION(i2c0),
+ FUNCTION(i2c1),
+ FUNCTION(i2c2),
+ FUNCTION(i2c3),
+ FUNCTION(audio_clk_in),
+ FUNCTION(i2s_out),
+ FUNCTION(i2s_dac_clk),
+ FUNCTION(audio_sync),
+ FUNCTION(audio_trigger),
+ FUNCTION(i2s_in),
+ FUNCTION(uart0),
+ FUNCTION(uart1),
+ FUNCTION(spdif_out),
+ FUNCTION_SCENARIO(spdif_in, PADS_SCENARIO_SELECT, 0, 0x1),
+ FUNCTION(eth),
+ FUNCTION(ir),
+ FUNCTION(pwmpdm),
+ FUNCTION(mips_trace_clk),
+ FUNCTION_SCENARIO(mips_trace_dint, PADS_SCENARIO_SELECT, 1, 0x3),
+ FUNCTION(mips_trace_trigout),
+ FUNCTION_SCENARIO(mips_trace_trigin, PADS_SCENARIO_SELECT, 3, 0x3),
+ FUNCTION(mips_trace_dm),
+ FUNCTION_SCENARIO(mips_probe_n, PADS_SCENARIO_SELECT, 5, 0x3),
+ FUNCTION(mips_trace_data),
+ FUNCTION(sram_debug),
+ FUNCTION(rom_debug),
+ FUNCTION(rpu_debug),
+ FUNCTION(mips_debug),
+ FUNCTION(eth_debug),
+ FUNCTION(usb_debug),
+ FUNCTION(sdhost_debug),
+ FUNCTION(socif_debug),
+ FUNCTION(mdc_debug),
+ FUNCTION(ddr_debug),
+ FUNCTION(dreq0),
+ FUNCTION(dreq1),
+ FUNCTION(dreq2),
+ FUNCTION(dreq3),
+ FUNCTION(dreq4),
+ FUNCTION(dreq5),
+ FUNCTION(mips_pll_lock),
+ FUNCTION(sys_pll_lock),
+ FUNCTION(wifi_pll_lock),
+ FUNCTION(bt_pll_lock),
+ FUNCTION(rpu_v_pll_lock),
+ FUNCTION(rpu_l_pll_lock),
+ FUNCTION(audio_pll_lock),
+ FUNCTION(debug_raw_cca_ind),
+ FUNCTION(debug_ed_sec20_cca_ind),
+ FUNCTION(debug_ed_sec40_cca_ind),
+ FUNCTION(debug_agc_done_0),
+ FUNCTION(debug_agc_done_1),
+ FUNCTION(debug_ed_cca_ind),
+ FUNCTION(debug_s2l_done),
+};
+
+#define PIN_GROUP(_pin, _name) \
+ { \
+ .name = #_name, \
+ .pin = PISTACHIO_PIN_##_pin, \
+ .mux_option = { \
+ PISTACHIO_FUNCTION_NONE, \
+ PISTACHIO_FUNCTION_NONE, \
+ PISTACHIO_FUNCTION_NONE, \
+ }, \
+ .mux_reg = -1, \
+ .mux_shift = -1, \
+ .mux_mask = -1, \
+ }
+
+#define MFIO_PIN_GROUP(_pin, _func) \
+ { \
+ .name = "mfio" #_pin, \
+ .pin = PISTACHIO_PIN_MFIO(_pin), \
+ .mux_option = { \
+ PISTACHIO_FUNCTION_##_func, \
+ PISTACHIO_FUNCTION_NONE, \
+ PISTACHIO_FUNCTION_NONE, \
+ }, \
+ .mux_reg = -1, \
+ .mux_shift = -1, \
+ .mux_mask = -1, \
+ }
+
+#define MFIO_MUX_PIN_GROUP(_pin, _f0, _f1, _f2, _reg, _shift, _mask) \
+ { \
+ .name = "mfio" #_pin, \
+ .pin = PISTACHIO_PIN_MFIO(_pin), \
+ .mux_option = { \
+ PISTACHIO_FUNCTION_##_f0, \
+ PISTACHIO_FUNCTION_##_f1, \
+ PISTACHIO_FUNCTION_##_f2, \
+ }, \
+ .mux_reg = _reg, \
+ .mux_shift = _shift, \
+ .mux_mask = _mask, \
+ }
+
+static const struct pistachio_pin_group pistachio_groups[] = {
+ MFIO_PIN_GROUP(0, SPIM1),
+ MFIO_MUX_PIN_GROUP(1, SPIM1, SPIM0, UART1,
+ PADS_FUNCTION_SELECT0, 0, 0x3),
+ MFIO_MUX_PIN_GROUP(2, SPIM1, SPIM0, UART1,
+ PADS_FUNCTION_SELECT0, 2, 0x3),
+ MFIO_PIN_GROUP(3, SPIM1),
+ MFIO_PIN_GROUP(4, SPIM1),
+ MFIO_PIN_GROUP(5, SPIM1),
+ MFIO_PIN_GROUP(6, SPIM1),
+ MFIO_PIN_GROUP(7, SPIM1),
+ MFIO_PIN_GROUP(8, SPIM0),
+ MFIO_PIN_GROUP(9, SPIM0),
+ MFIO_PIN_GROUP(10, SPIM0),
+ MFIO_PIN_GROUP(11, SPIS),
+ MFIO_PIN_GROUP(12, SPIS),
+ MFIO_PIN_GROUP(13, SPIS),
+ MFIO_PIN_GROUP(14, SPIS),
+ MFIO_MUX_PIN_GROUP(15, SDHOST, MIPS_TRACE_CLK, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT0, 4, 0x3),
+ MFIO_MUX_PIN_GROUP(16, SDHOST, MIPS_TRACE_DINT, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT0, 6, 0x3),
+ MFIO_MUX_PIN_GROUP(17, SDHOST, MIPS_TRACE_TRIGOUT, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT0, 8, 0x3),
+ MFIO_MUX_PIN_GROUP(18, SDHOST, MIPS_TRACE_TRIGIN, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT0, 10, 0x3),
+ MFIO_MUX_PIN_GROUP(19, SDHOST, MIPS_TRACE_DM, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT0, 12, 0x3),
+ MFIO_MUX_PIN_GROUP(20, SDHOST, MIPS_TRACE_PROBE_N, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT0, 14, 0x3),
+ MFIO_MUX_PIN_GROUP(21, SDHOST, NONE, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT0, 16, 0x3),
+ MFIO_MUX_PIN_GROUP(22, SDHOST, NONE, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT0, 18, 0x3),
+ MFIO_PIN_GROUP(23, SDHOST),
+ MFIO_PIN_GROUP(24, SDHOST),
+ MFIO_PIN_GROUP(25, SDHOST),
+ MFIO_PIN_GROUP(26, SDHOST),
+ MFIO_PIN_GROUP(27, SDHOST),
+ MFIO_MUX_PIN_GROUP(28, I2C0, SPIM0, NONE,
+ PADS_FUNCTION_SELECT0, 20, 0x1),
+ MFIO_MUX_PIN_GROUP(29, I2C0, SPIM0, NONE,
+ PADS_FUNCTION_SELECT0, 21, 0x1),
+ MFIO_MUX_PIN_GROUP(30, I2C1, SPIM0, NONE,
+ PADS_FUNCTION_SELECT0, 22, 0x1),
+ MFIO_MUX_PIN_GROUP(31, I2C1, SPIM1, NONE,
+ PADS_FUNCTION_SELECT0, 23, 0x1),
+ MFIO_PIN_GROUP(32, I2C2),
+ MFIO_PIN_GROUP(33, I2C2),
+ MFIO_PIN_GROUP(34, I2C3),
+ MFIO_PIN_GROUP(35, I2C3),
+ MFIO_MUX_PIN_GROUP(36, I2S_OUT, AUDIO_CLK_IN, NONE,
+ PADS_FUNCTION_SELECT0, 24, 0x1),
+ MFIO_MUX_PIN_GROUP(37, I2S_OUT, DEBUG_RAW_CCA_IND, NONE,
+ PADS_FUNCTION_SELECT0, 25, 0x1),
+ MFIO_MUX_PIN_GROUP(38, I2S_OUT, DEBUG_ED_SEC20_CCA_IND, NONE,
+ PADS_FUNCTION_SELECT0, 26, 0x1),
+ MFIO_MUX_PIN_GROUP(39, I2S_OUT, DEBUG_ED_SEC40_CCA_IND, NONE,
+ PADS_FUNCTION_SELECT0, 27, 0x1),
+ MFIO_MUX_PIN_GROUP(40, I2S_OUT, DEBUG_AGC_DONE_0, NONE,
+ PADS_FUNCTION_SELECT0, 28, 0x1),
+ MFIO_MUX_PIN_GROUP(41, I2S_OUT, DEBUG_AGC_DONE_1, NONE,
+ PADS_FUNCTION_SELECT0, 29, 0x1),
+ MFIO_MUX_PIN_GROUP(42, I2S_OUT, DEBUG_ED_CCA_IND, NONE,
+ PADS_FUNCTION_SELECT0, 30, 0x1),
+ MFIO_MUX_PIN_GROUP(43, I2S_OUT, DEBUG_S2L_DONE, NONE,
+ PADS_FUNCTION_SELECT0, 31, 0x1),
+ MFIO_PIN_GROUP(44, I2S_OUT),
+ MFIO_MUX_PIN_GROUP(45, I2S_DAC_CLK, AUDIO_SYNC, NONE,
+ PADS_FUNCTION_SELECT1, 0, 0x1),
+ MFIO_PIN_GROUP(46, AUDIO_TRIGGER),
+ MFIO_PIN_GROUP(47, I2S_IN),
+ MFIO_PIN_GROUP(48, I2S_IN),
+ MFIO_PIN_GROUP(49, I2S_IN),
+ MFIO_PIN_GROUP(50, I2S_IN),
+ MFIO_PIN_GROUP(51, I2S_IN),
+ MFIO_PIN_GROUP(52, I2S_IN),
+ MFIO_PIN_GROUP(53, I2S_IN),
+ MFIO_MUX_PIN_GROUP(54, I2S_IN, NONE, SPDIF_IN,
+ PADS_FUNCTION_SELECT1, 1, 0x3),
+ MFIO_MUX_PIN_GROUP(55, UART0, SPIM0, SPIM1,
+ PADS_FUNCTION_SELECT1, 3, 0x3),
+ MFIO_MUX_PIN_GROUP(56, UART0, SPIM0, SPIM1,
+ PADS_FUNCTION_SELECT1, 5, 0x3),
+ MFIO_MUX_PIN_GROUP(57, UART0, SPIM0, SPIM1,
+ PADS_FUNCTION_SELECT1, 7, 0x3),
+ MFIO_MUX_PIN_GROUP(58, UART0, SPIM1, NONE,
+ PADS_FUNCTION_SELECT1, 9, 0x1),
+ MFIO_PIN_GROUP(59, UART1),
+ MFIO_PIN_GROUP(60, UART1),
+ MFIO_PIN_GROUP(61, SPDIF_OUT),
+ MFIO_PIN_GROUP(62, SPDIF_IN),
+ MFIO_MUX_PIN_GROUP(63, ETH, MIPS_TRACE_CLK, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT1, 10, 0x3),
+ MFIO_MUX_PIN_GROUP(64, ETH, MIPS_TRACE_DINT, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT1, 12, 0x3),
+ MFIO_MUX_PIN_GROUP(65, ETH, MIPS_TRACE_TRIGOUT, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT1, 14, 0x3),
+ MFIO_MUX_PIN_GROUP(66, ETH, MIPS_TRACE_TRIGIN, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT1, 16, 0x3),
+ MFIO_MUX_PIN_GROUP(67, ETH, MIPS_TRACE_DM, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT1, 18, 0x3),
+ MFIO_MUX_PIN_GROUP(68, ETH, MIPS_TRACE_PROBE_N, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT1, 20, 0x3),
+ MFIO_MUX_PIN_GROUP(69, ETH, NONE, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT1, 22, 0x3),
+ MFIO_MUX_PIN_GROUP(70, ETH, NONE, MIPS_TRACE_DATA,
+ PADS_FUNCTION_SELECT1, 24, 0x3),
+ MFIO_PIN_GROUP(71, ETH),
+ MFIO_PIN_GROUP(72, IR),
+ MFIO_MUX_PIN_GROUP(73, PWMPDM, MIPS_TRACE_CLK, SRAM_DEBUG,
+ PADS_FUNCTION_SELECT1, 26, 0x3),
+ MFIO_MUX_PIN_GROUP(74, PWMPDM, MIPS_TRACE_DINT, SRAM_DEBUG,
+ PADS_FUNCTION_SELECT1, 28, 0x3),
+ MFIO_MUX_PIN_GROUP(75, PWMPDM, MIPS_TRACE_TRIGOUT, ROM_DEBUG,
+ PADS_FUNCTION_SELECT1, 30, 0x3),
+ MFIO_MUX_PIN_GROUP(76, PWMPDM, MIPS_TRACE_TRIGIN, ROM_DEBUG,
+ PADS_FUNCTION_SELECT2, 0, 0x3),
+ MFIO_MUX_PIN_GROUP(77, MDC_DEBUG, MIPS_TRACE_DM, RPU_DEBUG,
+ PADS_FUNCTION_SELECT2, 2, 0x3),
+ MFIO_MUX_PIN_GROUP(78, MDC_DEBUG, MIPS_TRACE_PROBE_N, RPU_DEBUG,
+ PADS_FUNCTION_SELECT2, 4, 0x3),
+ MFIO_MUX_PIN_GROUP(79, DDR_DEBUG, MIPS_TRACE_DATA, MIPS_DEBUG,
+ PADS_FUNCTION_SELECT2, 6, 0x3),
+ MFIO_MUX_PIN_GROUP(80, DDR_DEBUG, MIPS_TRACE_DATA, MIPS_DEBUG,
+ PADS_FUNCTION_SELECT2, 8, 0x3),
+ MFIO_MUX_PIN_GROUP(81, DREQ0, MIPS_TRACE_DATA, ETH_DEBUG,
+ PADS_FUNCTION_SELECT2, 10, 0x3),
+ MFIO_MUX_PIN_GROUP(82, DREQ1, MIPS_TRACE_DATA, ETH_DEBUG,
+ PADS_FUNCTION_SELECT2, 12, 0x3),
+ MFIO_MUX_PIN_GROUP(83, MIPS_PLL_LOCK, MIPS_TRACE_DATA, USB_DEBUG,
+ PADS_FUNCTION_SELECT2, 14, 0x3),
+ MFIO_MUX_PIN_GROUP(84, SYS_PLL_LOCK, MIPS_TRACE_DATA, USB_DEBUG,
+ PADS_FUNCTION_SELECT2, 16, 0x3),
+ MFIO_MUX_PIN_GROUP(85, WIFI_PLL_LOCK, MIPS_TRACE_DATA, SDHOST_DEBUG,
+ PADS_FUNCTION_SELECT2, 18, 0x3),
+ MFIO_MUX_PIN_GROUP(86, BT_PLL_LOCK, MIPS_TRACE_DATA, SDHOST_DEBUG,
+ PADS_FUNCTION_SELECT2, 20, 0x3),
+ MFIO_MUX_PIN_GROUP(87, RPU_V_PLL_LOCK, DREQ2, SOCIF_DEBUG,
+ PADS_FUNCTION_SELECT2, 22, 0x3),
+ MFIO_MUX_PIN_GROUP(88, RPU_L_PLL_LOCK, DREQ3, SOCIF_DEBUG,
+ PADS_FUNCTION_SELECT2, 24, 0x3),
+ MFIO_MUX_PIN_GROUP(89, AUDIO_PLL_LOCK, DREQ4, DREQ5,
+ PADS_FUNCTION_SELECT2, 26, 0x3),
+ PIN_GROUP(TCK, "tck"),
+ PIN_GROUP(TRSTN, "trstn"),
+ PIN_GROUP(TDI, "tdi"),
+ PIN_GROUP(TMS, "tms"),
+ PIN_GROUP(TDO, "tdo"),
+ PIN_GROUP(JTAG_COMPLY, "jtag_comply"),
+ PIN_GROUP(SAFE_MODE, "safe_mode"),
+ PIN_GROUP(POR_DISABLE, "por_disable"),
+ PIN_GROUP(RESETN, "resetn"),
+};
+
+static inline u32 pctl_readl(struct pistachio_pinctrl *pctl, u32 reg)
+{
+ return readl(pctl->base + reg);
+}
+
+static inline void pctl_writel(struct pistachio_pinctrl *pctl, u32 val, u32 reg)
+{
+ writel(val, pctl->base + reg);
+}
+
+static inline struct pistachio_gpio_bank *gc_to_bank(struct gpio_chip *gc)
+{
+ return container_of(gc, struct pistachio_gpio_bank, gpio_chip);
+}
+
+static inline struct pistachio_gpio_bank *irqd_to_bank(struct irq_data *d)
+{
+ return gc_to_bank(irq_data_get_irq_chip_data(d));
+}
+
+static inline u32 gpio_readl(struct pistachio_gpio_bank *bank, u32 reg)
+{
+ return readl(bank->base + reg);
+}
+
+static inline void gpio_writel(struct pistachio_gpio_bank *bank, u32 val,
+ u32 reg)
+{
+ writel(val, bank->base + reg);
+}
+
+static inline void gpio_mask_writel(struct pistachio_gpio_bank *bank,
+ u32 reg, unsigned int bit, u32 val)
+{
+ /*
+ * For most of the GPIO registers, bit 16 + X must be set in order to
+ * write bit X.
+ */
+ gpio_writel(bank, (0x10000 | val) << bit, reg);
+}
+
+static inline void gpio_enable(struct pistachio_gpio_bank *bank,
+ unsigned offset)
+{
+ gpio_mask_writel(bank, GPIO_BIT_EN, offset, 1);
+}
+
+static inline void gpio_disable(struct pistachio_gpio_bank *bank,
+ unsigned offset)
+{
+ gpio_mask_writel(bank, GPIO_BIT_EN, offset, 0);
+}
+
+static int pistachio_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct pistachio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->ngroups;
+}
+
+static const char *pistachio_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned group)
+{
+ struct pistachio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->groups[group].name;
+}
+
+static int pistachio_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned group,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ struct pistachio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = &pctl->groups[group].pin;
+ *num_pins = 1;
+
+ return 0;
+}
+
+static const struct pinctrl_ops pistachio_pinctrl_ops = {
+ .get_groups_count = pistachio_pinctrl_get_groups_count,
+ .get_group_name = pistachio_pinctrl_get_group_name,
+ .get_group_pins = pistachio_pinctrl_get_group_pins,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+ .dt_free_map = pinctrl_utils_dt_free_map,
+};
+
+static int pistachio_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ struct pistachio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->nfunctions;
+}
+
+static const char *
+pistachio_pinmux_get_function_name(struct pinctrl_dev *pctldev, unsigned func)
+{
+ struct pistachio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->functions[func].name;
+}
+
+static int pistachio_pinmux_get_function_groups(struct pinctrl_dev *pctldev,
+ unsigned func,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct pistachio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = pctl->functions[func].groups;
+ *num_groups = pctl->functions[func].ngroups;
+
+ return 0;
+}
+
+static int pistachio_pinmux_enable(struct pinctrl_dev *pctldev,
+ unsigned func, unsigned group)
+{
+ struct pistachio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct pistachio_pin_group *pg = &pctl->groups[group];
+ const struct pistachio_function *pf = &pctl->functions[func];
+ struct pinctrl_gpio_range *range;
+ unsigned int i;
+ u32 val;
+
+ if (pg->mux_reg > 0) {
+ for (i = 0; i < ARRAY_SIZE(pg->mux_option); i++) {
+ if (pg->mux_option[i] == func)
+ break;
+ }
+ if (i == ARRAY_SIZE(pg->mux_option)) {
+ dev_err(pctl->dev, "Cannot mux pin %u to function %u\n",
+ group, func);
+ return -EINVAL;
+ }
+
+ val = pctl_readl(pctl, pg->mux_reg);
+ val &= ~(pg->mux_mask << pg->mux_shift);
+ val |= i << pg->mux_shift;
+ pctl_writel(pctl, val, pg->mux_reg);
+
+ if (pf->scenarios) {
+ for (i = 0; i < pf->nscenarios; i++) {
+ if (pf->scenarios[i] == group)
+ break;
+ }
+ if (WARN_ON(i == pf->nscenarios))
+ return -EINVAL;
+
+ val = pctl_readl(pctl, pf->scenario_reg);
+ val &= ~(pf->scenario_mask << pf->scenario_shift);
+ val |= i << pf->scenario_shift;
+ pctl_writel(pctl, val, pf->scenario_reg);
+ }
+ }
+
+ range = pinctrl_find_gpio_range_from_pin(pctl->pctldev, pg->pin);
+ if (range)
+ gpio_disable(gc_to_bank(range->gc), pg->pin - range->pin_base);
+
+ return 0;
+}
+
+static const struct pinmux_ops pistachio_pinmux_ops = {
+ .get_functions_count = pistachio_pinmux_get_functions_count,
+ .get_function_name = pistachio_pinmux_get_function_name,
+ .get_function_groups = pistachio_pinmux_get_function_groups,
+ .set_mux = pistachio_pinmux_enable,
+};
+
+static int pistachio_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *config)
+{
+ struct pistachio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ u32 val, arg;
+
+ switch (param) {
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ val = pctl_readl(pctl, PADS_SCHMITT_EN_REG(pin));
+ arg = !!(val & PADS_SCHMITT_EN_BIT(pin));
+ break;
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ val = pctl_readl(pctl, PADS_PU_PD_REG(pin)) >>
+ PADS_PU_PD_SHIFT(pin);
+ arg = (val & PADS_PU_PD_MASK) == PADS_PU_PD_HIGHZ;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ val = pctl_readl(pctl, PADS_PU_PD_REG(pin)) >>
+ PADS_PU_PD_SHIFT(pin);
+ arg = (val & PADS_PU_PD_MASK) == PADS_PU_PD_UP;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ val = pctl_readl(pctl, PADS_PU_PD_REG(pin)) >>
+ PADS_PU_PD_SHIFT(pin);
+ arg = (val & PADS_PU_PD_MASK) == PADS_PU_PD_DOWN;
+ break;
+ case PIN_CONFIG_BIAS_BUS_HOLD:
+ val = pctl_readl(pctl, PADS_PU_PD_REG(pin)) >>
+ PADS_PU_PD_SHIFT(pin);
+ arg = (val & PADS_PU_PD_MASK) == PADS_PU_PD_BUS;
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ val = pctl_readl(pctl, PADS_SLEW_RATE_REG(pin));
+ arg = !!(val & PADS_SLEW_RATE_BIT(pin));
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ val = pctl_readl(pctl, PADS_DRIVE_STRENGTH_REG(pin)) >>
+ PADS_DRIVE_STRENGTH_SHIFT(pin);
+ switch (val & PADS_DRIVE_STRENGTH_MASK) {
+ case PADS_DRIVE_STRENGTH_2MA:
+ arg = 2;
+ break;
+ case PADS_DRIVE_STRENGTH_4MA:
+ arg = 4;
+ break;
+ case PADS_DRIVE_STRENGTH_8MA:
+ arg = 8;
+ break;
+ case PADS_DRIVE_STRENGTH_12MA:
+ default:
+ arg = 12;
+ break;
+ }
+ break;
+ default:
+ dev_dbg(pctl->dev, "Property %u not supported\n", param);
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+
+ return 0;
+}
+
+static int pistachio_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *configs, unsigned num_configs)
+{
+ struct pistachio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param;
+ u32 drv, val, arg;
+ unsigned int i;
+
+ for (i = 0; i < num_configs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ val = pctl_readl(pctl, PADS_SCHMITT_EN_REG(pin));
+ if (arg)
+ val |= PADS_SCHMITT_EN_BIT(pin);
+ else
+ val &= ~PADS_SCHMITT_EN_BIT(pin);
+ pctl_writel(pctl, val, PADS_SCHMITT_EN_REG(pin));
+ break;
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ val = pctl_readl(pctl, PADS_PU_PD_REG(pin));
+ val &= ~(PADS_PU_PD_MASK << PADS_PU_PD_SHIFT(pin));
+ val |= PADS_PU_PD_HIGHZ << PADS_PU_PD_SHIFT(pin);
+ pctl_writel(pctl, val, PADS_PU_PD_REG(pin));
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ val = pctl_readl(pctl, PADS_PU_PD_REG(pin));
+ val &= ~(PADS_PU_PD_MASK << PADS_PU_PD_SHIFT(pin));
+ val |= PADS_PU_PD_UP << PADS_PU_PD_SHIFT(pin);
+ pctl_writel(pctl, val, PADS_PU_PD_REG(pin));
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ val = pctl_readl(pctl, PADS_PU_PD_REG(pin));
+ val &= ~(PADS_PU_PD_MASK << PADS_PU_PD_SHIFT(pin));
+ val |= PADS_PU_PD_DOWN << PADS_PU_PD_SHIFT(pin);
+ pctl_writel(pctl, val, PADS_PU_PD_REG(pin));
+ break;
+ case PIN_CONFIG_BIAS_BUS_HOLD:
+ val = pctl_readl(pctl, PADS_PU_PD_REG(pin));
+ val &= ~(PADS_PU_PD_MASK << PADS_PU_PD_SHIFT(pin));
+ val |= PADS_PU_PD_BUS << PADS_PU_PD_SHIFT(pin);
+ pctl_writel(pctl, val, PADS_PU_PD_REG(pin));
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ val = pctl_readl(pctl, PADS_SLEW_RATE_REG(pin));
+ if (arg)
+ val |= PADS_SLEW_RATE_BIT(pin);
+ else
+ val &= ~PADS_SLEW_RATE_BIT(pin);
+ pctl_writel(pctl, val, PADS_SLEW_RATE_REG(pin));
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ val = pctl_readl(pctl, PADS_DRIVE_STRENGTH_REG(pin));
+ val &= ~(PADS_DRIVE_STRENGTH_MASK <<
+ PADS_DRIVE_STRENGTH_SHIFT(pin));
+ switch (arg) {
+ case 2:
+ drv = PADS_DRIVE_STRENGTH_2MA;
+ break;
+ case 4:
+ drv = PADS_DRIVE_STRENGTH_4MA;
+ break;
+ case 8:
+ drv = PADS_DRIVE_STRENGTH_8MA;
+ break;
+ case 12:
+ drv = PADS_DRIVE_STRENGTH_12MA;
+ break;
+ default:
+ dev_err(pctl->dev,
+ "Drive strength %umA not supported\n",
+ arg);
+ return -EINVAL;
+ }
+ val |= drv << PADS_DRIVE_STRENGTH_SHIFT(pin);
+ pctl_writel(pctl, val, PADS_DRIVE_STRENGTH_REG(pin));
+ break;
+ default:
+ dev_err(pctl->dev, "Property %u not supported\n",
+ param);
+ return -ENOTSUPP;
+ }
+ }
+
+ return 0;
+}
+
+static const struct pinconf_ops pistachio_pinconf_ops = {
+ .pin_config_get = pistachio_pinconf_get,
+ .pin_config_set = pistachio_pinconf_set,
+ .is_generic = true,
+};
+
+static struct pinctrl_desc pistachio_pinctrl_desc = {
+ .name = "pistachio-pinctrl",
+ .pctlops = &pistachio_pinctrl_ops,
+ .pmxops = &pistachio_pinmux_ops,
+ .confops = &pistachio_pinconf_ops,
+};
+
+static int pistachio_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void pistachio_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_free_gpio(chip->base + offset);
+}
+
+static int pistachio_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+ struct pistachio_gpio_bank *bank = gc_to_bank(chip);
+
+ return !(gpio_readl(bank, GPIO_OUTPUT_EN) & BIT(offset));
+}
+
+static int pistachio_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct pistachio_gpio_bank *bank = gc_to_bank(chip);
+ u32 reg;
+
+ if (gpio_readl(bank, GPIO_OUTPUT_EN) & BIT(offset))
+ reg = GPIO_OUTPUT;
+ else
+ reg = GPIO_INPUT;
+
+ return !!(gpio_readl(bank, reg) & BIT(offset));
+}
+
+static void pistachio_gpio_set(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct pistachio_gpio_bank *bank = gc_to_bank(chip);
+
+ gpio_mask_writel(bank, GPIO_OUTPUT, offset, !!value);
+}
+
+static int pistachio_gpio_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+{
+ struct pistachio_gpio_bank *bank = gc_to_bank(chip);
+
+ gpio_mask_writel(bank, GPIO_OUTPUT_EN, offset, 0);
+ gpio_enable(bank, offset);
+
+ return 0;
+}
+
+static int pistachio_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct pistachio_gpio_bank *bank = gc_to_bank(chip);
+
+ pistachio_gpio_set(chip, offset, value);
+ gpio_mask_writel(bank, GPIO_OUTPUT_EN, offset, 1);
+ gpio_enable(bank, offset);
+
+ return 0;
+}
+
+static void pistachio_gpio_irq_ack(struct irq_data *data)
+{
+ struct pistachio_gpio_bank *bank = irqd_to_bank(data);
+
+ gpio_mask_writel(bank, GPIO_INTERRUPT_STATUS, data->hwirq, 0);
+}
+
+static void pistachio_gpio_irq_mask(struct irq_data *data)
+{
+ struct pistachio_gpio_bank *bank = irqd_to_bank(data);
+
+ gpio_mask_writel(bank, GPIO_INTERRUPT_EN, data->hwirq, 0);
+}
+
+static void pistachio_gpio_irq_unmask(struct irq_data *data)
+{
+ struct pistachio_gpio_bank *bank = irqd_to_bank(data);
+
+ gpio_mask_writel(bank, GPIO_INTERRUPT_EN, data->hwirq, 1);
+}
+
+static unsigned int pistachio_gpio_irq_startup(struct irq_data *data)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+
+ pistachio_gpio_direction_input(chip, data->hwirq);
+ pistachio_gpio_irq_unmask(data);
+
+ return 0;
+}
+
+static int pistachio_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+ struct pistachio_gpio_bank *bank = irqd_to_bank(data);
+
+ switch (type & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_EDGE_RISING:
+ gpio_mask_writel(bank, GPIO_INPUT_POLARITY, data->hwirq, 1);
+ gpio_mask_writel(bank, GPIO_INTERRUPT_TYPE, data->hwirq,
+ GPIO_INTERRUPT_TYPE_EDGE);
+ gpio_mask_writel(bank, GPIO_INTERRUPT_EDGE, data->hwirq,
+ GPIO_INTERRUPT_EDGE_SINGLE);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ gpio_mask_writel(bank, GPIO_INPUT_POLARITY, data->hwirq, 0);
+ gpio_mask_writel(bank, GPIO_INTERRUPT_TYPE, data->hwirq,
+ GPIO_INTERRUPT_TYPE_EDGE);
+ gpio_mask_writel(bank, GPIO_INTERRUPT_EDGE, data->hwirq,
+ GPIO_INTERRUPT_EDGE_SINGLE);
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ gpio_mask_writel(bank, GPIO_INTERRUPT_TYPE, data->hwirq,
+ GPIO_INTERRUPT_TYPE_EDGE);
+ gpio_mask_writel(bank, GPIO_INTERRUPT_EDGE, data->hwirq,
+ GPIO_INTERRUPT_EDGE_DUAL);
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ gpio_mask_writel(bank, GPIO_INPUT_POLARITY, data->hwirq, 1);
+ gpio_mask_writel(bank, GPIO_INTERRUPT_TYPE, data->hwirq,
+ GPIO_INTERRUPT_TYPE_LEVEL);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ gpio_mask_writel(bank, GPIO_INPUT_POLARITY, data->hwirq, 0);
+ gpio_mask_writel(bank, GPIO_INTERRUPT_TYPE, data->hwirq,
+ GPIO_INTERRUPT_TYPE_LEVEL);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (type & IRQ_TYPE_LEVEL_MASK)
+ __irq_set_handler_locked(data->irq, handle_level_irq);
+ else
+ __irq_set_handler_locked(data->irq, handle_edge_irq);
+
+ return 0;
+}
+
+static void pistachio_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct gpio_chip *gc = irq_get_handler_data(irq);
+ struct pistachio_gpio_bank *bank = gc_to_bank(gc);
+ struct irq_chip *chip = irq_get_chip(irq);
+ unsigned long pending;
+ unsigned int pin;
+
+ chained_irq_enter(chip, desc);
+ pending = gpio_readl(bank, GPIO_INTERRUPT_STATUS) &
+ gpio_readl(bank, GPIO_INTERRUPT_EN);
+ for_each_set_bit(pin, &pending, 16)
+ generic_handle_irq(irq_linear_revmap(gc->irqdomain, pin));
+ chained_irq_exit(chip, desc);
+}
+
+#define GPIO_BANK(_bank, _pin_base, _npins) \
+ { \
+ .pin_base = _pin_base, \
+ .npins = _npins, \
+ .gpio_chip = { \
+ .label = "GPIO" #_bank, \
+ .request = pistachio_gpio_request, \
+ .free = pistachio_gpio_free, \
+ .get_direction = pistachio_gpio_get_direction, \
+ .direction_input = pistachio_gpio_direction_input, \
+ .direction_output = pistachio_gpio_direction_output, \
+ .get = pistachio_gpio_get, \
+ .set = pistachio_gpio_set, \
+ .base = _pin_base, \
+ .ngpio = _npins, \
+ }, \
+ .irq_chip = { \
+ .name = "GPIO" #_bank, \
+ .irq_startup = pistachio_gpio_irq_startup, \
+ .irq_ack = pistachio_gpio_irq_ack, \
+ .irq_mask = pistachio_gpio_irq_mask, \
+ .irq_unmask = pistachio_gpio_irq_unmask, \
+ .irq_set_type = pistachio_gpio_irq_set_type, \
+ }, \
+ }
+
+static struct pistachio_gpio_bank pistachio_gpio_banks[] = {
+ GPIO_BANK(0, PISTACHIO_PIN_MFIO(0), 16),
+ GPIO_BANK(1, PISTACHIO_PIN_MFIO(16), 16),
+ GPIO_BANK(2, PISTACHIO_PIN_MFIO(32), 16),
+ GPIO_BANK(3, PISTACHIO_PIN_MFIO(48), 16),
+ GPIO_BANK(4, PISTACHIO_PIN_MFIO(64), 16),
+ GPIO_BANK(5, PISTACHIO_PIN_MFIO(80), 10),
+};
+
+static int pistachio_gpio_register(struct pistachio_pinctrl *pctl)
+{
+ struct device_node *node = pctl->dev->of_node;
+ struct pistachio_gpio_bank *bank;
+ unsigned int i;
+ int irq, ret = 0;
+
+ for (i = 0; i < pctl->nbanks; i++) {
+ char child_name[sizeof("gpioXX")];
+ struct device_node *child;
+
+ snprintf(child_name, sizeof(child_name), "gpio%d", i);
+ child = of_get_child_by_name(node, child_name);
+ if (!child) {
+ dev_err(pctl->dev, "No node for bank %u\n", i);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ if (!of_find_property(child, "gpio-controller", NULL)) {
+ dev_err(pctl->dev,
+ "No gpio-controller property for bank %u\n", i);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ irq = irq_of_parse_and_map(child, 0);
+ if (irq < 0) {
+ dev_err(pctl->dev, "No IRQ for bank %u: %d\n", i, irq);
+ ret = irq;
+ goto err;
+ }
+
+ bank = &pctl->gpio_banks[i];
+ bank->pctl = pctl;
+ bank->base = pctl->base + GPIO_BANK_BASE(i);
+
+ bank->gpio_chip.dev = pctl->dev;
+ bank->gpio_chip.of_node = child;
+ ret = gpiochip_add(&bank->gpio_chip);
+ if (ret < 0) {
+ dev_err(pctl->dev, "Failed to add GPIO chip %u: %d\n",
+ i, ret);
+ goto err;
+ }
+
+ ret = gpiochip_irqchip_add(&bank->gpio_chip, &bank->irq_chip,
+ 0, handle_level_irq, IRQ_TYPE_NONE);
+ if (ret < 0) {
+ dev_err(pctl->dev, "Failed to add IRQ chip %u: %d\n",
+ i, ret);
+ gpiochip_remove(&bank->gpio_chip);
+ goto err;
+ }
+ gpiochip_set_chained_irqchip(&bank->gpio_chip, &bank->irq_chip,
+ irq, pistachio_gpio_irq_handler);
+
+ ret = gpiochip_add_pin_range(&bank->gpio_chip,
+ dev_name(pctl->dev), 0,
+ bank->pin_base, bank->npins);
+ if (ret < 0) {
+ dev_err(pctl->dev, "Failed to add GPIO range %u: %d\n",
+ i, ret);
+ gpiochip_remove(&bank->gpio_chip);
+ goto err;
+ }
+ }
+
+ return 0;
+err:
+ for (; i > 0; i--) {
+ bank = &pctl->gpio_banks[i - 1];
+ gpiochip_remove(&bank->gpio_chip);
+ }
+ return ret;
+}
+
+static const struct of_device_id pistachio_pinctrl_of_match[] = {
+ { .compatible = "img,pistachio-system-pinctrl", },
+ { },
+};
+
+static int pistachio_pinctrl_probe(struct platform_device *pdev)
+{
+ struct pistachio_pinctrl *pctl;
+ struct resource *res;
+ int ret;
+
+ pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
+ if (!pctl)
+ return -ENOMEM;
+ pctl->dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, pctl);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pctl->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pctl->base))
+ return PTR_ERR(pctl->base);
+
+ pctl->pins = pistachio_pins;
+ pctl->npins = ARRAY_SIZE(pistachio_pins);
+ pctl->functions = pistachio_functions;
+ pctl->nfunctions = ARRAY_SIZE(pistachio_functions);
+ pctl->groups = pistachio_groups;
+ pctl->ngroups = ARRAY_SIZE(pistachio_groups);
+ pctl->gpio_banks = pistachio_gpio_banks;
+ pctl->nbanks = ARRAY_SIZE(pistachio_gpio_banks);
+
+ pistachio_pinctrl_desc.pins = pctl->pins;
+ pistachio_pinctrl_desc.npins = pctl->npins;
+
+ pctl->pctldev = pinctrl_register(&pistachio_pinctrl_desc, &pdev->dev,
+ pctl);
+ if (IS_ERR(pctl->pctldev)) {
+ dev_err(&pdev->dev, "Failed to register pinctrl device\n");
+ return PTR_ERR(pctl->pctldev);
+ }
+
+ ret = pistachio_gpio_register(pctl);
+ if (ret < 0) {
+ pinctrl_unregister(pctl->pctldev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct platform_driver pistachio_pinctrl_driver = {
+ .driver = {
+ .name = "pistachio-pinctrl",
+ .of_match_table = pistachio_pinctrl_of_match,
+ .suppress_bind_attrs = true,
+ },
+ .probe = pistachio_pinctrl_probe,
+};
+
+static int __init pistachio_pinctrl_register(void)
+{
+ return platform_driver_register(&pistachio_pinctrl_driver);
+}
+arch_initcall(pistachio_pinctrl_register);
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index dee7d5f06c60..9affcd725776 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -63,6 +63,7 @@ enum rockchip_pinctrl_type {
RK3066B,
RK3188,
RK3288,
+ RK3368,
};
/**
@@ -163,6 +164,9 @@ struct rockchip_pin_ctrl {
void (*pull_calc_reg)(struct rockchip_pin_bank *bank,
int pin_num, struct regmap **regmap,
int *reg, u8 *bit);
+ void (*drv_calc_reg)(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit);
};
struct rockchip_pin_config {
@@ -581,7 +585,6 @@ static void rk3288_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
#define RK3288_DRV_BITS_PER_PIN 2
#define RK3288_DRV_PINS_PER_REG 8
#define RK3288_DRV_BANK_STRIDE 16
-static int rk3288_drv_list[] = { 2, 4, 8, 12 };
static void rk3288_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
int pin_num, struct regmap **regmap,
@@ -611,14 +614,81 @@ static void rk3288_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
}
}
-static int rk3288_get_drive(struct rockchip_pin_bank *bank, int pin_num)
+#define RK3368_PULL_GRF_OFFSET 0x100
+#define RK3368_PULL_PMU_OFFSET 0x10
+
+static void rk3368_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit)
{
+ struct rockchip_pinctrl *info = bank->drvdata;
+
+ /* The first 32 pins of the first bank are located in PMU */
+ if (bank->bank_num == 0) {
+ *regmap = info->regmap_pmu;
+ *reg = RK3368_PULL_PMU_OFFSET;
+
+ *reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
+ *bit = pin_num % RK3188_PULL_PINS_PER_REG;
+ *bit *= RK3188_PULL_BITS_PER_PIN;
+ } else {
+ *regmap = info->regmap_base;
+ *reg = RK3368_PULL_GRF_OFFSET;
+
+ /* correct the offset, as we're starting with the 2nd bank */
+ *reg -= 0x10;
+ *reg += bank->bank_num * RK3188_PULL_BANK_STRIDE;
+ *reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
+
+ *bit = (pin_num % RK3188_PULL_PINS_PER_REG);
+ *bit *= RK3188_PULL_BITS_PER_PIN;
+ }
+}
+
+#define RK3368_DRV_PMU_OFFSET 0x20
+#define RK3368_DRV_GRF_OFFSET 0x200
+
+static void rk3368_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl *info = bank->drvdata;
+
+ /* The first 32 pins of the first bank are located in PMU */
+ if (bank->bank_num == 0) {
+ *regmap = info->regmap_pmu;
+ *reg = RK3368_DRV_PMU_OFFSET;
+
+ *reg += ((pin_num / RK3288_DRV_PINS_PER_REG) * 4);
+ *bit = pin_num % RK3288_DRV_PINS_PER_REG;
+ *bit *= RK3288_DRV_BITS_PER_PIN;
+ } else {
+ *regmap = info->regmap_base;
+ *reg = RK3368_DRV_GRF_OFFSET;
+
+ /* correct the offset, as we're starting with the 2nd bank */
+ *reg -= 0x10;
+ *reg += bank->bank_num * RK3288_DRV_BANK_STRIDE;
+ *reg += ((pin_num / RK3288_DRV_PINS_PER_REG) * 4);
+
+ *bit = (pin_num % RK3288_DRV_PINS_PER_REG);
+ *bit *= RK3288_DRV_BITS_PER_PIN;
+ }
+}
+
+static int rockchip_perpin_drv_list[] = { 2, 4, 8, 12 };
+
+static int rockchip_get_drive_perpin(struct rockchip_pin_bank *bank,
+ int pin_num)
+{
+ struct rockchip_pinctrl *info = bank->drvdata;
+ struct rockchip_pin_ctrl *ctrl = info->ctrl;
struct regmap *regmap;
int reg, ret;
u32 data;
u8 bit;
- rk3288_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ ctrl->drv_calc_reg(bank, pin_num, &regmap, &reg, &bit);
ret = regmap_read(regmap, reg, &data);
if (ret)
@@ -627,24 +697,25 @@ static int rk3288_get_drive(struct rockchip_pin_bank *bank, int pin_num)
data >>= bit;
data &= (1 << RK3288_DRV_BITS_PER_PIN) - 1;
- return rk3288_drv_list[data];
+ return rockchip_perpin_drv_list[data];
}
-static int rk3288_set_drive(struct rockchip_pin_bank *bank, int pin_num,
- int strength)
+static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
+ int pin_num, int strength)
{
struct rockchip_pinctrl *info = bank->drvdata;
+ struct rockchip_pin_ctrl *ctrl = info->ctrl;
struct regmap *regmap;
unsigned long flags;
int reg, ret, i;
u32 data, rmask;
u8 bit;
- rk3288_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+ ctrl->drv_calc_reg(bank, pin_num, &regmap, &reg, &bit);
ret = -EINVAL;
- for (i = 0; i < ARRAY_SIZE(rk3288_drv_list); i++) {
- if (rk3288_drv_list[i] == strength) {
+ for (i = 0; i < ARRAY_SIZE(rockchip_perpin_drv_list); i++) {
+ if (rockchip_perpin_drv_list[i] == strength) {
ret = i;
break;
}
@@ -695,6 +766,7 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
: PIN_CONFIG_BIAS_DISABLE;
case RK3188:
case RK3288:
+ case RK3368:
data >>= bit;
data &= (1 << RK3188_PULL_BITS_PER_PIN) - 1;
@@ -750,6 +822,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
break;
case RK3188:
case RK3288:
+ case RK3368:
spin_lock_irqsave(&bank->slock, flags);
/* enable the write to the equivalent lower bits */
@@ -927,6 +1000,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
return pull ? false : true;
case RK3188:
case RK3288:
+ case RK3368:
return (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT);
}
@@ -983,10 +1057,11 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
break;
case PIN_CONFIG_DRIVE_STRENGTH:
/* rk3288 is the first with per-pin drive-strength */
- if (info->ctrl->type != RK3288)
+ if (!info->ctrl->drv_calc_reg)
return -ENOTSUPP;
- rc = rk3288_set_drive(bank, pin - bank->pin_base, arg);
+ rc = rockchip_set_drive_perpin(bank,
+ pin - bank->pin_base, arg);
if (rc < 0)
return rc;
break;
@@ -1041,10 +1116,10 @@ static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
break;
case PIN_CONFIG_DRIVE_STRENGTH:
/* rk3288 is the first with per-pin drive-strength */
- if (info->ctrl->type != RK3288)
+ if (!info->ctrl->drv_calc_reg)
return -ENOTSUPP;
- rc = rk3288_get_drive(bank, pin - bank->pin_base);
+ rc = rockchip_get_drive_perpin(bank, pin - bank->pin_base);
if (rc < 0)
return rc;
@@ -1274,9 +1349,9 @@ static int rockchip_pinctrl_register(struct platform_device *pdev,
return ret;
info->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, info);
- if (!info->pctl_dev) {
+ if (IS_ERR(info->pctl_dev)) {
dev_err(&pdev->dev, "could not register pinctrl driver\n");
- return -EINVAL;
+ return PTR_ERR(info->pctl_dev);
}
for (bank = 0; bank < info->ctrl->nr_banks; ++bank) {
@@ -2056,8 +2131,32 @@ static struct rockchip_pin_ctrl rk3288_pin_ctrl = {
.grf_mux_offset = 0x0,
.pmu_mux_offset = 0x84,
.pull_calc_reg = rk3288_calc_pull_reg_and_bit,
+ .drv_calc_reg = rk3288_calc_drv_reg_and_bit,
};
+static struct rockchip_pin_bank rk3368_pin_banks[] = {
+ PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU,
+ IOMUX_SOURCE_PMU,
+ IOMUX_SOURCE_PMU,
+ IOMUX_SOURCE_PMU
+ ),
+ PIN_BANK(1, 32, "gpio1"),
+ PIN_BANK(2, 32, "gpio2"),
+ PIN_BANK(3, 32, "gpio3"),
+};
+
+static struct rockchip_pin_ctrl rk3368_pin_ctrl = {
+ .pin_banks = rk3368_pin_banks,
+ .nr_banks = ARRAY_SIZE(rk3368_pin_banks),
+ .label = "RK3368-GPIO",
+ .type = RK3368,
+ .grf_mux_offset = 0x0,
+ .pmu_mux_offset = 0x0,
+ .pull_calc_reg = rk3368_calc_pull_reg_and_bit,
+ .drv_calc_reg = rk3368_calc_drv_reg_and_bit,
+};
+
+
static const struct of_device_id rockchip_pinctrl_dt_match[] = {
{ .compatible = "rockchip,rk2928-pinctrl",
.data = (void *)&rk2928_pin_ctrl },
@@ -2069,6 +2168,8 @@ static const struct of_device_id rockchip_pinctrl_dt_match[] = {
.data = (void *)&rk3188_pin_ctrl },
{ .compatible = "rockchip,rk3288-pinctrl",
.data = (void *)&rk3288_pin_ctrl },
+ { .compatible = "rockchip,rk3368-pinctrl",
+ .data = (void *)&rk3368_pin_ctrl },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_pinctrl_dt_match);
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 13b45f297727..b2de09d3b1a0 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -1726,7 +1726,7 @@ static int pcs_irqdomain_map(struct irq_domain *d, unsigned int irq,
return 0;
}
-static struct irq_domain_ops pcs_irqdomain_ops = {
+static const struct irq_domain_ops pcs_irqdomain_ops = {
.map = pcs_irqdomain_map,
.xlate = irq_domain_xlate_onecell,
};
@@ -1921,9 +1921,9 @@ static int pcs_probe(struct platform_device *pdev)
goto free;
pcs->pctl = pinctrl_register(&pcs->desc, pcs->dev, pcs);
- if (!pcs->pctl) {
+ if (IS_ERR(pcs->pctl)) {
dev_err(pcs->dev, "could not register single pinctrl driver\n");
- ret = -EINVAL;
+ ret = PTR_ERR(pcs->pctl);
goto free;
}
diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
index 65bf73b70e34..d34ac879af9e 100644
--- a/drivers/pinctrl/pinctrl-st.c
+++ b/drivers/pinctrl/pinctrl-st.c
@@ -1737,9 +1737,9 @@ static int st_pctl_probe(struct platform_device *pdev)
pctl_desc->name = dev_name(&pdev->dev);
info->pctl = pinctrl_register(pctl_desc, &pdev->dev, info);
- if (!info->pctl) {
+ if (IS_ERR(info->pctl)) {
dev_err(&pdev->dev, "Failed pinctrl registration\n");
- return -EINVAL;
+ return PTR_ERR(info->pctl);
}
for (i = 0; i < info->nbanks; i++)
diff --git a/drivers/pinctrl/pinctrl-tb10x.c b/drivers/pinctrl/pinctrl-tb10x.c
index 160a1f5e9896..6546b9bb2e06 100644
--- a/drivers/pinctrl/pinctrl-tb10x.c
+++ b/drivers/pinctrl/pinctrl-tb10x.c
@@ -807,9 +807,9 @@ static int tb10x_pinctrl_probe(struct platform_device *pdev)
}
state->pctl = pinctrl_register(&tb10x_pindesc, dev, state);
- if (!state->pctl) {
+ if (IS_ERR(state->pctl)) {
dev_err(dev, "could not register TB10x pin driver\n");
- ret = -EINVAL;
+ ret = PTR_ERR(state->pctl);
goto fail;
}
diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
index 753d747d4261..2651d04bd1be 100644
--- a/drivers/pinctrl/pinctrl-tegra-xusb.c
+++ b/drivers/pinctrl/pinctrl-tegra-xusb.c
@@ -59,11 +59,6 @@ struct tegra_xusb_padctl_function {
unsigned int num_groups;
};
-struct tegra_xusb_padctl_group {
- const unsigned int *funcs;
- unsigned int num_funcs;
-};
-
struct tegra_xusb_padctl_soc {
const struct pinctrl_pin_desc *pins;
unsigned int num_pins;
@@ -130,6 +125,21 @@ static const char *tegra_xusb_padctl_get_group_name(struct pinctrl_dev *pinctrl,
return padctl->soc->pins[group].name;
}
+static int tegra_xusb_padctl_get_group_pins(struct pinctrl_dev *pinctrl,
+ unsigned group,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ /*
+ * For the tegra-xusb pad controller groups are synonomous
+ * with lanes/pins and there is always one lane/pin per group.
+ */
+ *pins = &pinctrl->desc->pins[group].number;
+ *num_pins = 1;
+
+ return 0;
+}
+
enum tegra_xusb_padctl_param {
TEGRA_XUSB_PADCTL_IDDQ,
};
@@ -253,6 +263,7 @@ static int tegra_xusb_padctl_dt_node_to_map(struct pinctrl_dev *pinctrl,
static const struct pinctrl_ops tegra_xusb_padctl_pinctrl_ops = {
.get_groups_count = tegra_xusb_padctl_get_groups_count,
.get_group_name = tegra_xusb_padctl_get_group_name,
+ .get_group_pins = tegra_xusb_padctl_get_group_pins,
.dt_node_to_map = tegra_xusb_padctl_dt_node_to_map,
.dt_free_map = pinctrl_utils_dt_free_map,
};
@@ -903,15 +914,17 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
memset(&padctl->desc, 0, sizeof(padctl->desc));
padctl->desc.name = dev_name(padctl->dev);
+ padctl->desc.pins = tegra124_pins;
+ padctl->desc.npins = ARRAY_SIZE(tegra124_pins);
padctl->desc.pctlops = &tegra_xusb_padctl_pinctrl_ops;
padctl->desc.pmxops = &tegra_xusb_padctl_pinmux_ops;
padctl->desc.confops = &tegra_xusb_padctl_pinconf_ops;
padctl->desc.owner = THIS_MODULE;
padctl->pinctrl = pinctrl_register(&padctl->desc, &pdev->dev, padctl);
- if (!padctl->pinctrl) {
+ if (IS_ERR(padctl->pinctrl)) {
dev_err(&pdev->dev, "failed to register pincontrol\n");
- err = -ENODEV;
+ err = PTR_ERR(padctl->pinctrl);
goto reset;
}
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index 4c95c2024a1c..0f982b829be1 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -703,9 +703,9 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
}
pmx->pctl = pinctrl_register(&tegra_pinctrl_desc, &pdev->dev, pmx);
- if (!pmx->pctl) {
+ if (IS_ERR(pmx->pctl)) {
dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
- return -ENODEV;
+ return PTR_ERR(pmx->pctl);
}
pinctrl_add_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range);
diff --git a/drivers/pinctrl/pinctrl-tz1090-pdc.c b/drivers/pinctrl/pinctrl-tz1090-pdc.c
index 8a8911bb883a..c349911708ef 100644
--- a/drivers/pinctrl/pinctrl-tz1090-pdc.c
+++ b/drivers/pinctrl/pinctrl-tz1090-pdc.c
@@ -948,9 +948,9 @@ static int tz1090_pdc_pinctrl_probe(struct platform_device *pdev)
return PTR_ERR(pmx->regs);
pmx->pctl = pinctrl_register(&tz1090_pdc_pinctrl_desc, &pdev->dev, pmx);
- if (!pmx->pctl) {
+ if (IS_ERR(pmx->pctl)) {
dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
- return -ENODEV;
+ return PTR_ERR(pmx->pctl);
}
platform_set_drvdata(pdev, pmx);
diff --git a/drivers/pinctrl/pinctrl-tz1090.c b/drivers/pinctrl/pinctrl-tz1090.c
index fc5594a530c2..6d07a2f64d97 100644
--- a/drivers/pinctrl/pinctrl-tz1090.c
+++ b/drivers/pinctrl/pinctrl-tz1090.c
@@ -1963,9 +1963,9 @@ static int tz1090_pinctrl_probe(struct platform_device *pdev)
return PTR_ERR(pmx->regs);
pmx->pctl = pinctrl_register(&tz1090_pinctrl_desc, &pdev->dev, pmx);
- if (!pmx->pctl) {
+ if (IS_ERR(pmx->pctl)) {
dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
- return -ENODEV;
+ return PTR_ERR(pmx->pctl);
}
platform_set_drvdata(pdev, pmx);
diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c
index f931e65aba3a..c076021f37d2 100644
--- a/drivers/pinctrl/pinctrl-u300.c
+++ b/drivers/pinctrl/pinctrl-u300.c
@@ -1068,9 +1068,9 @@ static int u300_pmx_probe(struct platform_device *pdev)
return PTR_ERR(upmx->virtbase);
upmx->pctl = pinctrl_register(&u300_pmx_desc, &pdev->dev, upmx);
- if (!upmx->pctl) {
+ if (IS_ERR(upmx->pctl)) {
dev_err(&pdev->dev, "could not register U300 pinmux driver\n");
- return -EINVAL;
+ return PTR_ERR(upmx->pctl);
}
platform_set_drvdata(pdev, upmx);
diff --git a/drivers/pinctrl/pinctrl-zynq.c b/drivers/pinctrl/pinctrl-zynq.c
index 22280bddb9e2..7ce23b6282ad 100644
--- a/drivers/pinctrl/pinctrl-zynq.c
+++ b/drivers/pinctrl/pinctrl-zynq.c
@@ -101,6 +101,8 @@ enum zynq_pinmux_functions {
ZYNQ_PMUX_qspi_cs1,
ZYNQ_PMUX_spi0,
ZYNQ_PMUX_spi1,
+ ZYNQ_PMUX_spi0_ss,
+ ZYNQ_PMUX_spi1_ss,
ZYNQ_PMUX_sdio0,
ZYNQ_PMUX_sdio0_pc,
ZYNQ_PMUX_sdio0_cd,
@@ -123,7 +125,7 @@ enum zynq_pinmux_functions {
ZYNQ_PMUX_MAX_FUNC
};
-const struct pinctrl_pin_desc zynq_pins[] = {
+static const struct pinctrl_pin_desc zynq_pins[] = {
PINCTRL_PIN(0, "MIO0"),
PINCTRL_PIN(1, "MIO1"),
PINCTRL_PIN(2, "MIO2"),
@@ -196,13 +198,35 @@ static const unsigned int qspi0_0_pins[] = {1, 2, 3, 4, 5, 6};
static const unsigned int qspi1_0_pins[] = {9, 10, 11, 12, 13};
static const unsigned int qspi_cs1_pins[] = {0};
static const unsigned int qspi_fbclk_pins[] = {8};
-static const unsigned int spi0_0_pins[] = {16, 17, 18, 19, 20, 21};
-static const unsigned int spi0_1_pins[] = {28, 29, 30, 31, 32, 33};
-static const unsigned int spi0_2_pins[] = {40, 41, 42, 43, 44, 45};
-static const unsigned int spi1_0_pins[] = {10, 11, 12, 13, 14, 15};
-static const unsigned int spi1_1_pins[] = {22, 23, 24, 25, 26, 27};
-static const unsigned int spi1_2_pins[] = {34, 35, 36, 37, 38, 39};
-static const unsigned int spi1_3_pins[] = {46, 47, 48, 49, 40, 51};
+static const unsigned int spi0_0_pins[] = {16, 17, 21};
+static const unsigned int spi0_0_ss0_pins[] = {18};
+static const unsigned int spi0_0_ss1_pins[] = {19};
+static const unsigned int spi0_0_ss2_pins[] = {20,};
+static const unsigned int spi0_1_pins[] = {28, 29, 33};
+static const unsigned int spi0_1_ss0_pins[] = {30};
+static const unsigned int spi0_1_ss1_pins[] = {31};
+static const unsigned int spi0_1_ss2_pins[] = {32};
+static const unsigned int spi0_2_pins[] = {40, 41, 45};
+static const unsigned int spi0_2_ss0_pins[] = {42};
+static const unsigned int spi0_2_ss1_pins[] = {43};
+static const unsigned int spi0_2_ss2_pins[] = {44};
+static const unsigned int spi1_0_pins[] = {10, 11, 12};
+static const unsigned int spi1_0_ss0_pins[] = {13};
+static const unsigned int spi1_0_ss1_pins[] = {14};
+static const unsigned int spi1_0_ss2_pins[] = {15};
+static const unsigned int spi1_1_pins[] = {22, 23, 24};
+static const unsigned int spi1_1_ss0_pins[] = {25};
+static const unsigned int spi1_1_ss1_pins[] = {26};
+static const unsigned int spi1_1_ss2_pins[] = {27};
+static const unsigned int spi1_2_pins[] = {34, 35, 36};
+static const unsigned int spi1_2_ss0_pins[] = {37};
+static const unsigned int spi1_2_ss1_pins[] = {38};
+static const unsigned int spi1_2_ss2_pins[] = {39};
+static const unsigned int spi1_3_pins[] = {46, 47, 48, 49};
+static const unsigned int spi1_3_ss0_pins[] = {49};
+static const unsigned int spi1_3_ss1_pins[] = {50};
+static const unsigned int spi1_3_ss2_pins[] = {51};
+
static const unsigned int sdio0_0_pins[] = {16, 17, 18, 19, 20, 21};
static const unsigned int sdio0_1_pins[] = {28, 29, 30, 31, 32, 33};
static const unsigned int sdio0_2_pins[] = {40, 41, 42, 43, 44, 45};
@@ -369,7 +393,7 @@ static const unsigned int usb1_0_pins[] = {40, 41, 42, 43, 44, 45, 46, 47, 48,
.npins = ARRAY_SIZE(nm ## _pins), \
}
-struct zynq_pctrl_group zynq_pctrl_groups[] = {
+static const struct zynq_pctrl_group zynq_pctrl_groups[] = {
DEFINE_ZYNQ_PINCTRL_GRP(ethernet0_0),
DEFINE_ZYNQ_PINCTRL_GRP(ethernet1_0),
DEFINE_ZYNQ_PINCTRL_GRP(mdio0_0),
@@ -379,12 +403,33 @@ struct zynq_pctrl_group zynq_pctrl_groups[] = {
DEFINE_ZYNQ_PINCTRL_GRP(qspi_fbclk),
DEFINE_ZYNQ_PINCTRL_GRP(qspi_cs1),
DEFINE_ZYNQ_PINCTRL_GRP(spi0_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi0_0_ss0),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi0_0_ss1),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi0_0_ss2),
DEFINE_ZYNQ_PINCTRL_GRP(spi0_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi0_1_ss0),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi0_1_ss1),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi0_1_ss2),
DEFINE_ZYNQ_PINCTRL_GRP(spi0_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi0_2_ss0),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi0_2_ss1),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi0_2_ss2),
DEFINE_ZYNQ_PINCTRL_GRP(spi1_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_0_ss0),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_0_ss1),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_0_ss2),
DEFINE_ZYNQ_PINCTRL_GRP(spi1_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_1_ss0),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_1_ss1),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_1_ss2),
DEFINE_ZYNQ_PINCTRL_GRP(spi1_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_2_ss0),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_2_ss1),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_2_ss2),
DEFINE_ZYNQ_PINCTRL_GRP(spi1_3),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_3_ss0),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_3_ss1),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_3_ss2),
DEFINE_ZYNQ_PINCTRL_GRP(sdio0_0),
DEFINE_ZYNQ_PINCTRL_GRP(sdio0_1),
DEFINE_ZYNQ_PINCTRL_GRP(sdio0_2),
@@ -552,6 +597,15 @@ static const char * const spi0_groups[] = {"spi0_0_grp", "spi0_1_grp",
"spi0_2_grp"};
static const char * const spi1_groups[] = {"spi1_0_grp", "spi1_1_grp",
"spi1_2_grp", "spi1_3_grp"};
+static const char * const spi0_ss_groups[] = {"spi0_0_ss0_grp",
+ "spi0_0_ss1_grp", "spi0_0_ss2_grp", "spi0_1_ss0_grp",
+ "spi0_1_ss1_grp", "spi0_1_ss2_grp", "spi0_2_ss0_grp",
+ "spi0_2_ss1_grp", "spi0_2_ss2_grp"};
+static const char * const spi1_ss_groups[] = {"spi1_0_ss0_grp",
+ "spi1_0_ss1_grp", "spi1_0_ss2_grp", "spi1_1_ss0_grp",
+ "spi1_1_ss1_grp", "spi1_1_ss2_grp", "spi1_2_ss0_grp",
+ "spi1_2_ss1_grp", "spi1_2_ss2_grp", "spi1_3_ss0_grp",
+ "spi1_3_ss1_grp", "spi1_3_ss2_grp"};
static const char * const sdio0_groups[] = {"sdio0_0_grp", "sdio0_1_grp",
"sdio0_2_grp"};
static const char * const sdio1_groups[] = {"sdio1_0_grp", "sdio1_1_grp",
@@ -714,12 +768,13 @@ static const char * const gpio0_groups[] = {"gpio0_0_grp",
.mux_val = mval, \
}
-#define DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(fname, mval, mux, mask, shift) \
+#define DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(fname, mval, offset, mask, shift)\
[ZYNQ_PMUX_##fname] = { \
.name = #fname, \
.groups = fname##_groups, \
.ngroups = ARRAY_SIZE(fname##_groups), \
.mux_val = mval, \
+ .mux = offset, \
.mux_mask = mask, \
.mux_shift = shift, \
}
@@ -742,17 +797,19 @@ static const struct zynq_pinmux_function zynq_pmux_functions[] = {
DEFINE_ZYNQ_PINMUX_FUNCTION(qspi_cs1, 1),
DEFINE_ZYNQ_PINMUX_FUNCTION(spi0, 0x50),
DEFINE_ZYNQ_PINMUX_FUNCTION(spi1, 0x50),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(spi0_ss, 0x50),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(spi1_ss, 0x50),
DEFINE_ZYNQ_PINMUX_FUNCTION(sdio0, 0x40),
DEFINE_ZYNQ_PINMUX_FUNCTION(sdio0_pc, 0xc),
- DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio0_wp, 0, 130, ZYNQ_SDIO_WP_MASK,
+ DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio0_wp, 0, 0x130, ZYNQ_SDIO_WP_MASK,
ZYNQ_SDIO_WP_SHIFT),
- DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio0_cd, 0, 130, ZYNQ_SDIO_CD_MASK,
+ DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio0_cd, 0, 0x130, ZYNQ_SDIO_CD_MASK,
ZYNQ_SDIO_CD_SHIFT),
DEFINE_ZYNQ_PINMUX_FUNCTION(sdio1, 0x40),
DEFINE_ZYNQ_PINMUX_FUNCTION(sdio1_pc, 0xc),
- DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio1_wp, 0, 134, ZYNQ_SDIO_WP_MASK,
+ DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio1_wp, 0, 0x134, ZYNQ_SDIO_WP_MASK,
ZYNQ_SDIO_WP_SHIFT),
- DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio1_cd, 0, 134, ZYNQ_SDIO_CD_MASK,
+ DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio1_cd, 0, 0x134, ZYNQ_SDIO_CD_MASK,
ZYNQ_SDIO_CD_SHIFT),
DEFINE_ZYNQ_PINMUX_FUNCTION(smc0_nor, 4),
DEFINE_ZYNQ_PINMUX_FUNCTION(smc0_nor_cs1, 8),
@@ -1139,8 +1196,8 @@ static int zynq_pinctrl_probe(struct platform_device *pdev)
pctrl->nfuncs = ARRAY_SIZE(zynq_pmux_functions);
pctrl->pctrl = pinctrl_register(&zynq_desc, &pdev->dev, pctrl);
- if (!pctrl->pctrl)
- return -ENOMEM;
+ if (IS_ERR(pctrl->pctrl))
+ return PTR_ERR(pctrl->pctrl);
platform_set_drvdata(pdev, pctrl);
@@ -1149,7 +1206,7 @@ static int zynq_pinctrl_probe(struct platform_device *pdev)
return 0;
}
-int zynq_pinctrl_remove(struct platform_device *pdev)
+static int zynq_pinctrl_remove(struct platform_device *pdev)
{
struct zynq_pinctrl *pctrl = platform_get_drvdata(pdev);
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index b874458dcb88..e7ae890dcf1a 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -107,6 +107,13 @@ static int pin_request(struct pinctrl_dev *pctldev,
desc->name, desc->gpio_owner, owner);
goto out;
}
+ if (ops->strict && desc->mux_usecount &&
+ strcmp(desc->mux_owner, owner)) {
+ dev_err(pctldev->dev,
+ "pin %s already requested by %s; cannot claim for %s\n",
+ desc->name, desc->mux_owner, owner);
+ goto out;
+ }
desc->gpio_owner = owner;
} else {
@@ -116,6 +123,12 @@ static int pin_request(struct pinctrl_dev *pctldev,
desc->name, desc->mux_owner, owner);
goto out;
}
+ if (ops->strict && desc->gpio_owner) {
+ dev_err(pctldev->dev,
+ "pin %s already requested by %s; cannot claim for %s\n",
+ desc->name, desc->gpio_owner, owner);
+ goto out;
+ }
desc->mux_usecount++;
if (desc->mux_usecount > 1)
@@ -544,9 +557,12 @@ static int pinmux_functions_show(struct seq_file *s, void *what)
ret = pmxops->get_function_groups(pctldev, func_selector,
&groups, &num_groups);
- if (ret)
+ if (ret) {
seq_printf(s, "function %s: COULD NOT GET GROUPS\n",
func);
+ func_selector++;
+ continue;
+ }
seq_printf(s, "function: %s, groups = [ ", func);
for (i = 0; i < num_groups; i++)
@@ -572,7 +588,12 @@ static int pinmux_pins_show(struct seq_file *s, void *what)
return 0;
seq_puts(s, "Pinmux settings per pin\n");
- seq_puts(s, "Format: pin (name): mux_owner gpio_owner hog?\n");
+ if (pmxops->strict)
+ seq_puts(s,
+ "Format: pin (name): mux_owner|gpio_owner (strict) hog?\n");
+ else
+ seq_puts(s,
+ "Format: pin (name): mux_owner gpio_owner hog?\n");
mutex_lock(&pctldev->mutex);
@@ -591,14 +612,34 @@ static int pinmux_pins_show(struct seq_file *s, void *what)
!strcmp(desc->mux_owner, pinctrl_dev_get_name(pctldev)))
is_hog = true;
- seq_printf(s, "pin %d (%s): %s %s%s", pin,
- desc->name ? desc->name : "unnamed",
- desc->mux_owner ? desc->mux_owner
- : "(MUX UNCLAIMED)",
- desc->gpio_owner ? desc->gpio_owner
- : "(GPIO UNCLAIMED)",
- is_hog ? " (HOG)" : "");
+ if (pmxops->strict) {
+ if (desc->mux_owner)
+ seq_printf(s, "pin %d (%s): device %s%s",
+ pin,
+ desc->name ? desc->name : "unnamed",
+ desc->mux_owner,
+ is_hog ? " (HOG)" : "");
+ else if (desc->gpio_owner)
+ seq_printf(s, "pin %d (%s): GPIO %s",
+ pin,
+ desc->name ? desc->name : "unnamed",
+ desc->gpio_owner);
+ else
+ seq_printf(s, "pin %d (%s): UNCLAIMED",
+ pin,
+ desc->name ? desc->name : "unnamed");
+ } else {
+ /* For non-strict controllers */
+ seq_printf(s, "pin %d (%s): %s %s%s", pin,
+ desc->name ? desc->name : "unnamed",
+ desc->mux_owner ? desc->mux_owner
+ : "(MUX UNCLAIMED)",
+ desc->gpio_owner ? desc->gpio_owner
+ : "(GPIO UNCLAIMED)",
+ is_hog ? " (HOG)" : "");
+ }
+ /* If mux: print function+group claiming the pin */
if (desc->mux_setting)
seq_printf(s, " function %s group %s\n",
pmxops->get_function_name(pctldev,
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index ea575f60f001..58f5632b27f4 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -31,6 +31,14 @@ config PINCTRL_IPQ8064
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm TLMM block found in the Qualcomm IPQ8064 platform.
+config PINCTRL_MSM8660
+ tristate "Qualcomm 8660 pin controller driver"
+ depends on GPIOLIB && OF
+ select PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm TLMM block found in the Qualcomm 8660 platform.
+
config PINCTRL_MSM8960
tristate "Qualcomm 8960 pin controller driver"
depends on GPIOLIB && OF
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 68958702917d..3666c703ce88 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_PINCTRL_MSM) += pinctrl-msm.o
obj-$(CONFIG_PINCTRL_APQ8064) += pinctrl-apq8064.o
obj-$(CONFIG_PINCTRL_APQ8084) += pinctrl-apq8084.o
obj-$(CONFIG_PINCTRL_IPQ8064) += pinctrl-ipq8064.o
+obj-$(CONFIG_PINCTRL_MSM8660) += pinctrl-msm8660.o
obj-$(CONFIG_PINCTRL_MSM8960) += pinctrl-msm8960.o
obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o
obj-$(CONFIG_PINCTRL_MSM8916) += pinctrl-msm8916.o
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index f3d800f796c2..e457d52302a2 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -906,9 +906,9 @@ int msm_pinctrl_probe(struct platform_device *pdev,
msm_pinctrl_desc.pins = pctrl->soc->pins;
msm_pinctrl_desc.npins = pctrl->soc->npins;
pctrl->pctrl = pinctrl_register(&msm_pinctrl_desc, &pdev->dev, pctrl);
- if (!pctrl->pctrl) {
+ if (IS_ERR(pctrl->pctrl)) {
dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
- return -ENODEV;
+ return PTR_ERR(pctrl->pctrl);
}
ret = msm_gpio_init(pctrl);
diff --git a/drivers/pinctrl/qcom/pinctrl-msm8660.c b/drivers/pinctrl/qcom/pinctrl-msm8660.c
new file mode 100644
index 000000000000..3e8f7ac2ac8a
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-msm8660.c
@@ -0,0 +1,984 @@
+/*
+ * Copyright (c) 2015, Sony Mobile Communications AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+static const struct pinctrl_pin_desc msm8660_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "GPIO_113"),
+ PINCTRL_PIN(114, "GPIO_114"),
+ PINCTRL_PIN(115, "GPIO_115"),
+ PINCTRL_PIN(116, "GPIO_116"),
+ PINCTRL_PIN(117, "GPIO_117"),
+ PINCTRL_PIN(118, "GPIO_118"),
+ PINCTRL_PIN(119, "GPIO_119"),
+ PINCTRL_PIN(120, "GPIO_120"),
+ PINCTRL_PIN(121, "GPIO_121"),
+ PINCTRL_PIN(122, "GPIO_122"),
+ PINCTRL_PIN(123, "GPIO_123"),
+ PINCTRL_PIN(124, "GPIO_124"),
+ PINCTRL_PIN(125, "GPIO_125"),
+ PINCTRL_PIN(126, "GPIO_126"),
+ PINCTRL_PIN(127, "GPIO_127"),
+ PINCTRL_PIN(128, "GPIO_128"),
+ PINCTRL_PIN(129, "GPIO_129"),
+ PINCTRL_PIN(130, "GPIO_130"),
+ PINCTRL_PIN(131, "GPIO_131"),
+ PINCTRL_PIN(132, "GPIO_132"),
+ PINCTRL_PIN(133, "GPIO_133"),
+ PINCTRL_PIN(134, "GPIO_134"),
+ PINCTRL_PIN(135, "GPIO_135"),
+ PINCTRL_PIN(136, "GPIO_136"),
+ PINCTRL_PIN(137, "GPIO_137"),
+ PINCTRL_PIN(138, "GPIO_138"),
+ PINCTRL_PIN(139, "GPIO_139"),
+ PINCTRL_PIN(140, "GPIO_140"),
+ PINCTRL_PIN(141, "GPIO_141"),
+ PINCTRL_PIN(142, "GPIO_142"),
+ PINCTRL_PIN(143, "GPIO_143"),
+ PINCTRL_PIN(144, "GPIO_144"),
+ PINCTRL_PIN(145, "GPIO_145"),
+ PINCTRL_PIN(146, "GPIO_146"),
+ PINCTRL_PIN(147, "GPIO_147"),
+ PINCTRL_PIN(148, "GPIO_148"),
+ PINCTRL_PIN(149, "GPIO_149"),
+ PINCTRL_PIN(150, "GPIO_150"),
+ PINCTRL_PIN(151, "GPIO_151"),
+ PINCTRL_PIN(152, "GPIO_152"),
+ PINCTRL_PIN(153, "GPIO_153"),
+ PINCTRL_PIN(154, "GPIO_154"),
+ PINCTRL_PIN(155, "GPIO_155"),
+ PINCTRL_PIN(156, "GPIO_156"),
+ PINCTRL_PIN(157, "GPIO_157"),
+ PINCTRL_PIN(158, "GPIO_158"),
+ PINCTRL_PIN(159, "GPIO_159"),
+ PINCTRL_PIN(160, "GPIO_160"),
+ PINCTRL_PIN(161, "GPIO_161"),
+ PINCTRL_PIN(162, "GPIO_162"),
+ PINCTRL_PIN(163, "GPIO_163"),
+ PINCTRL_PIN(164, "GPIO_164"),
+ PINCTRL_PIN(165, "GPIO_165"),
+ PINCTRL_PIN(166, "GPIO_166"),
+ PINCTRL_PIN(167, "GPIO_167"),
+ PINCTRL_PIN(168, "GPIO_168"),
+ PINCTRL_PIN(169, "GPIO_169"),
+ PINCTRL_PIN(170, "GPIO_170"),
+ PINCTRL_PIN(171, "GPIO_171"),
+ PINCTRL_PIN(172, "GPIO_172"),
+
+ PINCTRL_PIN(173, "SDC1_CLK"),
+ PINCTRL_PIN(174, "SDC1_CMD"),
+ PINCTRL_PIN(175, "SDC1_DATA"),
+ PINCTRL_PIN(176, "SDC3_CLK"),
+ PINCTRL_PIN(177, "SDC3_CMD"),
+ PINCTRL_PIN(178, "SDC3_DATA"),
+};
+
+#define DECLARE_MSM_GPIO_PIN(pin) static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PIN(0);
+DECLARE_MSM_GPIO_PIN(1);
+DECLARE_MSM_GPIO_PIN(2);
+DECLARE_MSM_GPIO_PIN(3);
+DECLARE_MSM_GPIO_PIN(4);
+DECLARE_MSM_GPIO_PIN(5);
+DECLARE_MSM_GPIO_PIN(6);
+DECLARE_MSM_GPIO_PIN(7);
+DECLARE_MSM_GPIO_PIN(8);
+DECLARE_MSM_GPIO_PIN(9);
+DECLARE_MSM_GPIO_PIN(10);
+DECLARE_MSM_GPIO_PIN(11);
+DECLARE_MSM_GPIO_PIN(12);
+DECLARE_MSM_GPIO_PIN(13);
+DECLARE_MSM_GPIO_PIN(14);
+DECLARE_MSM_GPIO_PIN(15);
+DECLARE_MSM_GPIO_PIN(16);
+DECLARE_MSM_GPIO_PIN(17);
+DECLARE_MSM_GPIO_PIN(18);
+DECLARE_MSM_GPIO_PIN(19);
+DECLARE_MSM_GPIO_PIN(20);
+DECLARE_MSM_GPIO_PIN(21);
+DECLARE_MSM_GPIO_PIN(22);
+DECLARE_MSM_GPIO_PIN(23);
+DECLARE_MSM_GPIO_PIN(24);
+DECLARE_MSM_GPIO_PIN(25);
+DECLARE_MSM_GPIO_PIN(26);
+DECLARE_MSM_GPIO_PIN(27);
+DECLARE_MSM_GPIO_PIN(28);
+DECLARE_MSM_GPIO_PIN(29);
+DECLARE_MSM_GPIO_PIN(30);
+DECLARE_MSM_GPIO_PIN(31);
+DECLARE_MSM_GPIO_PIN(32);
+DECLARE_MSM_GPIO_PIN(33);
+DECLARE_MSM_GPIO_PIN(34);
+DECLARE_MSM_GPIO_PIN(35);
+DECLARE_MSM_GPIO_PIN(36);
+DECLARE_MSM_GPIO_PIN(37);
+DECLARE_MSM_GPIO_PIN(38);
+DECLARE_MSM_GPIO_PIN(39);
+DECLARE_MSM_GPIO_PIN(40);
+DECLARE_MSM_GPIO_PIN(41);
+DECLARE_MSM_GPIO_PIN(42);
+DECLARE_MSM_GPIO_PIN(43);
+DECLARE_MSM_GPIO_PIN(44);
+DECLARE_MSM_GPIO_PIN(45);
+DECLARE_MSM_GPIO_PIN(46);
+DECLARE_MSM_GPIO_PIN(47);
+DECLARE_MSM_GPIO_PIN(48);
+DECLARE_MSM_GPIO_PIN(49);
+DECLARE_MSM_GPIO_PIN(50);
+DECLARE_MSM_GPIO_PIN(51);
+DECLARE_MSM_GPIO_PIN(52);
+DECLARE_MSM_GPIO_PIN(53);
+DECLARE_MSM_GPIO_PIN(54);
+DECLARE_MSM_GPIO_PIN(55);
+DECLARE_MSM_GPIO_PIN(56);
+DECLARE_MSM_GPIO_PIN(57);
+DECLARE_MSM_GPIO_PIN(58);
+DECLARE_MSM_GPIO_PIN(59);
+DECLARE_MSM_GPIO_PIN(60);
+DECLARE_MSM_GPIO_PIN(61);
+DECLARE_MSM_GPIO_PIN(62);
+DECLARE_MSM_GPIO_PIN(63);
+DECLARE_MSM_GPIO_PIN(64);
+DECLARE_MSM_GPIO_PIN(65);
+DECLARE_MSM_GPIO_PIN(66);
+DECLARE_MSM_GPIO_PIN(67);
+DECLARE_MSM_GPIO_PIN(68);
+DECLARE_MSM_GPIO_PIN(69);
+DECLARE_MSM_GPIO_PIN(70);
+DECLARE_MSM_GPIO_PIN(71);
+DECLARE_MSM_GPIO_PIN(72);
+DECLARE_MSM_GPIO_PIN(73);
+DECLARE_MSM_GPIO_PIN(74);
+DECLARE_MSM_GPIO_PIN(75);
+DECLARE_MSM_GPIO_PIN(76);
+DECLARE_MSM_GPIO_PIN(77);
+DECLARE_MSM_GPIO_PIN(78);
+DECLARE_MSM_GPIO_PIN(79);
+DECLARE_MSM_GPIO_PIN(80);
+DECLARE_MSM_GPIO_PIN(81);
+DECLARE_MSM_GPIO_PIN(82);
+DECLARE_MSM_GPIO_PIN(83);
+DECLARE_MSM_GPIO_PIN(84);
+DECLARE_MSM_GPIO_PIN(85);
+DECLARE_MSM_GPIO_PIN(86);
+DECLARE_MSM_GPIO_PIN(87);
+DECLARE_MSM_GPIO_PIN(88);
+DECLARE_MSM_GPIO_PIN(89);
+DECLARE_MSM_GPIO_PIN(90);
+DECLARE_MSM_GPIO_PIN(91);
+DECLARE_MSM_GPIO_PIN(92);
+DECLARE_MSM_GPIO_PIN(93);
+DECLARE_MSM_GPIO_PIN(94);
+DECLARE_MSM_GPIO_PIN(95);
+DECLARE_MSM_GPIO_PIN(96);
+DECLARE_MSM_GPIO_PIN(97);
+DECLARE_MSM_GPIO_PIN(98);
+DECLARE_MSM_GPIO_PIN(99);
+DECLARE_MSM_GPIO_PIN(100);
+DECLARE_MSM_GPIO_PIN(101);
+DECLARE_MSM_GPIO_PIN(102);
+DECLARE_MSM_GPIO_PIN(103);
+DECLARE_MSM_GPIO_PIN(104);
+DECLARE_MSM_GPIO_PIN(105);
+DECLARE_MSM_GPIO_PIN(106);
+DECLARE_MSM_GPIO_PIN(107);
+DECLARE_MSM_GPIO_PIN(108);
+DECLARE_MSM_GPIO_PIN(109);
+DECLARE_MSM_GPIO_PIN(110);
+DECLARE_MSM_GPIO_PIN(111);
+DECLARE_MSM_GPIO_PIN(112);
+DECLARE_MSM_GPIO_PIN(113);
+DECLARE_MSM_GPIO_PIN(114);
+DECLARE_MSM_GPIO_PIN(115);
+DECLARE_MSM_GPIO_PIN(116);
+DECLARE_MSM_GPIO_PIN(117);
+DECLARE_MSM_GPIO_PIN(118);
+DECLARE_MSM_GPIO_PIN(119);
+DECLARE_MSM_GPIO_PIN(120);
+DECLARE_MSM_GPIO_PIN(121);
+DECLARE_MSM_GPIO_PIN(122);
+DECLARE_MSM_GPIO_PIN(123);
+DECLARE_MSM_GPIO_PIN(124);
+DECLARE_MSM_GPIO_PIN(125);
+DECLARE_MSM_GPIO_PIN(126);
+DECLARE_MSM_GPIO_PIN(127);
+DECLARE_MSM_GPIO_PIN(128);
+DECLARE_MSM_GPIO_PIN(129);
+DECLARE_MSM_GPIO_PIN(130);
+DECLARE_MSM_GPIO_PIN(131);
+DECLARE_MSM_GPIO_PIN(132);
+DECLARE_MSM_GPIO_PIN(133);
+DECLARE_MSM_GPIO_PIN(134);
+DECLARE_MSM_GPIO_PIN(135);
+DECLARE_MSM_GPIO_PIN(136);
+DECLARE_MSM_GPIO_PIN(137);
+DECLARE_MSM_GPIO_PIN(138);
+DECLARE_MSM_GPIO_PIN(139);
+DECLARE_MSM_GPIO_PIN(140);
+DECLARE_MSM_GPIO_PIN(141);
+DECLARE_MSM_GPIO_PIN(142);
+DECLARE_MSM_GPIO_PIN(143);
+DECLARE_MSM_GPIO_PIN(144);
+DECLARE_MSM_GPIO_PIN(145);
+DECLARE_MSM_GPIO_PIN(146);
+DECLARE_MSM_GPIO_PIN(147);
+DECLARE_MSM_GPIO_PIN(148);
+DECLARE_MSM_GPIO_PIN(149);
+DECLARE_MSM_GPIO_PIN(150);
+DECLARE_MSM_GPIO_PIN(151);
+DECLARE_MSM_GPIO_PIN(152);
+DECLARE_MSM_GPIO_PIN(153);
+DECLARE_MSM_GPIO_PIN(154);
+DECLARE_MSM_GPIO_PIN(155);
+DECLARE_MSM_GPIO_PIN(156);
+DECLARE_MSM_GPIO_PIN(157);
+DECLARE_MSM_GPIO_PIN(158);
+DECLARE_MSM_GPIO_PIN(159);
+DECLARE_MSM_GPIO_PIN(160);
+DECLARE_MSM_GPIO_PIN(161);
+DECLARE_MSM_GPIO_PIN(162);
+DECLARE_MSM_GPIO_PIN(163);
+DECLARE_MSM_GPIO_PIN(164);
+DECLARE_MSM_GPIO_PIN(165);
+DECLARE_MSM_GPIO_PIN(166);
+DECLARE_MSM_GPIO_PIN(167);
+DECLARE_MSM_GPIO_PIN(168);
+DECLARE_MSM_GPIO_PIN(169);
+DECLARE_MSM_GPIO_PIN(170);
+DECLARE_MSM_GPIO_PIN(171);
+DECLARE_MSM_GPIO_PIN(172);
+
+static const unsigned int sdc4_clk_pins[] = { 173 };
+static const unsigned int sdc4_cmd_pins[] = { 174 };
+static const unsigned int sdc4_data_pins[] = { 175 };
+static const unsigned int sdc3_clk_pins[] = { 176 };
+static const unsigned int sdc3_cmd_pins[] = { 177 };
+static const unsigned int sdc3_data_pins[] = { 178 };
+
+#define FUNCTION(fname) \
+ [MSM_MUX_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ MSM_MUX_gpio, \
+ MSM_MUX_##f1, \
+ MSM_MUX_##f2, \
+ MSM_MUX_##f3, \
+ MSM_MUX_##f4, \
+ MSM_MUX_##f5, \
+ MSM_MUX_##f6, \
+ MSM_MUX_##f7, \
+ }, \
+ .nfuncs = 8, \
+ .ctl_reg = 0x1000 + 0x10 * id, \
+ .io_reg = 0x1004 + 0x10 * id, \
+ .intr_cfg_reg = 0x1008 + 0x10 * id, \
+ .intr_status_reg = 0x100c + 0x10 * id, \
+ .intr_target_reg = 0x400 + 0x4 * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_ack_high = 1, \
+ .intr_target_bit = 0, \
+ .intr_target_kpss_val = 4, \
+ .intr_raw_status_bit = 3, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 1, \
+ }
+
+#define SDC_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_target_kpss_val = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+enum msm8660_functions {
+ MSM_MUX_gpio,
+ MSM_MUX_cam_mclk,
+ MSM_MUX_dsub,
+ MSM_MUX_ext_gps,
+ MSM_MUX_gp_clk_0a,
+ MSM_MUX_gp_clk_0b,
+ MSM_MUX_gp_clk_1a,
+ MSM_MUX_gp_clk_1b,
+ MSM_MUX_gp_clk_2a,
+ MSM_MUX_gp_clk_2b,
+ MSM_MUX_gp_mn,
+ MSM_MUX_gsbi1,
+ MSM_MUX_gsbi1_spi_cs1_n,
+ MSM_MUX_gsbi1_spi_cs2a_n,
+ MSM_MUX_gsbi1_spi_cs2b_n,
+ MSM_MUX_gsbi1_spi_cs3_n,
+ MSM_MUX_gsbi2,
+ MSM_MUX_gsbi2_spi_cs1_n,
+ MSM_MUX_gsbi2_spi_cs2_n,
+ MSM_MUX_gsbi2_spi_cs3_n,
+ MSM_MUX_gsbi3,
+ MSM_MUX_gsbi3_spi_cs1_n,
+ MSM_MUX_gsbi3_spi_cs2_n,
+ MSM_MUX_gsbi3_spi_cs3_n,
+ MSM_MUX_gsbi4,
+ MSM_MUX_gsbi5,
+ MSM_MUX_gsbi6,
+ MSM_MUX_gsbi7,
+ MSM_MUX_gsbi8,
+ MSM_MUX_gsbi9,
+ MSM_MUX_gsbi10,
+ MSM_MUX_gsbi11,
+ MSM_MUX_gsbi12,
+ MSM_MUX_hdmi,
+ MSM_MUX_i2s,
+ MSM_MUX_lcdc,
+ MSM_MUX_mdp_vsync,
+ MSM_MUX_mi2s,
+ MSM_MUX_pcm,
+ MSM_MUX_ps_hold,
+ MSM_MUX_sdc1,
+ MSM_MUX_sdc2,
+ MSM_MUX_sdc5,
+ MSM_MUX_tsif1,
+ MSM_MUX_tsif2,
+ MSM_MUX_usb_fs1,
+ MSM_MUX_usb_fs1_oe_n,
+ MSM_MUX_usb_fs2,
+ MSM_MUX_usb_fs2_oe_n,
+ MSM_MUX_vfe,
+ MSM_MUX_vsens_alarm,
+ MSM_MUX__,
+};
+
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+ "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+ "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+ "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+ "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+ "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+ "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+ "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+ "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+ "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+ "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134",
+ "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140",
+ "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146",
+ "gpio147", "gpio148", "gpio149", "gpio150", "gpio151", "gpio152",
+ "gpio153", "gpio154", "gpio155", "gpio156", "gpio157", "gpio158",
+ "gpio159", "gpio160", "gpio161", "gpio162", "gpio163", "gpio164",
+ "gpio165", "gpio166", "gpio167", "gpio168", "gpio169", "gpio170",
+ "gpio171", "gpio172"
+};
+
+static const char * const cam_mclk_groups[] = {
+ "gpio32"
+};
+static const char * const dsub_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27"
+};
+static const char * const ext_gps_groups[] = {
+ "gpio66", "gpio67", "gpio68", "gpio69"
+};
+static const char * const gp_clk_0a_groups[] = {
+ "gpio30"
+};
+static const char * const gp_clk_0b_groups[] = {
+ "gpio115"
+};
+static const char * const gp_clk_1a_groups[] = {
+ "gpio31"
+};
+static const char * const gp_clk_1b_groups[] = {
+ "gpio122"
+};
+static const char * const gp_clk_2a_groups[] = {
+ "gpio103"
+};
+static const char * const gp_clk_2b_groups[] = {
+ "gpio70"
+};
+static const char * const gp_mn_groups[] = {
+ "gpio29"
+};
+static const char * const gsbi1_groups[] = {
+ "gpio33", "gpio34", "gpio35", "gpio36"
+};
+static const char * const gsbi1_spi_cs1_n_groups[] = {
+};
+static const char * const gsbi1_spi_cs2a_n_groups[] = {
+};
+static const char * const gsbi1_spi_cs2b_n_groups[] = {
+};
+static const char * const gsbi1_spi_cs3_n_groups[] = {
+};
+static const char * const gsbi2_groups[] = {
+ "gpio37", "gpio38", "gpio39", "gpio40"
+};
+static const char * const gsbi2_spi_cs1_n_groups[] = {
+ "gpio123"
+};
+static const char * const gsbi2_spi_cs2_n_groups[] = {
+ "gpio124"
+};
+static const char * const gsbi2_spi_cs3_n_groups[] = {
+ "gpio125"
+};
+static const char * const gsbi3_groups[] = {
+ "gpio41", "gpio42", "gpio43", "gpio44"
+};
+static const char * const gsbi3_spi_cs1_n_groups[] = {
+ "gpio62"
+};
+static const char * const gsbi3_spi_cs2_n_groups[] = {
+ "gpio45"
+};
+static const char * const gsbi3_spi_cs3_n_groups[] = {
+ "gpio46"
+};
+static const char * const gsbi4_groups[] = {
+ "gpio45", "gpio56", "gpio47", "gpio48"
+};
+static const char * const gsbi5_groups[] = {
+ "gpio49", "gpio50", "gpio51", "gpio52"
+};
+static const char * const gsbi6_groups[] = {
+ "gpio53", "gpio54", "gpio55", "gpio56"
+};
+static const char * const gsbi7_groups[] = {
+ "gpio57", "gpio58", "gpio59", "gpio60"
+};
+static const char * const gsbi8_groups[] = {
+ "gpio62", "gpio63", "gpio64", "gpio65"
+};
+static const char * const gsbi9_groups[] = {
+ "gpio66", "gpio67", "gpio68", "gpio69"
+};
+static const char * const gsbi10_groups[] = {
+ "gpio70", "gpio71", "gpio72", "gpio73"
+};
+static const char * const gsbi11_groups[] = {
+ "gpio103", "gpio104", "gpio105", "gpio106"
+};
+static const char * const gsbi12_groups[] = {
+ "gpio115", "gpio116", "gpio117", "gpio118"
+};
+static const char * const hdmi_groups[] = {
+ "gpio169", "gpio170", "gpio171", "gpio172"
+};
+static const char * const i2s_groups[] = {
+ "gpio108", "gpio109", "gpio110", "gpio115", "gpio116", "gpio117",
+ "gpio118", "gpio119", "gpio120", "gpio121", "gpio122"
+};
+static const char * const lcdc_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27"
+};
+static const char * const mdp_vsync_groups[] = {
+ "gpio28", "gpio39", "gpio41"
+};
+static const char * const mi2s_groups[] = {
+ "gpio101", "gpio102", "gpio103", "gpio104", "gpio105", "gpio106",
+ "gpio107"
+};
+static const char * const pcm_groups[] = {
+ "gpio111", "gpio112", "gpio113", "gpio114"
+};
+static const char * const ps_hold_groups[] = {
+ "gpio92"
+};
+static const char * const sdc1_groups[] = {
+ "gpio159", "gpio160", "gpio161", "gpio162", "gpio163", "gpio164",
+ "gpio165", "gpio166", "gpio167", "gpio168"
+};
+static const char * const sdc2_groups[] = {
+ "gpio143", "gpio144", "gpio145", "gpio146", "gpio147", "gpio148",
+ "gpio149", "gpio150", "gpio151", "gpio152"
+};
+static const char * const sdc5_groups[] = {
+ "gpio95", "gpio96", "gpio97", "gpio98", "gpio99", "gpio100"
+};
+static const char * const tsif1_groups[] = {
+ "gpio93", "gpio94", "gpio95", "gpio96"
+};
+static const char * const tsif2_groups[] = {
+ "gpio97", "gpio98", "gpio99", "gpio100"
+};
+static const char * const usb_fs1_groups[] = {
+ "gpio49", "gpio50", "gpio51"
+};
+static const char * const usb_fs1_oe_n_groups[] = {
+ "gpio51"
+};
+static const char * const usb_fs2_groups[] = {
+ "gpio71", "gpio72", "gpio73"
+};
+static const char * const usb_fs2_oe_n_groups[] = {
+ "gpio73"
+};
+static const char * const vfe_groups[] = {
+ "gpio29", "gpio30", "gpio31", "gpio42", "gpio46", "gpio105", "gpio106",
+ "gpio117"
+};
+static const char * const vsens_alarm_groups[] = {
+ "gpio127"
+};
+
+static const struct msm_function msm8660_functions[] = {
+ FUNCTION(gpio),
+ FUNCTION(cam_mclk),
+ FUNCTION(dsub),
+ FUNCTION(ext_gps),
+ FUNCTION(gp_clk_0a),
+ FUNCTION(gp_clk_0b),
+ FUNCTION(gp_clk_1a),
+ FUNCTION(gp_clk_1b),
+ FUNCTION(gp_clk_2a),
+ FUNCTION(gp_clk_2b),
+ FUNCTION(gp_mn),
+ FUNCTION(gsbi1),
+ FUNCTION(gsbi1_spi_cs1_n),
+ FUNCTION(gsbi1_spi_cs2a_n),
+ FUNCTION(gsbi1_spi_cs2b_n),
+ FUNCTION(gsbi1_spi_cs3_n),
+ FUNCTION(gsbi2),
+ FUNCTION(gsbi2_spi_cs1_n),
+ FUNCTION(gsbi2_spi_cs2_n),
+ FUNCTION(gsbi2_spi_cs3_n),
+ FUNCTION(gsbi3),
+ FUNCTION(gsbi3_spi_cs1_n),
+ FUNCTION(gsbi3_spi_cs2_n),
+ FUNCTION(gsbi3_spi_cs3_n),
+ FUNCTION(gsbi4),
+ FUNCTION(gsbi5),
+ FUNCTION(gsbi6),
+ FUNCTION(gsbi7),
+ FUNCTION(gsbi8),
+ FUNCTION(gsbi9),
+ FUNCTION(gsbi10),
+ FUNCTION(gsbi11),
+ FUNCTION(gsbi12),
+ FUNCTION(hdmi),
+ FUNCTION(i2s),
+ FUNCTION(lcdc),
+ FUNCTION(mdp_vsync),
+ FUNCTION(mi2s),
+ FUNCTION(pcm),
+ FUNCTION(ps_hold),
+ FUNCTION(sdc1),
+ FUNCTION(sdc2),
+ FUNCTION(sdc5),
+ FUNCTION(tsif1),
+ FUNCTION(tsif2),
+ FUNCTION(usb_fs1),
+ FUNCTION(usb_fs1_oe_n),
+ FUNCTION(usb_fs2),
+ FUNCTION(usb_fs2_oe_n),
+ FUNCTION(vfe),
+ FUNCTION(vsens_alarm),
+};
+
+static const struct msm_pingroup msm8660_groups[] = {
+ PINGROUP(0, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(1, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(2, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(3, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(4, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(5, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(6, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(7, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(8, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(9, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(10, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(11, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(12, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(13, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(14, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(15, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(16, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(17, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(18, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(19, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(20, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(21, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(22, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(23, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(24, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(25, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(26, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(27, lcdc, dsub, _, _, _, _, _),
+ PINGROUP(28, mdp_vsync, _, _, _, _, _, _),
+ PINGROUP(29, vfe, gp_mn, _, _, _, _, _),
+ PINGROUP(30, vfe, gp_clk_0a, _, _, _, _, _),
+ PINGROUP(31, vfe, gp_clk_1a, _, _, _, _, _),
+ PINGROUP(32, cam_mclk, _, _, _, _, _, _),
+ PINGROUP(33, gsbi1, _, _, _, _, _, _),
+ PINGROUP(34, gsbi1, _, _, _, _, _, _),
+ PINGROUP(35, gsbi1, _, _, _, _, _, _),
+ PINGROUP(36, gsbi1, _, _, _, _, _, _),
+ PINGROUP(37, gsbi2, _, _, _, _, _, _),
+ PINGROUP(38, gsbi2, _, _, _, _, _, _),
+ PINGROUP(39, gsbi2, _, mdp_vsync, _, _, _, _),
+ PINGROUP(40, gsbi2, _, _, _, _, _, _),
+ PINGROUP(41, gsbi3, mdp_vsync, _, _, _, _, _),
+ PINGROUP(42, gsbi3, vfe, _, _, _, _, _),
+ PINGROUP(43, gsbi3, _, _, _, _, _, _),
+ PINGROUP(44, gsbi3, _, _, _, _, _, _),
+ PINGROUP(45, gsbi4, gsbi3_spi_cs2_n, _, _, _, _, _),
+ PINGROUP(46, gsbi4, gsbi3_spi_cs3_n, vfe, _, _, _, _),
+ PINGROUP(47, gsbi4, _, _, _, _, _, _),
+ PINGROUP(48, gsbi4, _, _, _, _, _, _),
+ PINGROUP(49, gsbi5, usb_fs1, _, _, _, _, _),
+ PINGROUP(50, gsbi5, usb_fs1, _, _, _, _, _),
+ PINGROUP(51, gsbi5, usb_fs1, usb_fs1_oe_n, _, _, _, _),
+ PINGROUP(52, gsbi5, _, _, _, _, _, _),
+ PINGROUP(53, gsbi6, _, _, _, _, _, _),
+ PINGROUP(54, gsbi6, _, _, _, _, _, _),
+ PINGROUP(55, gsbi6, _, _, _, _, _, _),
+ PINGROUP(56, gsbi6, _, _, _, _, _, _),
+ PINGROUP(57, gsbi7, _, _, _, _, _, _),
+ PINGROUP(58, gsbi7, _, _, _, _, _, _),
+ PINGROUP(59, gsbi7, _, _, _, _, _, _),
+ PINGROUP(60, gsbi7, _, _, _, _, _, _),
+ PINGROUP(61, _, _, _, _, _, _, _),
+ PINGROUP(62, gsbi8, gsbi3_spi_cs1_n, gsbi1_spi_cs2a_n, _, _, _, _),
+ PINGROUP(63, gsbi8, gsbi1_spi_cs1_n, _, _, _, _, _),
+ PINGROUP(64, gsbi8, gsbi1_spi_cs2b_n, _, _, _, _, _),
+ PINGROUP(65, gsbi8, gsbi1_spi_cs3_n, _, _, _, _, _),
+ PINGROUP(66, gsbi9, ext_gps, _, _, _, _, _),
+ PINGROUP(67, gsbi9, ext_gps, _, _, _, _, _),
+ PINGROUP(68, gsbi9, ext_gps, _, _, _, _, _),
+ PINGROUP(69, gsbi9, ext_gps, _, _, _, _, _),
+ PINGROUP(70, gsbi10, gp_clk_2b, _, _, _, _, _),
+ PINGROUP(71, gsbi10, usb_fs2, _, _, _, _, _),
+ PINGROUP(72, gsbi10, usb_fs2, _, _, _, _, _),
+ PINGROUP(73, gsbi10, usb_fs2, usb_fs2_oe_n, _, _, _, _),
+ PINGROUP(74, _, _, _, _, _, _, _),
+ PINGROUP(75, _, _, _, _, _, _, _),
+ PINGROUP(76, _, _, _, _, _, _, _),
+ PINGROUP(77, _, _, _, _, _, _, _),
+ PINGROUP(78, _, _, _, _, _, _, _),
+ PINGROUP(79, _, _, _, _, _, _, _),
+ PINGROUP(80, _, _, _, _, _, _, _),
+ PINGROUP(81, _, _, _, _, _, _, _),
+ PINGROUP(82, _, _, _, _, _, _, _),
+ PINGROUP(83, _, _, _, _, _, _, _),
+ PINGROUP(84, _, _, _, _, _, _, _),
+ PINGROUP(85, _, _, _, _, _, _, _),
+ PINGROUP(86, _, _, _, _, _, _, _),
+ PINGROUP(87, _, _, _, _, _, _, _),
+ PINGROUP(88, _, _, _, _, _, _, _),
+ PINGROUP(89, _, _, _, _, _, _, _),
+ PINGROUP(90, _, _, _, _, _, _, _),
+ PINGROUP(91, _, _, _, _, _, _, _),
+ PINGROUP(92, ps_hold, _, _, _, _, _, _),
+ PINGROUP(93, tsif1, _, _, _, _, _, _),
+ PINGROUP(94, tsif1, _, _, _, _, _, _),
+ PINGROUP(95, tsif1, sdc5, _, _, _, _, _),
+ PINGROUP(96, tsif1, sdc5, _, _, _, _, _),
+ PINGROUP(97, tsif2, sdc5, _, _, _, _, _),
+ PINGROUP(98, tsif2, sdc5, _, _, _, _, _),
+ PINGROUP(99, tsif2, sdc5, _, _, _, _, _),
+ PINGROUP(100, tsif2, sdc5, _, _, _, _, _),
+ PINGROUP(101, mi2s, _, _, _, _, _, _),
+ PINGROUP(102, mi2s, _, _, _, _, _, _),
+ PINGROUP(103, mi2s, gsbi11, gp_clk_2a, _, _, _, _),
+ PINGROUP(104, mi2s, gsbi11, _, _, _, _, _),
+ PINGROUP(105, mi2s, gsbi11, vfe, _, _, _, _),
+ PINGROUP(106, mi2s, gsbi11, vfe, _, _, _, _),
+ PINGROUP(107, mi2s, _, _, _, _, _, _),
+ PINGROUP(108, i2s, _, _, _, _, _, _),
+ PINGROUP(109, i2s, _, _, _, _, _, _),
+ PINGROUP(110, i2s, _, _, _, _, _, _),
+ PINGROUP(111, pcm, _, _, _, _, _, _),
+ PINGROUP(112, pcm, _, _, _, _, _, _),
+ PINGROUP(113, pcm, _, _, _, _, _, _),
+ PINGROUP(114, pcm, _, _, _, _, _, _),
+ PINGROUP(115, i2s, gsbi12, gp_clk_0b, _, _, _, _),
+ PINGROUP(116, i2s, gsbi12, _, _, _, _, _),
+ PINGROUP(117, i2s, gsbi12, vfe, _, _, _, _),
+ PINGROUP(118, i2s, gsbi12, _, _, _, _, _),
+ PINGROUP(119, i2s, _, _, _, _, _, _),
+ PINGROUP(120, i2s, _, _, _, _, _, _),
+ PINGROUP(121, i2s, _, _, _, _, _, _),
+ PINGROUP(122, i2s, gp_clk_1b, _, _, _, _, _),
+ PINGROUP(123, _, gsbi2_spi_cs1_n, _, _, _, _, _),
+ PINGROUP(124, _, gsbi2_spi_cs2_n, _, _, _, _, _),
+ PINGROUP(125, _, gsbi2_spi_cs3_n, _, _, _, _, _),
+ PINGROUP(126, _, _, _, _, _, _, _),
+ PINGROUP(127, _, vsens_alarm, _, _, _, _, _),
+ PINGROUP(128, _, _, _, _, _, _, _),
+ PINGROUP(129, _, _, _, _, _, _, _),
+ PINGROUP(130, _, _, _, _, _, _, _),
+ PINGROUP(131, _, _, _, _, _, _, _),
+ PINGROUP(132, _, _, _, _, _, _, _),
+ PINGROUP(133, _, _, _, _, _, _, _),
+ PINGROUP(134, _, _, _, _, _, _, _),
+ PINGROUP(135, _, _, _, _, _, _, _),
+ PINGROUP(136, _, _, _, _, _, _, _),
+ PINGROUP(137, _, _, _, _, _, _, _),
+ PINGROUP(138, _, _, _, _, _, _, _),
+ PINGROUP(139, _, _, _, _, _, _, _),
+ PINGROUP(140, _, _, _, _, _, _, _),
+ PINGROUP(141, _, _, _, _, _, _, _),
+ PINGROUP(142, _, _, _, _, _, _, _),
+ PINGROUP(143, _, sdc2, _, _, _, _, _),
+ PINGROUP(144, _, sdc2, _, _, _, _, _),
+ PINGROUP(145, _, sdc2, _, _, _, _, _),
+ PINGROUP(146, _, sdc2, _, _, _, _, _),
+ PINGROUP(147, _, sdc2, _, _, _, _, _),
+ PINGROUP(148, _, sdc2, _, _, _, _, _),
+ PINGROUP(149, _, sdc2, _, _, _, _, _),
+ PINGROUP(150, _, sdc2, _, _, _, _, _),
+ PINGROUP(151, _, sdc2, _, _, _, _, _),
+ PINGROUP(152, _, sdc2, _, _, _, _, _),
+ PINGROUP(153, _, _, _, _, _, _, _),
+ PINGROUP(154, _, _, _, _, _, _, _),
+ PINGROUP(155, _, _, _, _, _, _, _),
+ PINGROUP(156, _, _, _, _, _, _, _),
+ PINGROUP(157, _, _, _, _, _, _, _),
+ PINGROUP(158, _, _, _, _, _, _, _),
+ PINGROUP(159, sdc1, _, _, _, _, _, _),
+ PINGROUP(160, sdc1, _, _, _, _, _, _),
+ PINGROUP(161, sdc1, _, _, _, _, _, _),
+ PINGROUP(162, sdc1, _, _, _, _, _, _),
+ PINGROUP(163, sdc1, _, _, _, _, _, _),
+ PINGROUP(164, sdc1, _, _, _, _, _, _),
+ PINGROUP(165, sdc1, _, _, _, _, _, _),
+ PINGROUP(166, sdc1, _, _, _, _, _, _),
+ PINGROUP(167, sdc1, _, _, _, _, _, _),
+ PINGROUP(168, sdc1, _, _, _, _, _, _),
+ PINGROUP(169, hdmi, _, _, _, _, _, _),
+ PINGROUP(170, hdmi, _, _, _, _, _, _),
+ PINGROUP(171, hdmi, _, _, _, _, _, _),
+ PINGROUP(172, hdmi, _, _, _, _, _, _),
+
+ SDC_PINGROUP(sdc4_clk, 0x20a0, -1, 6),
+ SDC_PINGROUP(sdc4_cmd, 0x20a0, 11, 3),
+ SDC_PINGROUP(sdc4_data, 0x20a0, 9, 0),
+
+ SDC_PINGROUP(sdc3_clk, 0x20a4, -1, 6),
+ SDC_PINGROUP(sdc3_cmd, 0x20a4, 11, 3),
+ SDC_PINGROUP(sdc3_data, 0x20a4, 9, 0),
+};
+
+#define NUM_GPIO_PINGROUPS 173
+
+static const struct msm_pinctrl_soc_data msm8660_pinctrl = {
+ .pins = msm8660_pins,
+ .npins = ARRAY_SIZE(msm8660_pins),
+ .functions = msm8660_functions,
+ .nfunctions = ARRAY_SIZE(msm8660_functions),
+ .groups = msm8660_groups,
+ .ngroups = ARRAY_SIZE(msm8660_groups),
+ .ngpios = NUM_GPIO_PINGROUPS,
+};
+
+static int msm8660_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &msm8660_pinctrl);
+}
+
+static const struct of_device_id msm8660_pinctrl_of_match[] = {
+ { .compatible = "qcom,msm8660-pinctrl", },
+ { },
+};
+
+static struct platform_driver msm8660_pinctrl_driver = {
+ .driver = {
+ .name = "msm8660-pinctrl",
+ .of_match_table = msm8660_pinctrl_of_match,
+ },
+ .probe = msm8660_pinctrl_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init msm8660_pinctrl_init(void)
+{
+ return platform_driver_register(&msm8660_pinctrl_driver);
+}
+arch_initcall(msm8660_pinctrl_init);
+
+static void __exit msm8660_pinctrl_exit(void)
+{
+ platform_driver_unregister(&msm8660_pinctrl_driver);
+}
+module_exit(msm8660_pinctrl_exit);
+
+MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
+MODULE_DESCRIPTION("Qualcomm MSM8660 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, msm8660_pinctrl_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index ae4115e4b4ef..bd1e24598e12 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -778,8 +778,8 @@ static int pmic_gpio_probe(struct platform_device *pdev)
state->chip.can_sleep = false;
state->ctrl = pinctrl_register(pctrldesc, dev, state);
- if (!state->ctrl)
- return -ENODEV;
+ if (IS_ERR(state->ctrl))
+ return PTR_ERR(state->ctrl);
ret = gpiochip_add(&state->chip);
if (ret) {
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
index 211b942ad6d5..3121de9b6331 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
@@ -892,8 +892,8 @@ static int pmic_mpp_probe(struct platform_device *pdev)
state->chip.can_sleep = false;
state->ctrl = pinctrl_register(pctrldesc, dev, state);
- if (!state->ctrl)
- return -ENODEV;
+ if (IS_ERR(state->ctrl))
+ return PTR_ERR(state->ctrl);
ret = gpiochip_add(&state->chip);
if (ret) {
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos5440.c b/drivers/pinctrl/samsung/pinctrl-exynos5440.c
index 86192be3b679..f5619fb50447 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos5440.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos5440.c
@@ -822,9 +822,9 @@ static int exynos5440_pinctrl_register(struct platform_device *pdev,
return ret;
pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, priv);
- if (!pctl_dev) {
+ if (IS_ERR(pctl_dev)) {
dev_err(&pdev->dev, "could not register pinctrl driver\n");
- return -EINVAL;
+ return PTR_ERR(pctl_dev);
}
grange.name = "exynos5440-pctrl-gpio-range";
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c
index ed165ba2eb2f..3dd5a3b2ac62 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.c
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.c
@@ -806,7 +806,7 @@ static int samsung_pinctrl_parse_dt(struct platform_device *pdev,
functions = samsung_pinctrl_create_functions(dev, drvdata, &func_cnt);
if (IS_ERR(functions)) {
dev_err(dev, "failed to parse pin functions\n");
- return PTR_ERR(groups);
+ return PTR_ERR(functions);
}
drvdata->pin_groups = groups;
@@ -873,9 +873,9 @@ static int samsung_pinctrl_register(struct platform_device *pdev,
return ret;
drvdata->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, drvdata);
- if (!drvdata->pctl_dev) {
+ if (IS_ERR(drvdata->pctl_dev)) {
dev_err(&pdev->dev, "could not register pinctrl driver\n");
- return -EINVAL;
+ return PTR_ERR(drvdata->pctl_dev);
}
for (bank = 0; bank < drvdata->nr_banks; ++bank) {
diff --git a/drivers/pinctrl/sh-pfc/Kconfig b/drivers/pinctrl/sh-pfc/Kconfig
index 8c4b3d391823..8e024c9c9115 100644
--- a/drivers/pinctrl/sh-pfc/Kconfig
+++ b/drivers/pinctrl/sh-pfc/Kconfig
@@ -55,6 +55,16 @@ config PINCTRL_PFC_R8A7791
depends on ARCH_R8A7791
select PINCTRL_SH_PFC
+config PINCTRL_PFC_R8A7793
+ def_bool y
+ depends on ARCH_R8A7793
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_R8A7794
+ def_bool y
+ depends on ARCH_R8A7794
+ select PINCTRL_SH_PFC
+
config PINCTRL_PFC_SH7203
def_bool y
depends on CPU_SUBTYPE_SH7203
diff --git a/drivers/pinctrl/sh-pfc/Makefile b/drivers/pinctrl/sh-pfc/Makefile
index f4074e166bcf..ea2a60ef122a 100644
--- a/drivers/pinctrl/sh-pfc/Makefile
+++ b/drivers/pinctrl/sh-pfc/Makefile
@@ -10,6 +10,8 @@ obj-$(CONFIG_PINCTRL_PFC_R8A7778) += pfc-r8a7778.o
obj-$(CONFIG_PINCTRL_PFC_R8A7779) += pfc-r8a7779.o
obj-$(CONFIG_PINCTRL_PFC_R8A7790) += pfc-r8a7790.o
obj-$(CONFIG_PINCTRL_PFC_R8A7791) += pfc-r8a7791.o
+obj-$(CONFIG_PINCTRL_PFC_R8A7793) += pfc-r8a7791.o
+obj-$(CONFIG_PINCTRL_PFC_R8A7794) += pfc-r8a7794.o
obj-$(CONFIG_PINCTRL_PFC_SH7203) += pfc-sh7203.o
obj-$(CONFIG_PINCTRL_PFC_SH7264) += pfc-sh7264.o
obj-$(CONFIG_PINCTRL_PFC_SH7269) += pfc-sh7269.o
diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c
index 7b2c9495c383..865d235612c5 100644
--- a/drivers/pinctrl/sh-pfc/core.c
+++ b/drivers/pinctrl/sh-pfc/core.c
@@ -481,6 +481,18 @@ static const struct of_device_id sh_pfc_of_table[] = {
.data = &r8a7791_pinmux_info,
},
#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A7793
+ {
+ .compatible = "renesas,pfc-r8a7793",
+ .data = &r8a7793_pinmux_info,
+ },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A7794
+ {
+ .compatible = "renesas,pfc-r8a7794",
+ .data = &r8a7794_pinmux_info,
+ },
+#endif
#ifdef CONFIG_PINCTRL_PFC_SH73A0
{
.compatible = "renesas,pfc-sh73a0",
@@ -579,9 +591,6 @@ static int sh_pfc_remove(struct platform_device *pdev)
}
static const struct platform_device_id sh_pfc_id_table[] = {
-#ifdef CONFIG_PINCTRL_PFC_R8A73A4
- { "pfc-r8a73a4", (kernel_ulong_t)&r8a73a4_pinmux_info },
-#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7740
{ "pfc-r8a7740", (kernel_ulong_t)&r8a7740_pinmux_info },
#endif
diff --git a/drivers/pinctrl/sh-pfc/core.h b/drivers/pinctrl/sh-pfc/core.h
index 6dc8a6fc2746..4c3c37bf7161 100644
--- a/drivers/pinctrl/sh-pfc/core.h
+++ b/drivers/pinctrl/sh-pfc/core.h
@@ -71,6 +71,8 @@ extern const struct sh_pfc_soc_info r8a7778_pinmux_info;
extern const struct sh_pfc_soc_info r8a7779_pinmux_info;
extern const struct sh_pfc_soc_info r8a7790_pinmux_info;
extern const struct sh_pfc_soc_info r8a7791_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7793_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7794_pinmux_info;
extern const struct sh_pfc_soc_info sh7203_pinmux_info;
extern const struct sh_pfc_soc_info sh7264_pinmux_info;
extern const struct sh_pfc_soc_info sh7269_pinmux_info;
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c b/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c
index 280a56f97786..ba18d2e65e67 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c
@@ -21,10 +21,6 @@
#include <linux/kernel.h>
#include <linux/pinctrl/pinconf-generic.h>
-#ifndef CONFIG_ARCH_MULTIPLATFORM
-#include <mach/irqs.h>
-#endif
-
#include "core.h"
#include "sh_pfc.h"
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
index b486e9d20cc2..d0bb1459783a 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
@@ -258,7 +258,7 @@ enum {
/* SCIFA7 */
SCIFA7_TXD_MARK, SCIFA7_RXD_MARK,
- /* SCIFAB */
+ /* SCIFB */
SCIFB_SCK_PORT190_MARK, /* MSEL5CR_17_0 */
SCIFB_RXD_PORT191_MARK,
SCIFB_TXD_PORT192_MARK,
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
index 22a5470889f5..baab81ead9ff 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
@@ -2664,6 +2664,61 @@ static const unsigned int msiof3_tx_b_pins[] = {
static const unsigned int msiof3_tx_b_mux[] = {
MSIOF3_TXD_B_MARK,
};
+/* - PWM -------------------------------------------------------------------- */
+static const unsigned int pwm0_pins[] = {
+ RCAR_GP_PIN(5, 29),
+};
+static const unsigned int pwm0_mux[] = {
+ PWM0_MARK,
+};
+static const unsigned int pwm0_b_pins[] = {
+ RCAR_GP_PIN(4, 30),
+};
+static const unsigned int pwm0_b_mux[] = {
+ PWM0_B_MARK,
+};
+static const unsigned int pwm1_pins[] = {
+ RCAR_GP_PIN(5, 30),
+};
+static const unsigned int pwm1_mux[] = {
+ PWM1_MARK,
+};
+static const unsigned int pwm1_b_pins[] = {
+ RCAR_GP_PIN(4, 31),
+};
+static const unsigned int pwm1_b_mux[] = {
+ PWM1_B_MARK,
+};
+static const unsigned int pwm2_pins[] = {
+ RCAR_GP_PIN(5, 31),
+};
+static const unsigned int pwm2_mux[] = {
+ PWM2_MARK,
+};
+static const unsigned int pwm3_pins[] = {
+ RCAR_GP_PIN(0, 16),
+};
+static const unsigned int pwm3_mux[] = {
+ PWM3_MARK,
+};
+static const unsigned int pwm4_pins[] = {
+ RCAR_GP_PIN(0, 17),
+};
+static const unsigned int pwm4_mux[] = {
+ PWM4_MARK,
+};
+static const unsigned int pwm5_pins[] = {
+ RCAR_GP_PIN(0, 18),
+};
+static const unsigned int pwm5_mux[] = {
+ PWM5_MARK,
+};
+static const unsigned int pwm6_pins[] = {
+ RCAR_GP_PIN(0, 19),
+};
+static const unsigned int pwm6_mux[] = {
+ PWM6_MARK,
+};
/* - QSPI ------------------------------------------------------------------- */
static const unsigned int qspi_ctrl_pins[] = {
/* SPCLK, SSL */
@@ -4008,6 +4063,15 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(msiof3_sync_b),
SH_PFC_PIN_GROUP(msiof3_rx_b),
SH_PFC_PIN_GROUP(msiof3_tx_b),
+ SH_PFC_PIN_GROUP(pwm0),
+ SH_PFC_PIN_GROUP(pwm0_b),
+ SH_PFC_PIN_GROUP(pwm1),
+ SH_PFC_PIN_GROUP(pwm1_b),
+ SH_PFC_PIN_GROUP(pwm2),
+ SH_PFC_PIN_GROUP(pwm3),
+ SH_PFC_PIN_GROUP(pwm4),
+ SH_PFC_PIN_GROUP(pwm5),
+ SH_PFC_PIN_GROUP(pwm6),
SH_PFC_PIN_GROUP(qspi_ctrl),
SH_PFC_PIN_GROUP(qspi_data2),
SH_PFC_PIN_GROUP(qspi_data4),
@@ -4364,6 +4428,36 @@ static const char * const msiof3_groups[] = {
"msiof3_tx_b",
};
+static const char * const pwm0_groups[] = {
+ "pwm0",
+ "pwm0_b",
+};
+
+static const char * const pwm1_groups[] = {
+ "pwm1",
+ "pwm1_b",
+};
+
+static const char * const pwm2_groups[] = {
+ "pwm2",
+};
+
+static const char * const pwm3_groups[] = {
+ "pwm3",
+};
+
+static const char * const pwm4_groups[] = {
+ "pwm4",
+};
+
+static const char * const pwm5_groups[] = {
+ "pwm5",
+};
+
+static const char * const pwm6_groups[] = {
+ "pwm6",
+};
+
static const char * const qspi_groups[] = {
"qspi_ctrl",
"qspi_data2",
@@ -4621,6 +4715,13 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(msiof1),
SH_PFC_FUNCTION(msiof2),
SH_PFC_FUNCTION(msiof3),
+ SH_PFC_FUNCTION(pwm0),
+ SH_PFC_FUNCTION(pwm1),
+ SH_PFC_FUNCTION(pwm2),
+ SH_PFC_FUNCTION(pwm3),
+ SH_PFC_FUNCTION(pwm4),
+ SH_PFC_FUNCTION(pwm5),
+ SH_PFC_FUNCTION(pwm6),
SH_PFC_FUNCTION(qspi),
SH_PFC_FUNCTION(scif0),
SH_PFC_FUNCTION(scif1),
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
index fdd2c8729791..3ddf23ec9f0b 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
@@ -2928,6 +2928,79 @@ static const unsigned int msiof2_tx_e_pins[] = {
static const unsigned int msiof2_tx_e_mux[] = {
MSIOF2_TXD_E_MARK,
};
+/* - PWM -------------------------------------------------------------------- */
+static const unsigned int pwm0_pins[] = {
+ RCAR_GP_PIN(6, 14),
+};
+static const unsigned int pwm0_mux[] = {
+ PWM0_MARK,
+};
+static const unsigned int pwm0_b_pins[] = {
+ RCAR_GP_PIN(5, 30),
+};
+static const unsigned int pwm0_b_mux[] = {
+ PWM0_B_MARK,
+};
+static const unsigned int pwm1_pins[] = {
+ RCAR_GP_PIN(1, 17),
+};
+static const unsigned int pwm1_mux[] = {
+ PWM1_MARK,
+};
+static const unsigned int pwm1_b_pins[] = {
+ RCAR_GP_PIN(6, 15),
+};
+static const unsigned int pwm1_b_mux[] = {
+ PWM1_B_MARK,
+};
+static const unsigned int pwm2_pins[] = {
+ RCAR_GP_PIN(1, 18),
+};
+static const unsigned int pwm2_mux[] = {
+ PWM2_MARK,
+};
+static const unsigned int pwm2_b_pins[] = {
+ RCAR_GP_PIN(0, 16),
+};
+static const unsigned int pwm2_b_mux[] = {
+ PWM2_B_MARK,
+};
+static const unsigned int pwm3_pins[] = {
+ RCAR_GP_PIN(1, 24),
+};
+static const unsigned int pwm3_mux[] = {
+ PWM3_MARK,
+};
+static const unsigned int pwm4_pins[] = {
+ RCAR_GP_PIN(3, 26),
+};
+static const unsigned int pwm4_mux[] = {
+ PWM4_MARK,
+};
+static const unsigned int pwm4_b_pins[] = {
+ RCAR_GP_PIN(3, 31),
+};
+static const unsigned int pwm4_b_mux[] = {
+ PWM4_B_MARK,
+};
+static const unsigned int pwm5_pins[] = {
+ RCAR_GP_PIN(7, 21),
+};
+static const unsigned int pwm5_mux[] = {
+ PWM5_MARK,
+};
+static const unsigned int pwm5_b_pins[] = {
+ RCAR_GP_PIN(7, 20),
+};
+static const unsigned int pwm5_b_mux[] = {
+ PWM5_B_MARK,
+};
+static const unsigned int pwm6_pins[] = {
+ RCAR_GP_PIN(7, 22),
+};
+static const unsigned int pwm6_mux[] = {
+ PWM6_MARK,
+};
/* - QSPI ------------------------------------------------------------------- */
static const unsigned int qspi_ctrl_pins[] = {
/* SPCLK, SSL */
@@ -4348,6 +4421,18 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(msiof2_sync_e),
SH_PFC_PIN_GROUP(msiof2_rx_e),
SH_PFC_PIN_GROUP(msiof2_tx_e),
+ SH_PFC_PIN_GROUP(pwm0),
+ SH_PFC_PIN_GROUP(pwm0_b),
+ SH_PFC_PIN_GROUP(pwm1),
+ SH_PFC_PIN_GROUP(pwm1_b),
+ SH_PFC_PIN_GROUP(pwm2),
+ SH_PFC_PIN_GROUP(pwm2_b),
+ SH_PFC_PIN_GROUP(pwm3),
+ SH_PFC_PIN_GROUP(pwm4),
+ SH_PFC_PIN_GROUP(pwm4_b),
+ SH_PFC_PIN_GROUP(pwm5),
+ SH_PFC_PIN_GROUP(pwm5_b),
+ SH_PFC_PIN_GROUP(pwm6),
SH_PFC_PIN_GROUP(qspi_ctrl),
SH_PFC_PIN_GROUP(qspi_data2),
SH_PFC_PIN_GROUP(qspi_data4),
@@ -4745,6 +4830,39 @@ static const char * const msiof2_groups[] = {
"msiof2_tx_e",
};
+static const char * const pwm0_groups[] = {
+ "pwm0",
+ "pwm0_b",
+};
+
+static const char * const pwm1_groups[] = {
+ "pwm1",
+ "pwm1_b",
+};
+
+static const char * const pwm2_groups[] = {
+ "pwm2",
+ "pwm2_b",
+};
+
+static const char * const pwm3_groups[] = {
+ "pwm3",
+};
+
+static const char * const pwm4_groups[] = {
+ "pwm4",
+ "pwm4_b",
+};
+
+static const char * const pwm5_groups[] = {
+ "pwm5",
+ "pwm5_b",
+};
+
+static const char * const pwm6_groups[] = {
+ "pwm6",
+};
+
static const char * const qspi_groups[] = {
"qspi_ctrl",
"qspi_data2",
@@ -4989,6 +5107,13 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(msiof0),
SH_PFC_FUNCTION(msiof1),
SH_PFC_FUNCTION(msiof2),
+ SH_PFC_FUNCTION(pwm0),
+ SH_PFC_FUNCTION(pwm1),
+ SH_PFC_FUNCTION(pwm2),
+ SH_PFC_FUNCTION(pwm3),
+ SH_PFC_FUNCTION(pwm4),
+ SH_PFC_FUNCTION(pwm5),
+ SH_PFC_FUNCTION(pwm6),
SH_PFC_FUNCTION(qspi),
SH_PFC_FUNCTION(scif0),
SH_PFC_FUNCTION(scif1),
@@ -6000,7 +6125,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
{ PINMUX_CFG_REG_VAR("MOD_SEL", 0xE6060090, 32,
1, 2, 2, 2, 3, 2, 1, 1, 1, 1,
3, 2, 2, 2, 1, 2, 2, 2) {
- /* RESEVED [1] */
+ /* RESERVED [1] */
0, 0,
/* SEL_SCIF1 [2] */
FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2, FN_SEL_SCIF1_3,
@@ -6027,11 +6152,11 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
FN_SEL_HSCIF1_0, FN_SEL_HSCIF1_1, FN_SEL_HSCIF1_2,
FN_SEL_HSCIF1_3, FN_SEL_HSCIF1_4,
0, 0, 0,
- /* RESEVED [2] */
+ /* RESERVED [2] */
0, 0, 0, 0,
/* SEL_VI1 [2] */
FN_SEL_VI1_0, FN_SEL_VI1_1, FN_SEL_VI1_2, 0,
- /* RESEVED [2] */
+ /* RESERVED [2] */
0, 0, 0, 0,
/* SEL_TMU [1] */
FN_SEL_TMU1_0, FN_SEL_TMU1_1,
@@ -6049,7 +6174,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2,
FN_SEL_SCIF0_3, FN_SEL_SCIF0_4,
0, 0, 0,
- /* RESEVED [1] */
+ /* RESERVED [1] */
0, 0,
/* SEL_SCIF [1] */
FN_SEL_SCIF_0, FN_SEL_SCIF_1,
@@ -6059,13 +6184,13 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
0, 0,
/* SEL_CAN1 [2] */
FN_SEL_CAN1_0, FN_SEL_CAN1_1, FN_SEL_CAN1_2, FN_SEL_CAN1_3,
- /* RESEVED [1] */
+ /* RESERVED [1] */
0, 0,
/* SEL_SCIFA2 [1] */
FN_SEL_SCIFA2_0, FN_SEL_SCIFA2_1,
/* SEL_SCIF4 [2] */
FN_SEL_SCIF4_0, FN_SEL_SCIF4_1, FN_SEL_SCIF4_2, 0,
- /* RESEVED [2] */
+ /* RESERVED [2] */
0, 0, 0, 0,
/* SEL_ADG [1] */
FN_SEL_ADG_0, FN_SEL_ADG_1,
@@ -6075,7 +6200,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
0, 0, 0,
/* SEL_SCIFA5 [2] */
FN_SEL_SCIFA5_0, FN_SEL_SCIFA5_1, FN_SEL_SCIFA5_2, 0,
- /* RESEVED [1] */
+ /* RESERVED [1] */
0, 0,
/* SEL_GPS [2] */
FN_SEL_GPS_0, FN_SEL_GPS_1, FN_SEL_GPS_2, FN_SEL_GPS_3,
@@ -6085,7 +6210,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
FN_SEL_SCIFA3_0, FN_SEL_SCIFA3_1, FN_SEL_SCIFA3_2, 0,
/* SEL_SIM [1] */
FN_SEL_SIM_0, FN_SEL_SIM_1,
- /* RESEVED [1] */
+ /* RESERVED [1] */
0, 0,
/* SEL_SSI8 [1] */
FN_SEL_SSI8_0, FN_SEL_SSI8_1, }
@@ -6115,7 +6240,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
FN_SEL_MMC_0, FN_SEL_MMC_1,
/* SEL_SCIF5 [1] */
FN_SEL_SCIF5_0, FN_SEL_SCIF5_1,
- /* RESEVED [2] */
+ /* RESERVED [2] */
0, 0, 0, 0,
/* SEL_IIC2 [2] */
FN_SEL_IIC2_0, FN_SEL_IIC2_1, FN_SEL_IIC2_2, FN_SEL_IIC2_3,
@@ -6125,11 +6250,11 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
0, 0, 0,
/* SEL_IIC0 [2] */
FN_SEL_IIC0_0, FN_SEL_IIC0_1, FN_SEL_IIC0_2, 0,
- /* RESEVED [2] */
+ /* RESERVED [2] */
0, 0, 0, 0,
- /* RESEVED [2] */
+ /* RESERVED [2] */
0, 0, 0, 0,
- /* RESEVED [1] */
+ /* RESERVED [1] */
0, 0, }
},
{ PINMUX_CFG_REG_VAR("MOD_SEL4", 0xE606009C, 32,
@@ -6143,7 +6268,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
FN_SEL_HSCIF0_0, FN_SEL_HSCIF0_1, FN_SEL_HSCIF0_2, 0,
/* SEL_DIS [2] */
FN_SEL_DIS_0, FN_SEL_DIS_1, FN_SEL_DIS_2, 0,
- /* RESEVED [1] */
+ /* RESERVED [1] */
0, 0,
/* SEL_RAD [1] */
FN_SEL_RAD_0, FN_SEL_RAD_1,
@@ -6155,15 +6280,15 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2,
FN_SEL_SCIF2_3, FN_SEL_SCIF2_4,
0, 0, 0,
- /* RESEVED [2] */
+ /* RESERVED [2] */
0, 0, 0, 0,
- /* RESEVED [2] */
+ /* RESERVED [2] */
0, 0, 0, 0,
/* SEL_SOF2 [3] */
FN_SEL_SOF2_0, FN_SEL_SOF2_1, FN_SEL_SOF2_2,
FN_SEL_SOF2_3, FN_SEL_SOF2_4,
0, 0, 0,
- /* RESEVED [1] */
+ /* RESERVED [1] */
0, 0,
/* SEL_SSI1 [1] */
FN_SEL_SSI1_0, FN_SEL_SSI1_1,
@@ -6171,16 +6296,17 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
FN_SEL_SSI0_0, FN_SEL_SSI0_1,
/* SEL_SSP [2] */
FN_SEL_SSP_0, FN_SEL_SSP_1, FN_SEL_SSP_2, 0,
- /* RESEVED [2] */
+ /* RESERVED [2] */
0, 0, 0, 0,
- /* RESEVED [2] */
+ /* RESERVED [2] */
0, 0, 0, 0,
- /* RESEVED [2] */
+ /* RESERVED [2] */
0, 0, 0, 0, }
},
{ },
};
+#ifdef CONFIG_PINCTRL_PFC_R8A7791
const struct sh_pfc_soc_info r8a7791_pinmux_info = {
.name = "r8a77910_pfc",
.unlock_reg = 0xe6060000, /* PMMR */
@@ -6199,3 +6325,25 @@ const struct sh_pfc_soc_info r8a7791_pinmux_info = {
.gpio_data = pinmux_data,
.gpio_data_size = ARRAY_SIZE(pinmux_data),
};
+#endif
+
+#ifdef CONFIG_PINCTRL_PFC_R8A7793
+const struct sh_pfc_soc_info r8a7793_pinmux_info = {
+ .name = "r8a77930_pfc",
+ .unlock_reg = 0xe6060000, /* PMMR */
+
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .pins = pinmux_pins,
+ .nr_pins = ARRAY_SIZE(pinmux_pins),
+ .groups = pinmux_groups,
+ .nr_groups = ARRAY_SIZE(pinmux_groups),
+ .functions = pinmux_functions,
+ .nr_functions = ARRAY_SIZE(pinmux_functions),
+
+ .cfg_regs = pinmux_config_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
+#endif
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
new file mode 100644
index 000000000000..bfdcac4b3bc4
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
@@ -0,0 +1,4207 @@
+/*
+ * r8a7794 processor support - PFC hardware block.
+ *
+ * Copyright (C) 2014 Renesas Electronics Corporation
+ * Copyright (C) 2015 Renesas Solutions Corp.
+ * Copyright (C) 2015 Cogent Embedded, Inc., <source@cogentembedded.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_data/gpio-rcar.h>
+
+#include "core.h"
+#include "sh_pfc.h"
+
+#define PORT_GP_26(bank, fn, sfx) \
+ PORT_GP_1(bank, 0, fn, sfx), PORT_GP_1(bank, 1, fn, sfx), \
+ PORT_GP_1(bank, 2, fn, sfx), PORT_GP_1(bank, 3, fn, sfx), \
+ PORT_GP_1(bank, 4, fn, sfx), PORT_GP_1(bank, 5, fn, sfx), \
+ PORT_GP_1(bank, 6, fn, sfx), PORT_GP_1(bank, 7, fn, sfx), \
+ PORT_GP_1(bank, 8, fn, sfx), PORT_GP_1(bank, 9, fn, sfx), \
+ PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx), \
+ PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx), \
+ PORT_GP_1(bank, 14, fn, sfx), PORT_GP_1(bank, 15, fn, sfx), \
+ PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx), \
+ PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx), \
+ PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx), \
+ PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx), \
+ PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx)
+
+#define PORT_GP_28(bank, fn, sfx) \
+ PORT_GP_26(bank, fn, sfx), \
+ PORT_GP_1(bank, 26, fn, sfx), PORT_GP_1(bank, 27, fn, sfx)
+
+#define CPU_ALL_PORT(fn, sfx) \
+ PORT_GP_32(0, fn, sfx), \
+ PORT_GP_26(1, fn, sfx), \
+ PORT_GP_32(2, fn, sfx), \
+ PORT_GP_32(3, fn, sfx), \
+ PORT_GP_32(4, fn, sfx), \
+ PORT_GP_28(5, fn, sfx), \
+ PORT_GP_26(6, fn, sfx)
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ GP_ALL(DATA),
+ PINMUX_DATA_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ GP_ALL(FN),
+
+ /* GPSR0 */
+ FN_IP0_23_22, FN_IP0_24, FN_IP0_25, FN_IP0_27_26, FN_IP0_29_28,
+ FN_IP0_31_30, FN_IP1_1_0, FN_IP1_3_2, FN_IP1_5_4, FN_IP1_7_6,
+ FN_IP1_10_8, FN_IP1_12_11, FN_IP1_14_13, FN_IP1_17_15, FN_IP1_19_18,
+ FN_IP1_21_20, FN_IP1_23_22, FN_IP1_24, FN_A2, FN_IP1_26, FN_IP1_27,
+ FN_IP1_29_28, FN_IP1_31_30, FN_IP2_1_0, FN_IP2_3_2, FN_IP2_5_4,
+ FN_IP2_7_6, FN_IP2_9_8, FN_IP2_11_10, FN_IP2_13_12, FN_IP2_15_14,
+ FN_IP2_17_16,
+
+ /* GPSR1 */
+ FN_IP2_20_18, FN_IP2_23_21, FN_IP2_26_24, FN_IP2_29_27, FN_IP2_31_30,
+ FN_IP3_1_0, FN_IP3_3_2, FN_IP3_5_4, FN_IP3_7_6, FN_IP3_9_8, FN_IP3_10,
+ FN_IP3_11, FN_IP3_12, FN_IP3_14_13, FN_IP3_17_15, FN_IP3_20_18,
+ FN_IP3_23_21, FN_IP3_26_24, FN_IP3_29_27, FN_IP3_30, FN_IP3_31,
+ FN_WE0_N, FN_WE1_N, FN_IP4_1_0 , FN_IP7_31, FN_DACK0,
+
+ /* GPSR2 */
+ FN_IP4_4_2, FN_IP4_7_5, FN_IP4_9_8, FN_IP4_11_10, FN_IP4_13_12,
+ FN_IP4_15_14, FN_IP4_17_16, FN_IP4_19_18, FN_IP4_22_20, FN_IP4_25_23,
+ FN_IP4_27_26, FN_IP4_29_28, FN_IP4_31_30, FN_IP5_1_0, FN_IP5_3_2,
+ FN_IP5_5_4, FN_IP5_8_6, FN_IP5_11_9, FN_IP5_13_12, FN_IP5_15_14,
+ FN_IP5_17_16, FN_IP5_19_18, FN_IP5_21_20, FN_IP5_23_22, FN_IP5_25_24,
+ FN_IP5_27_26, FN_IP5_29_28, FN_IP5_31_30, FN_IP6_1_0, FN_IP6_3_2,
+ FN_IP6_5_4, FN_IP6_7_6,
+
+ /* GPSR3 */
+ FN_IP6_8, FN_IP6_9, FN_IP6_10, FN_IP6_11, FN_IP6_12, FN_IP6_13,
+ FN_IP6_14, FN_IP6_15, FN_IP6_16, FN_IP6_19_17, FN_IP6_22_20,
+ FN_IP6_25_23, FN_IP6_28_26, FN_IP6_31_29, FN_IP7_2_0, FN_IP7_5_3,
+ FN_IP7_8_6, FN_IP7_11_9, FN_IP7_14_12, FN_IP7_17_15, FN_IP7_20_18,
+ FN_IP7_23_21, FN_IP7_26_24, FN_IP7_29_27, FN_IP8_2_0, FN_IP8_5_3,
+ FN_IP8_8_6, FN_IP8_11_9, FN_IP8_14_12, FN_IP8_16_15, FN_IP8_19_17,
+ FN_IP8_22_20,
+
+ /* GPSR4 */
+ FN_IP8_25_23, FN_IP8_28_26, FN_IP8_31_29, FN_IP9_2_0, FN_IP9_5_3,
+ FN_IP9_8_6, FN_IP9_11_9, FN_IP9_14_12, FN_IP9_16_15, FN_IP9_18_17,
+ FN_IP9_21_19, FN_IP9_24_22, FN_IP9_27_25, FN_IP9_30_28, FN_IP10_2_0,
+ FN_IP10_5_3, FN_IP10_8_6, FN_IP10_11_9, FN_IP10_14_12, FN_IP10_17_15,
+ FN_IP10_20_18, FN_IP10_23_21, FN_IP10_26_24, FN_IP10_29_27,
+ FN_IP10_31_30, FN_IP11_2_0, FN_IP11_5_3, FN_IP11_7_6, FN_IP11_10_8,
+ FN_IP11_13_11, FN_IP11_15_14, FN_IP11_17_16,
+
+ /* GPSR5 */
+ FN_IP11_20_18, FN_IP11_23_21, FN_IP11_26_24, FN_IP11_29_27, FN_IP12_2_0,
+ FN_IP12_5_3, FN_IP12_8_6, FN_IP12_10_9, FN_IP12_12_11, FN_IP12_14_13,
+ FN_IP12_17_15, FN_IP12_20_18, FN_IP12_23_21, FN_IP12_26_24,
+ FN_IP12_29_27, FN_IP13_2_0, FN_IP13_5_3, FN_IP13_8_6, FN_IP13_11_9,
+ FN_IP13_14_12, FN_IP13_17_15, FN_IP13_20_18, FN_IP13_23_21,
+ FN_IP13_26_24, FN_USB0_PWEN, FN_USB0_OVC, FN_USB1_PWEN, FN_USB1_OVC,
+
+ /* GPSR6 */
+ FN_SD0_CLK, FN_SD0_CMD, FN_SD0_DATA0, FN_SD0_DATA1, FN_SD0_DATA2,
+ FN_SD0_DATA3, FN_SD0_CD, FN_SD0_WP, FN_SD1_CLK, FN_SD1_CMD,
+ FN_SD1_DATA0, FN_SD1_DATA1, FN_SD1_DATA2, FN_SD1_DATA3, FN_IP0_0,
+ FN_IP0_9_8, FN_IP0_10, FN_IP0_11, FN_IP0_12, FN_IP0_13, FN_IP0_14,
+ FN_IP0_15, FN_IP0_16, FN_IP0_17, FN_IP0_19_18, FN_IP0_21_20,
+
+ /* IPSR0 */
+ FN_SD1_CD, FN_CAN0_RX, FN_SD1_WP, FN_IRQ7, FN_CAN0_TX, FN_MMC_CLK,
+ FN_SD2_CLK, FN_MMC_CMD, FN_SD2_CMD, FN_MMC_D0, FN_SD2_DATA0, FN_MMC_D1,
+ FN_SD2_DATA1, FN_MMC_D2, FN_SD2_DATA2, FN_MMC_D3, FN_SD2_DATA3,
+ FN_MMC_D4, FN_SD2_CD, FN_MMC_D5, FN_SD2_WP, FN_MMC_D6, FN_SCIF0_RXD,
+ FN_I2C2_SCL_B, FN_CAN1_RX, FN_MMC_D7, FN_SCIF0_TXD, FN_I2C2_SDA_B,
+ FN_CAN1_TX, FN_D0, FN_SCIFA3_SCK_B, FN_IRQ4, FN_D1, FN_SCIFA3_RXD_B,
+ FN_D2, FN_SCIFA3_TXD_B, FN_D3, FN_I2C3_SCL_B, FN_SCIF5_RXD_B, FN_D4,
+ FN_I2C3_SDA_B, FN_SCIF5_TXD_B, FN_D5, FN_SCIF4_RXD_B, FN_I2C0_SCL_D,
+
+ /* IPSR1 */
+ FN_D6, FN_SCIF4_TXD_B, FN_I2C0_SDA_D, FN_D7, FN_IRQ3, FN_TCLK1,
+ FN_PWM6_B, FN_D8, FN_HSCIF2_HRX, FN_I2C1_SCL_B, FN_D9, FN_HSCIF2_HTX,
+ FN_I2C1_SDA_B, FN_D10, FN_HSCIF2_HSCK, FN_SCIF1_SCK_C, FN_IRQ6,
+ FN_PWM5_C, FN_D11, FN_HSCIF2_HCTS_N, FN_SCIF1_RXD_C, FN_I2C1_SCL_D,
+ FN_D12, FN_HSCIF2_HRTS_N, FN_SCIF1_TXD_C, FN_I2C1_SDA_D, FN_D13,
+ FN_SCIFA1_SCK, FN_TANS1, FN_PWM2_C, FN_TCLK2_B, FN_D14, FN_SCIFA1_RXD,
+ FN_IIC0_SCL_B, FN_D15, FN_SCIFA1_TXD, FN_IIC0_SDA_B, FN_A0,
+ FN_SCIFB1_SCK, FN_PWM3_B, FN_A1, FN_SCIFB1_TXD, FN_A3, FN_SCIFB0_SCK,
+ FN_A4, FN_SCIFB0_TXD, FN_A5, FN_SCIFB0_RXD, FN_PWM4_B, FN_TPUTO3_C,
+ FN_A6, FN_SCIFB0_CTS_N, FN_SCIFA4_RXD_B, FN_TPUTO2_C,
+
+ /* IPSR2 */
+ FN_A7, FN_SCIFB0_RTS_N, FN_SCIFA4_TXD_B, FN_A8, FN_MSIOF1_RXD,
+ FN_SCIFA0_RXD_B, FN_A9, FN_MSIOF1_TXD, FN_SCIFA0_TXD_B, FN_A10,
+ FN_MSIOF1_SCK, FN_IIC1_SCL_B, FN_A11, FN_MSIOF1_SYNC, FN_IIC1_SDA_B,
+ FN_A12, FN_MSIOF1_SS1, FN_SCIFA5_RXD_B, FN_A13, FN_MSIOF1_SS2,
+ FN_SCIFA5_TXD_B, FN_A14, FN_MSIOF2_RXD, FN_HSCIF0_HRX_B, FN_DREQ1_N,
+ FN_A15, FN_MSIOF2_TXD, FN_HSCIF0_HTX_B, FN_DACK1, FN_A16,
+ FN_MSIOF2_SCK, FN_HSCIF0_HSCK_B, FN_SPEEDIN, FN_VSP, FN_CAN_CLK_C,
+ FN_TPUTO2_B, FN_A17, FN_MSIOF2_SYNC, FN_SCIF4_RXD_E, FN_CAN1_RX_B,
+ FN_AVB_AVTP_CAPTURE_B, FN_A18, FN_MSIOF2_SS1, FN_SCIF4_TXD_E,
+ FN_CAN1_TX_B, FN_AVB_AVTP_MATCH_B, FN_A19, FN_MSIOF2_SS2, FN_PWM4,
+ FN_TPUTO2, FN_MOUT0, FN_A20, FN_SPCLK, FN_MOUT1,
+
+ /* IPSR3 */
+ FN_A21, FN_MOSI_IO0, FN_MOUT2, FN_A22, FN_MISO_IO1, FN_MOUT5,
+ FN_ATADIR1_N, FN_A23, FN_IO2, FN_MOUT6, FN_ATAWR1_N, FN_A24, FN_IO3,
+ FN_EX_WAIT2, FN_A25, FN_SSL, FN_ATARD1_N, FN_CS0_N, FN_VI1_DATA8,
+ FN_CS1_N_A26, FN_VI1_DATA9, FN_EX_CS0_N, FN_VI1_DATA10, FN_EX_CS1_N,
+ FN_TPUTO3_B, FN_SCIFB2_RXD, FN_VI1_DATA11, FN_EX_CS2_N, FN_PWM0,
+ FN_SCIF4_RXD_C, FN_TS_SDATA_B, FN_RIF0_SYNC, FN_TPUTO3, FN_SCIFB2_TXD,
+ FN_SDATA_B, FN_EX_CS3_N, FN_SCIFA2_SCK, FN_SCIF4_TXD_C, FN_TS_SCK_B,
+ FN_RIF0_CLK, FN_BPFCLK, FN_SCIFB2_SCK, FN_MDATA_B, FN_EX_CS4_N,
+ FN_SCIFA2_RXD, FN_I2C2_SCL_E, FN_TS_SDEN_B, FN_RIF0_D0, FN_FMCLK,
+ FN_SCIFB2_CTS_N, FN_SCKZ_B, FN_EX_CS5_N, FN_SCIFA2_TXD, FN_I2C2_SDA_E,
+ FN_TS_SPSYNC_B, FN_RIF0_D1, FN_FMIN, FN_SCIFB2_RTS_N, FN_STM_N_B,
+ FN_BS_N, FN_DRACK0, FN_PWM1_C, FN_TPUTO0_C, FN_ATACS01_N, FN_MTS_N_B,
+ FN_RD_N, FN_ATACS11_N, FN_RD_WR_N, FN_ATAG1_N,
+
+ /* IPSR4 */
+ FN_EX_WAIT0, FN_CAN_CLK_B, FN_SCIF_CLK, FN_PWMFSW0, FN_DU0_DR0,
+ FN_LCDOUT16, FN_SCIF5_RXD_C, FN_I2C2_SCL_D, FN_CC50_STATE0,
+ FN_DU0_DR1, FN_LCDOUT17, FN_SCIF5_TXD_C, FN_I2C2_SDA_D, FN_CC50_STATE1,
+ FN_DU0_DR2, FN_LCDOUT18, FN_CC50_STATE2, FN_DU0_DR3, FN_LCDOUT19,
+ FN_CC50_STATE3, FN_DU0_DR4, FN_LCDOUT20, FN_CC50_STATE4, FN_DU0_DR5,
+ FN_LCDOUT21, FN_CC50_STATE5, FN_DU0_DR6, FN_LCDOUT22, FN_CC50_STATE6,
+ FN_DU0_DR7, FN_LCDOUT23, FN_CC50_STATE7, FN_DU0_DG0, FN_LCDOUT8,
+ FN_SCIFA0_RXD_C, FN_I2C3_SCL_D, FN_CC50_STATE8, FN_DU0_DG1, FN_LCDOUT9,
+ FN_SCIFA0_TXD_C, FN_I2C3_SDA_D, FN_CC50_STATE9, FN_DU0_DG2, FN_LCDOUT10,
+ FN_CC50_STATE10, FN_DU0_DG3, FN_LCDOUT11, FN_CC50_STATE11, FN_DU0_DG4,
+ FN_LCDOUT12, FN_CC50_STATE12,
+
+ /* IPSR5 */
+ FN_DU0_DG5, FN_LCDOUT13, FN_CC50_STATE13, FN_DU0_DG6, FN_LCDOUT14,
+ FN_CC50_STATE14, FN_DU0_DG7, FN_LCDOUT15, FN_CC50_STATE15, FN_DU0_DB0,
+ FN_LCDOUT0, FN_SCIFA4_RXD_C, FN_I2C4_SCL_D, FN_CAN0_RX_C,
+ FN_CC50_STATE16, FN_DU0_DB1, FN_LCDOUT1, FN_SCIFA4_TXD_C, FN_I2C4_SDA_D,
+ FN_CAN0_TX_C, FN_CC50_STATE17, FN_DU0_DB2, FN_LCDOUT2, FN_CC50_STATE18,
+ FN_DU0_DB3, FN_LCDOUT3, FN_CC50_STATE19, FN_DU0_DB4, FN_LCDOUT4,
+ FN_CC50_STATE20, FN_DU0_DB5, FN_LCDOUT5, FN_CC50_STATE21, FN_DU0_DB6,
+ FN_LCDOUT6, FN_CC50_STATE22, FN_DU0_DB7, FN_LCDOUT7, FN_CC50_STATE23,
+ FN_DU0_DOTCLKIN, FN_QSTVA_QVS, FN_CC50_STATE24, FN_DU0_DOTCLKOUT0,
+ FN_QCLK, FN_CC50_STATE25, FN_DU0_DOTCLKOUT1, FN_QSTVB_QVE,
+ FN_CC50_STATE26, FN_DU0_EXHSYNC_DU0_HSYNC, FN_QSTH_QHS, FN_CC50_STATE27,
+
+ /* IPSR6 */
+ FN_DU0_EXVSYNC_DU0_VSYNC, FN_QSTB_QHE, FN_CC50_STATE28,
+ FN_DU0_EXODDF_DU0_ODDF_DISP_CDE, FN_QCPV_QDE, FN_CC50_STATE29,
+ FN_DU0_DISP, FN_QPOLA, FN_CC50_STATE30, FN_DU0_CDE, FN_QPOLB,
+ FN_CC50_STATE31, FN_VI0_CLK, FN_AVB_RX_CLK, FN_VI0_DATA0_VI0_B0,
+ FN_AVB_RX_DV, FN_VI0_DATA1_VI0_B1, FN_AVB_RXD0, FN_VI0_DATA2_VI0_B2,
+ FN_AVB_RXD1, FN_VI0_DATA3_VI0_B3, FN_AVB_RXD2, FN_VI0_DATA4_VI0_B4,
+ FN_AVB_RXD3, FN_VI0_DATA5_VI0_B5, FN_AVB_RXD4, FN_VI0_DATA6_VI0_B6,
+ FN_AVB_RXD5, FN_VI0_DATA7_VI0_B7, FN_AVB_RXD6, FN_VI0_CLKENB,
+ FN_I2C3_SCL, FN_SCIFA5_RXD_C, FN_IETX_C, FN_AVB_RXD7, FN_VI0_FIELD,
+ FN_I2C3_SDA, FN_SCIFA5_TXD_C, FN_IECLK_C, FN_AVB_RX_ER, FN_VI0_HSYNC_N,
+ FN_SCIF0_RXD_B, FN_I2C0_SCL_C, FN_IERX_C, FN_AVB_COL, FN_VI0_VSYNC_N,
+ FN_SCIF0_TXD_B, FN_I2C0_SDA_C, FN_AUDIO_CLKOUT_B, FN_AVB_TX_EN,
+ FN_ETH_MDIO, FN_VI0_G0, FN_MSIOF2_RXD_B, FN_IIC0_SCL_D, FN_AVB_TX_CLK,
+ FN_ADIDATA, FN_AD_DI,
+
+ /* IPSR7 */
+ FN_ETH_CRS_DV, FN_VI0_G1, FN_MSIOF2_TXD_B, FN_IIC0_SDA_D, FN_AVB_TXD0,
+ FN_ADICS_SAMP, FN_AD_DO, FN_ETH_RX_ER, FN_VI0_G2, FN_MSIOF2_SCK_B,
+ FN_CAN0_RX_B, FN_AVB_TXD1, FN_ADICLK, FN_AD_CLK, FN_ETH_RXD0, FN_VI0_G3,
+ FN_MSIOF2_SYNC_B, FN_CAN0_TX_B, FN_AVB_TXD2, FN_ADICHS0, FN_AD_NCS_N,
+ FN_ETH_RXD1, FN_VI0_G4, FN_MSIOF2_SS1_B, FN_SCIF4_RXD_D, FN_AVB_TXD3,
+ FN_ADICHS1, FN_ETH_LINK, FN_VI0_G5, FN_MSIOF2_SS2_B, FN_SCIF4_TXD_D,
+ FN_AVB_TXD4, FN_ADICHS2, FN_ETH_REFCLK, FN_VI0_G6, FN_SCIF2_SCK_C,
+ FN_AVB_TXD5, FN_SSI_SCK5_B, FN_ETH_TXD1, FN_VI0_G7, FN_SCIF2_RXD_C,
+ FN_IIC1_SCL_D, FN_AVB_TXD6, FN_SSI_WS5_B, FN_ETH_TX_EN, FN_VI0_R0,
+ FN_SCIF2_TXD_C, FN_IIC1_SDA_D, FN_AVB_TXD7, FN_SSI_SDATA5_B,
+ FN_ETH_MAGIC, FN_VI0_R1, FN_SCIF3_SCK_B, FN_AVB_TX_ER, FN_SSI_SCK6_B,
+ FN_ETH_TXD0, FN_VI0_R2, FN_SCIF3_RXD_B, FN_I2C4_SCL_E, FN_AVB_GTX_CLK,
+ FN_SSI_WS6_B, FN_DREQ0_N, FN_SCIFB1_RXD,
+
+ /* IPSR8 */
+ FN_ETH_MDC, FN_VI0_R3, FN_SCIF3_TXD_B, FN_I2C4_SDA_E, FN_AVB_MDC,
+ FN_SSI_SDATA6_B, FN_HSCIF0_HRX, FN_VI0_R4, FN_I2C1_SCL_C,
+ FN_AUDIO_CLKA_B, FN_AVB_MDIO, FN_SSI_SCK78_B, FN_HSCIF0_HTX,
+ FN_VI0_R5, FN_I2C1_SDA_C, FN_AUDIO_CLKB_B, FN_AVB_LINK, FN_SSI_WS78_B,
+ FN_HSCIF0_HCTS_N, FN_VI0_R6, FN_SCIF0_RXD_D, FN_I2C0_SCL_E,
+ FN_AVB_MAGIC, FN_SSI_SDATA7_B, FN_HSCIF0_HRTS_N, FN_VI0_R7,
+ FN_SCIF0_TXD_D, FN_I2C0_SDA_E, FN_AVB_PHY_INT, FN_SSI_SDATA8_B,
+ FN_HSCIF0_HSCK, FN_SCIF_CLK_B, FN_AVB_CRS, FN_AUDIO_CLKC_B,
+ FN_I2C0_SCL, FN_SCIF0_RXD_C, FN_PWM5, FN_TCLK1_B, FN_AVB_GTXREFCLK,
+ FN_CAN1_RX_D, FN_TPUTO0_B, FN_I2C0_SDA, FN_SCIF0_TXD_C, FN_TPUTO0,
+ FN_CAN_CLK, FN_DVC_MUTE, FN_CAN1_TX_D, FN_I2C1_SCL, FN_SCIF4_RXD,
+ FN_PWM5_B, FN_DU1_DR0, FN_RIF1_SYNC_B, FN_TS_SDATA_D, FN_TPUTO1_B,
+ FN_I2C1_SDA, FN_SCIF4_TXD, FN_IRQ5, FN_DU1_DR1, FN_RIF1_CLK_B,
+ FN_TS_SCK_D, FN_BPFCLK_C, FN_MSIOF0_RXD, FN_SCIF5_RXD, FN_I2C2_SCL_C,
+ FN_DU1_DR2, FN_RIF1_D0_B, FN_TS_SDEN_D, FN_FMCLK_C, FN_RDS_CLK,
+
+ /* IPSR9 */
+ FN_MSIOF0_TXD, FN_SCIF5_TXD, FN_I2C2_SDA_C, FN_DU1_DR3, FN_RIF1_D1_B,
+ FN_TS_SPSYNC_D, FN_FMIN_C, FN_RDS_DATA, FN_MSIOF0_SCK, FN_IRQ0,
+ FN_TS_SDATA, FN_DU1_DR4, FN_RIF1_SYNC, FN_TPUTO1_C, FN_MSIOF0_SYNC,
+ FN_PWM1, FN_TS_SCK, FN_DU1_DR5, FN_RIF1_CLK, FN_BPFCLK_B, FN_MSIOF0_SS1,
+ FN_SCIFA0_RXD, FN_TS_SDEN, FN_DU1_DR6, FN_RIF1_D0, FN_FMCLK_B,
+ FN_RDS_CLK_B, FN_MSIOF0_SS2, FN_SCIFA0_TXD, FN_TS_SPSYNC, FN_DU1_DR7,
+ FN_RIF1_D1, FN_FMIN_B, FN_RDS_DATA_B, FN_HSCIF1_HRX, FN_I2C4_SCL,
+ FN_PWM6, FN_DU1_DG0, FN_HSCIF1_HTX, FN_I2C4_SDA, FN_TPUTO1, FN_DU1_DG1,
+ FN_HSCIF1_HSCK, FN_PWM2, FN_IETX, FN_DU1_DG2, FN_REMOCON_B,
+ FN_SPEEDIN_B, FN_VSP_B, FN_HSCIF1_HCTS_N, FN_SCIFA4_RXD, FN_IECLK,
+ FN_DU1_DG3, FN_SSI_SCK1_B, FN_CAN_DEBUG_HW_TRIGGER, FN_CC50_STATE32,
+ FN_HSCIF1_HRTS_N, FN_SCIFA4_TXD, FN_IERX, FN_DU1_DG4, FN_SSI_WS1_B,
+ FN_CAN_STEP0, FN_CC50_STATE33, FN_SCIF1_SCK, FN_PWM3, FN_TCLK2,
+ FN_DU1_DG5, FN_SSI_SDATA1_B, FN_CAN_TXCLK, FN_CC50_STATE34,
+
+ /* IPSR10 */
+ FN_SCIF1_RXD, FN_IIC0_SCL, FN_DU1_DG6, FN_SSI_SCK2_B, FN_CAN_DEBUGOUT0,
+ FN_CC50_STATE35, FN_SCIF1_TXD, FN_IIC0_SDA, FN_DU1_DG7, FN_SSI_WS2_B,
+ FN_CAN_DEBUGOUT1, FN_CC50_STATE36, FN_SCIF2_RXD, FN_IIC1_SCL,
+ FN_DU1_DB0, FN_SSI_SDATA2_B, FN_USB0_EXTLP, FN_CAN_DEBUGOUT2,
+ FN_CC50_STATE37, FN_SCIF2_TXD, FN_IIC1_SDA, FN_DU1_DB1, FN_SSI_SCK9_B,
+ FN_USB0_OVC1, FN_CAN_DEBUGOUT3, FN_CC50_STATE38, FN_SCIF2_SCK, FN_IRQ1,
+ FN_DU1_DB2, FN_SSI_WS9_B, FN_USB0_IDIN, FN_CAN_DEBUGOUT4,
+ FN_CC50_STATE39, FN_SCIF3_SCK, FN_IRQ2, FN_BPFCLK_D, FN_DU1_DB3,
+ FN_SSI_SDATA9_B, FN_TANS2, FN_CAN_DEBUGOUT5, FN_CC50_OSCOUT,
+ FN_SCIF3_RXD, FN_I2C1_SCL_E, FN_FMCLK_D, FN_DU1_DB4, FN_AUDIO_CLKA_C,
+ FN_SSI_SCK4_B, FN_CAN_DEBUGOUT6, FN_RDS_CLK_C, FN_SCIF3_TXD,
+ FN_I2C1_SDA_E, FN_FMIN_D, FN_DU1_DB5, FN_AUDIO_CLKB_C, FN_SSI_WS4_B,
+ FN_CAN_DEBUGOUT7, FN_RDS_DATA_C, FN_I2C2_SCL, FN_SCIFA5_RXD, FN_DU1_DB6,
+ FN_AUDIO_CLKC_C, FN_SSI_SDATA4_B, FN_CAN_DEBUGOUT8, FN_I2C2_SDA,
+ FN_SCIFA5_TXD, FN_DU1_DB7, FN_AUDIO_CLKOUT_C, FN_CAN_DEBUGOUT9,
+ FN_SSI_SCK5, FN_SCIFA3_SCK, FN_DU1_DOTCLKIN, FN_CAN_DEBUGOUT10,
+
+ /* IPSR11 */
+ FN_SSI_WS5, FN_SCIFA3_RXD, FN_I2C3_SCL_C, FN_DU1_DOTCLKOUT0,
+ FN_CAN_DEBUGOUT11, FN_SSI_SDATA5, FN_SCIFA3_TXD, FN_I2C3_SDA_C,
+ FN_DU1_DOTCLKOUT1, FN_CAN_DEBUGOUT12, FN_SSI_SCK6, FN_SCIFA1_SCK_B,
+ FN_DU1_EXHSYNC_DU1_HSYNC, FN_CAN_DEBUGOUT13, FN_SSI_WS6,
+ FN_SCIFA1_RXD_B, FN_I2C4_SCL_C, FN_DU1_EXVSYNC_DU1_VSYNC,
+ FN_CAN_DEBUGOUT14, FN_SSI_SDATA6, FN_SCIFA1_TXD_B, FN_I2C4_SDA_C,
+ FN_DU1_EXODDF_DU1_ODDF_DISP_CDE, FN_CAN_DEBUGOUT15, FN_SSI_SCK78,
+ FN_SCIFA2_SCK_B, FN_IIC0_SDA_C, FN_DU1_DISP, FN_SSI_WS78,
+ FN_SCIFA2_RXD_B, FN_IIC0_SCL_C, FN_DU1_CDE, FN_SSI_SDATA7,
+ FN_SCIFA2_TXD_B, FN_IRQ8, FN_AUDIO_CLKA_D, FN_CAN_CLK_D, FN_PCMOE_N,
+ FN_SSI_SCK0129, FN_MSIOF1_RXD_B, FN_SCIF5_RXD_D, FN_ADIDATA_B,
+ FN_AD_DI_B, FN_PCMWE_N, FN_SSI_WS0129, FN_MSIOF1_TXD_B, FN_SCIF5_TXD_D,
+ FN_ADICS_SAMP_B, FN_AD_DO_B, FN_SSI_SDATA0, FN_MSIOF1_SCK_B, FN_PWM0_B,
+ FN_ADICLK_B, FN_AD_CLK_B,
+
+ /* IPSR12 */
+ FN_SSI_SCK34, FN_MSIOF1_SYNC_B, FN_SCIFA1_SCK_C, FN_ADICHS0_B,
+ FN_AD_NCS_N_B, FN_DREQ1_N_B, FN_SSI_WS34, FN_MSIOF1_SS1_B,
+ FN_SCIFA1_RXD_C, FN_ADICHS1_B, FN_CAN1_RX_C, FN_DACK1_B, FN_SSI_SDATA3,
+ FN_MSIOF1_SS2_B, FN_SCIFA1_TXD_C, FN_ADICHS2_B, FN_CAN1_TX_C,
+ FN_DREQ2_N, FN_SSI_SCK4, FN_MLB_CLK, FN_IETX_B, FN_IRD_TX, FN_SSI_WS4,
+ FN_MLB_SIG, FN_IECLK_B, FN_IRD_RX, FN_SSI_SDATA4, FN_MLB_DAT,
+ FN_IERX_B, FN_IRD_SCK, FN_SSI_SDATA8, FN_SCIF1_SCK_B,
+ FN_PWM1_B, FN_IRQ9, FN_REMOCON, FN_DACK2, FN_ETH_MDIO_B, FN_SSI_SCK1,
+ FN_SCIF1_RXD_B, FN_IIC1_SCL_C, FN_VI1_CLK, FN_CAN0_RX_D,
+ FN_AVB_AVTP_CAPTURE, FN_ETH_CRS_DV_B, FN_SSI_WS1, FN_SCIF1_TXD_B,
+ FN_IIC1_SDA_C, FN_VI1_DATA0, FN_CAN0_TX_D, FN_AVB_AVTP_MATCH,
+ FN_ETH_RX_ER_B, FN_SSI_SDATA1, FN_HSCIF1_HRX_B, FN_SDATA, FN_VI1_DATA1,
+ FN_ATAG0_N, FN_ETH_RXD0_B, FN_SSI_SCK2, FN_HSCIF1_HTX_B, FN_VI1_DATA2,
+ FN_MDATA, FN_ATAWR0_N, FN_ETH_RXD1_B,
+
+ /* IPSR13 */
+ FN_SSI_WS2, FN_HSCIF1_HCTS_N_B, FN_SCIFA0_RXD_D, FN_VI1_DATA3, FN_SCKZ,
+ FN_ATACS00_N, FN_ETH_LINK_B, FN_SSI_SDATA2, FN_HSCIF1_HRTS_N_B,
+ FN_SCIFA0_TXD_D, FN_VI1_DATA4, FN_STM_N, FN_ATACS10_N, FN_ETH_REFCLK_B,
+ FN_SSI_SCK9, FN_SCIF2_SCK_B, FN_PWM2_B, FN_VI1_DATA5, FN_MTS_N,
+ FN_EX_WAIT1, FN_ETH_TXD1_B, FN_SSI_WS9, FN_SCIF2_RXD_B, FN_I2C3_SCL_E,
+ FN_VI1_DATA6, FN_ATARD0_N, FN_ETH_TX_EN_B, FN_SSI_SDATA9,
+ FN_SCIF2_TXD_B, FN_I2C3_SDA_E, FN_VI1_DATA7, FN_ATADIR0_N,
+ FN_ETH_MAGIC_B, FN_AUDIO_CLKA, FN_I2C0_SCL_B, FN_SCIFA4_RXD_D,
+ FN_VI1_CLKENB, FN_TS_SDATA_C, FN_RIF0_SYNC_B, FN_ETH_TXD0_B,
+ FN_AUDIO_CLKB, FN_I2C0_SDA_B, FN_SCIFA4_TXD_D, FN_VI1_FIELD,
+ FN_TS_SCK_C, FN_RIF0_CLK_B, FN_BPFCLK_E, FN_ETH_MDC_B, FN_AUDIO_CLKC,
+ FN_I2C4_SCL_B, FN_SCIFA5_RXD_D, FN_VI1_HSYNC_N, FN_TS_SDEN_C,
+ FN_RIF0_D0_B, FN_FMCLK_E, FN_RDS_CLK_D, FN_AUDIO_CLKOUT, FN_I2C4_SDA_B,
+ FN_SCIFA5_TXD_D, FN_VI1_VSYNC_N, FN_TS_SPSYNC_C, FN_RIF0_D1_B,
+ FN_FMIN_E, FN_RDS_DATA_D,
+
+ /* MOD_SEL */
+ FN_SEL_ADG_0, FN_SEL_ADG_1, FN_SEL_ADG_2, FN_SEL_ADG_3,
+ FN_SEL_ADI_0, FN_SEL_ADI_1, FN_SEL_CAN_0, FN_SEL_CAN_1,
+ FN_SEL_CAN_2, FN_SEL_CAN_3, FN_SEL_DARC_0, FN_SEL_DARC_1,
+ FN_SEL_DARC_2, FN_SEL_DARC_3, FN_SEL_DARC_4, FN_SEL_DR0_0,
+ FN_SEL_DR0_1, FN_SEL_DR1_0, FN_SEL_DR1_1, FN_SEL_DR2_0, FN_SEL_DR2_1,
+ FN_SEL_DR3_0, FN_SEL_DR3_1, FN_SEL_ETH_0, FN_SEL_ETH_1, FN_SEL_FSN_0,
+ FN_SEL_FSN_1, FN_SEL_I2C00_0, FN_SEL_I2C00_1, FN_SEL_I2C00_2,
+ FN_SEL_I2C00_3, FN_SEL_I2C00_4, FN_SEL_I2C01_0, FN_SEL_I2C01_1,
+ FN_SEL_I2C01_2, FN_SEL_I2C01_3, FN_SEL_I2C01_4, FN_SEL_I2C02_0,
+ FN_SEL_I2C02_1, FN_SEL_I2C02_2, FN_SEL_I2C02_3, FN_SEL_I2C02_4,
+ FN_SEL_I2C03_0, FN_SEL_I2C03_1, FN_SEL_I2C03_2, FN_SEL_I2C03_3,
+ FN_SEL_I2C03_4, FN_SEL_I2C04_0, FN_SEL_I2C04_1, FN_SEL_I2C04_2,
+ FN_SEL_I2C04_3, FN_SEL_I2C04_4, FN_SEL_IIC00_0, FN_SEL_IIC00_1,
+ FN_SEL_IIC00_2, FN_SEL_IIC00_3, FN_SEL_AVB_0, FN_SEL_AVB_1,
+
+ /* MOD_SEL2 */
+ FN_SEL_IEB_0, FN_SEL_IEB_1, FN_SEL_IEB_2, FN_SEL_IIC01_0,
+ FN_SEL_IIC01_1, FN_SEL_IIC01_2, FN_SEL_IIC01_3, FN_SEL_LBS_0,
+ FN_SEL_LBS_1, FN_SEL_MSI1_0, FN_SEL_MSI1_1, FN_SEL_MSI2_0,
+ FN_SEL_MSI2_1, FN_SEL_RAD_0, FN_SEL_RAD_1, FN_SEL_RCN_0,
+ FN_SEL_RCN_1, FN_SEL_RSP_0, FN_SEL_RSP_1, FN_SEL_SCIFA0_0,
+ FN_SEL_SCIFA0_1, FN_SEL_SCIFA0_2, FN_SEL_SCIFA0_3, FN_SEL_SCIFA1_0,
+ FN_SEL_SCIFA1_1, FN_SEL_SCIFA1_2, FN_SEL_SCIFA2_0, FN_SEL_SCIFA2_1,
+ FN_SEL_SCIFA3_0, FN_SEL_SCIFA3_1, FN_SEL_SCIFA4_0, FN_SEL_SCIFA4_1,
+ FN_SEL_SCIFA4_2, FN_SEL_SCIFA4_3, FN_SEL_SCIFA5_0, FN_SEL_SCIFA5_1,
+ FN_SEL_SCIFA5_2, FN_SEL_SCIFA5_3, FN_SEL_SPDM_0, FN_SEL_SPDM_1,
+ FN_SEL_TMU_0, FN_SEL_TMU_1, FN_SEL_TSIF0_0, FN_SEL_TSIF0_1,
+ FN_SEL_TSIF0_2, FN_SEL_TSIF0_3, FN_SEL_CAN0_0, FN_SEL_CAN0_1,
+ FN_SEL_CAN0_2, FN_SEL_CAN0_3, FN_SEL_CAN1_0, FN_SEL_CAN1_1,
+ FN_SEL_CAN1_2, FN_SEL_CAN1_3, FN_SEL_HSCIF0_0, FN_SEL_HSCIF0_1,
+ FN_SEL_HSCIF1_0, FN_SEL_HSCIF1_1, FN_SEL_RDS_0, FN_SEL_RDS_1,
+ FN_SEL_RDS_2, FN_SEL_RDS_3,
+
+ /* MOD_SEL3 */
+ FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2, FN_SEL_SCIF0_3,
+ FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2, FN_SEL_SCIF2_0,
+ FN_SEL_SCIF2_1, FN_SEL_SCIF2_2, FN_SEL_SCIF3_0, FN_SEL_SCIF3_1,
+ FN_SEL_SCIF4_0, FN_SEL_SCIF4_1, FN_SEL_SCIF4_2, FN_SEL_SCIF4_3,
+ FN_SEL_SCIF4_4, FN_SEL_SCIF5_0, FN_SEL_SCIF5_1, FN_SEL_SCIF5_2,
+ FN_SEL_SCIF5_3, FN_SEL_SSI1_0, FN_SEL_SSI1_1, FN_SEL_SSI2_0,
+ FN_SEL_SSI2_1, FN_SEL_SSI4_0, FN_SEL_SSI4_1, FN_SEL_SSI5_0,
+ FN_SEL_SSI5_1, FN_SEL_SSI6_0, FN_SEL_SSI6_1, FN_SEL_SSI7_0,
+ FN_SEL_SSI7_1, FN_SEL_SSI8_0, FN_SEL_SSI8_1, FN_SEL_SSI9_0,
+ FN_SEL_SSI9_1,
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+ A2_MARK, WE0_N_MARK, WE1_N_MARK, DACK0_MARK,
+
+ USB0_PWEN_MARK, USB0_OVC_MARK, USB1_PWEN_MARK, USB1_OVC_MARK,
+
+ SD0_CLK_MARK, SD0_CMD_MARK, SD0_DATA0_MARK, SD0_DATA1_MARK,
+ SD0_DATA2_MARK, SD0_DATA3_MARK, SD0_CD_MARK, SD0_WP_MARK,
+
+ SD1_CLK_MARK, SD1_CMD_MARK, SD1_DATA0_MARK, SD1_DATA1_MARK,
+ SD1_DATA2_MARK, SD1_DATA3_MARK,
+
+ /* IPSR0 */
+ SD1_CD_MARK, CAN0_RX_MARK, SD1_WP_MARK, IRQ7_MARK, CAN0_TX_MARK,
+ MMC_CLK_MARK, SD2_CLK_MARK, MMC_CMD_MARK, SD2_CMD_MARK, MMC_D0_MARK,
+ SD2_DATA0_MARK, MMC_D1_MARK, SD2_DATA1_MARK, MMC_D2_MARK,
+ SD2_DATA2_MARK, MMC_D3_MARK, SD2_DATA3_MARK, MMC_D4_MARK, SD2_CD_MARK,
+ MMC_D5_MARK, SD2_WP_MARK, MMC_D6_MARK, SCIF0_RXD_MARK, I2C2_SCL_B_MARK,
+ CAN1_RX_MARK, MMC_D7_MARK, SCIF0_TXD_MARK, I2C2_SDA_B_MARK,
+ CAN1_TX_MARK, D0_MARK, SCIFA3_SCK_B_MARK, IRQ4_MARK, D1_MARK,
+ SCIFA3_RXD_B_MARK, D2_MARK, SCIFA3_TXD_B_MARK, D3_MARK, I2C3_SCL_B_MARK,
+ SCIF5_RXD_B_MARK, D4_MARK, I2C3_SDA_B_MARK, SCIF5_TXD_B_MARK, D5_MARK,
+ SCIF4_RXD_B_MARK, I2C0_SCL_D_MARK,
+
+ /* IPSR1 */
+ D6_MARK, SCIF4_TXD_B_MARK, I2C0_SDA_D_MARK, D7_MARK, IRQ3_MARK,
+ TCLK1_MARK, PWM6_B_MARK, D8_MARK, HSCIF2_HRX_MARK, I2C1_SCL_B_MARK,
+ D9_MARK, HSCIF2_HTX_MARK, I2C1_SDA_B_MARK, D10_MARK,
+ HSCIF2_HSCK_MARK, SCIF1_SCK_C_MARK, IRQ6_MARK, PWM5_C_MARK,
+ D11_MARK, HSCIF2_HCTS_N_MARK, SCIF1_RXD_C_MARK, I2C1_SCL_D_MARK,
+ D12_MARK, HSCIF2_HRTS_N_MARK, SCIF1_TXD_C_MARK, I2C1_SDA_D_MARK,
+ D13_MARK, SCIFA1_SCK_MARK, TANS1_MARK, PWM2_C_MARK, TCLK2_B_MARK,
+ D14_MARK, SCIFA1_RXD_MARK, IIC0_SCL_B_MARK, D15_MARK, SCIFA1_TXD_MARK,
+ IIC0_SDA_B_MARK, A0_MARK, SCIFB1_SCK_MARK, PWM3_B_MARK, A1_MARK,
+ SCIFB1_TXD_MARK, A3_MARK, SCIFB0_SCK_MARK, A4_MARK, SCIFB0_TXD_MARK,
+ A5_MARK, SCIFB0_RXD_MARK, PWM4_B_MARK, TPUTO3_C_MARK, A6_MARK,
+ SCIFB0_CTS_N_MARK, SCIFA4_RXD_B_MARK, TPUTO2_C_MARK,
+
+ /* IPSR2 */
+ A7_MARK, SCIFB0_RTS_N_MARK, SCIFA4_TXD_B_MARK, A8_MARK, MSIOF1_RXD_MARK,
+ SCIFA0_RXD_B_MARK, A9_MARK, MSIOF1_TXD_MARK, SCIFA0_TXD_B_MARK,
+ A10_MARK, MSIOF1_SCK_MARK, IIC1_SCL_B_MARK, A11_MARK, MSIOF1_SYNC_MARK,
+ IIC1_SDA_B_MARK, A12_MARK, MSIOF1_SS1_MARK, SCIFA5_RXD_B_MARK,
+ A13_MARK, MSIOF1_SS2_MARK, SCIFA5_TXD_B_MARK, A14_MARK, MSIOF2_RXD_MARK,
+ HSCIF0_HRX_B_MARK, DREQ1_N_MARK, A15_MARK, MSIOF2_TXD_MARK,
+ HSCIF0_HTX_B_MARK, DACK1_MARK, A16_MARK, MSIOF2_SCK_MARK,
+ HSCIF0_HSCK_B_MARK, SPEEDIN_MARK, VSP_MARK, CAN_CLK_C_MARK,
+ TPUTO2_B_MARK, A17_MARK, MSIOF2_SYNC_MARK, SCIF4_RXD_E_MARK,
+ CAN1_RX_B_MARK, AVB_AVTP_CAPTURE_B_MARK, A18_MARK, MSIOF2_SS1_MARK,
+ SCIF4_TXD_E_MARK, CAN1_TX_B_MARK, AVB_AVTP_MATCH_B_MARK, A19_MARK,
+ MSIOF2_SS2_MARK, PWM4_MARK, TPUTO2_MARK, MOUT0_MARK, A20_MARK,
+ SPCLK_MARK, MOUT1_MARK,
+
+ /* IPSR3 */
+ A21_MARK, MOSI_IO0_MARK, MOUT2_MARK, A22_MARK, MISO_IO1_MARK,
+ MOUT5_MARK, ATADIR1_N_MARK, A23_MARK, IO2_MARK, MOUT6_MARK,
+ ATAWR1_N_MARK, A24_MARK, IO3_MARK, EX_WAIT2_MARK, A25_MARK, SSL_MARK,
+ ATARD1_N_MARK, CS0_N_MARK, VI1_DATA8_MARK, CS1_N_A26_MARK,
+ VI1_DATA9_MARK, EX_CS0_N_MARK, VI1_DATA10_MARK, EX_CS1_N_MARK,
+ TPUTO3_B_MARK, SCIFB2_RXD_MARK, VI1_DATA11_MARK, EX_CS2_N_MARK,
+ PWM0_MARK, SCIF4_RXD_C_MARK, TS_SDATA_B_MARK, RIF0_SYNC_MARK,
+ TPUTO3_MARK, SCIFB2_TXD_MARK, SDATA_B_MARK, EX_CS3_N_MARK,
+ SCIFA2_SCK_MARK, SCIF4_TXD_C_MARK, TS_SCK_B_MARK, RIF0_CLK_MARK,
+ BPFCLK_MARK, SCIFB2_SCK_MARK, MDATA_B_MARK, EX_CS4_N_MARK,
+ SCIFA2_RXD_MARK, I2C2_SCL_E_MARK, TS_SDEN_B_MARK, RIF0_D0_MARK,
+ FMCLK_MARK, SCIFB2_CTS_N_MARK, SCKZ_B_MARK, EX_CS5_N_MARK,
+ SCIFA2_TXD_MARK, I2C2_SDA_E_MARK, TS_SPSYNC_B_MARK, RIF0_D1_MARK,
+ FMIN_MARK, SCIFB2_RTS_N_MARK, STM_N_B_MARK, BS_N_MARK, DRACK0_MARK,
+ PWM1_C_MARK, TPUTO0_C_MARK, ATACS01_N_MARK, MTS_N_B_MARK, RD_N_MARK,
+ ATACS11_N_MARK, RD_WR_N_MARK, ATAG1_N_MARK,
+
+ /* IPSR4 */
+ EX_WAIT0_MARK, CAN_CLK_B_MARK, SCIF_CLK_MARK, PWMFSW0_MARK,
+ DU0_DR0_MARK, LCDOUT16_MARK, SCIF5_RXD_C_MARK, I2C2_SCL_D_MARK,
+ CC50_STATE0_MARK, DU0_DR1_MARK, LCDOUT17_MARK, SCIF5_TXD_C_MARK,
+ I2C2_SDA_D_MARK, CC50_STATE1_MARK, DU0_DR2_MARK, LCDOUT18_MARK,
+ CC50_STATE2_MARK, DU0_DR3_MARK, LCDOUT19_MARK, CC50_STATE3_MARK,
+ DU0_DR4_MARK, LCDOUT20_MARK, CC50_STATE4_MARK, DU0_DR5_MARK,
+ LCDOUT21_MARK, CC50_STATE5_MARK, DU0_DR6_MARK, LCDOUT22_MARK,
+ CC50_STATE6_MARK, DU0_DR7_MARK, LCDOUT23_MARK, CC50_STATE7_MARK,
+ DU0_DG0_MARK, LCDOUT8_MARK, SCIFA0_RXD_C_MARK, I2C3_SCL_D_MARK,
+ CC50_STATE8_MARK, DU0_DG1_MARK, LCDOUT9_MARK, SCIFA0_TXD_C_MARK,
+ I2C3_SDA_D_MARK, CC50_STATE9_MARK, DU0_DG2_MARK, LCDOUT10_MARK,
+ CC50_STATE10_MARK, DU0_DG3_MARK, LCDOUT11_MARK, CC50_STATE11_MARK,
+ DU0_DG4_MARK, LCDOUT12_MARK, CC50_STATE12_MARK,
+
+ /* IPSR5 */
+ DU0_DG5_MARK, LCDOUT13_MARK, CC50_STATE13_MARK, DU0_DG6_MARK,
+ LCDOUT14_MARK, CC50_STATE14_MARK, DU0_DG7_MARK, LCDOUT15_MARK,
+ CC50_STATE15_MARK, DU0_DB0_MARK, LCDOUT0_MARK, SCIFA4_RXD_C_MARK,
+ I2C4_SCL_D_MARK, CAN0_RX_C_MARK, CC50_STATE16_MARK, DU0_DB1_MARK,
+ LCDOUT1_MARK, SCIFA4_TXD_C_MARK, I2C4_SDA_D_MARK, CAN0_TX_C_MARK,
+ CC50_STATE17_MARK, DU0_DB2_MARK, LCDOUT2_MARK, CC50_STATE18_MARK,
+ DU0_DB3_MARK, LCDOUT3_MARK, CC50_STATE19_MARK, DU0_DB4_MARK,
+ LCDOUT4_MARK, CC50_STATE20_MARK, DU0_DB5_MARK, LCDOUT5_MARK,
+ CC50_STATE21_MARK, DU0_DB6_MARK, LCDOUT6_MARK, CC50_STATE22_MARK,
+ DU0_DB7_MARK, LCDOUT7_MARK, CC50_STATE23_MARK, DU0_DOTCLKIN_MARK,
+ QSTVA_QVS_MARK, CC50_STATE24_MARK, DU0_DOTCLKOUT0_MARK,
+ QCLK_MARK, CC50_STATE25_MARK, DU0_DOTCLKOUT1_MARK, QSTVB_QVE_MARK,
+ CC50_STATE26_MARK, DU0_EXHSYNC_DU0_HSYNC_MARK, QSTH_QHS_MARK,
+ CC50_STATE27_MARK,
+
+ /* IPSR6 */
+ DU0_EXVSYNC_DU0_VSYNC_MARK, QSTB_QHE_MARK, CC50_STATE28_MARK,
+ DU0_EXODDF_DU0_ODDF_DISP_CDE_MARK, QCPV_QDE_MARK, CC50_STATE29_MARK,
+ DU0_DISP_MARK, QPOLA_MARK, CC50_STATE30_MARK, DU0_CDE_MARK, QPOLB_MARK,
+ CC50_STATE31_MARK, VI0_CLK_MARK, AVB_RX_CLK_MARK, VI0_DATA0_VI0_B0_MARK,
+ AVB_RX_DV_MARK, VI0_DATA1_VI0_B1_MARK, AVB_RXD0_MARK,
+ VI0_DATA2_VI0_B2_MARK, AVB_RXD1_MARK, VI0_DATA3_VI0_B3_MARK,
+ AVB_RXD2_MARK, VI0_DATA4_VI0_B4_MARK, AVB_RXD3_MARK,
+ VI0_DATA5_VI0_B5_MARK, AVB_RXD4_MARK, VI0_DATA6_VI0_B6_MARK,
+ AVB_RXD5_MARK, VI0_DATA7_VI0_B7_MARK, AVB_RXD6_MARK, VI0_CLKENB_MARK,
+ I2C3_SCL_MARK, SCIFA5_RXD_C_MARK, IETX_C_MARK, AVB_RXD7_MARK,
+ VI0_FIELD_MARK, I2C3_SDA_MARK, SCIFA5_TXD_C_MARK, IECLK_C_MARK,
+ AVB_RX_ER_MARK, VI0_HSYNC_N_MARK, SCIF0_RXD_B_MARK, I2C0_SCL_C_MARK,
+ IERX_C_MARK, AVB_COL_MARK, VI0_VSYNC_N_MARK, SCIF0_TXD_B_MARK,
+ I2C0_SDA_C_MARK, AUDIO_CLKOUT_B_MARK, AVB_TX_EN_MARK, ETH_MDIO_MARK,
+ VI0_G0_MARK, MSIOF2_RXD_B_MARK, IIC0_SCL_D_MARK, AVB_TX_CLK_MARK,
+ ADIDATA_MARK, AD_DI_MARK,
+
+ /* IPSR7 */
+ ETH_CRS_DV_MARK, VI0_G1_MARK, MSIOF2_TXD_B_MARK, IIC0_SDA_D_MARK,
+ AVB_TXD0_MARK, ADICS_SAMP_MARK, AD_DO_MARK, ETH_RX_ER_MARK, VI0_G2_MARK,
+ MSIOF2_SCK_B_MARK, CAN0_RX_B_MARK, AVB_TXD1_MARK, ADICLK_MARK,
+ AD_CLK_MARK, ETH_RXD0_MARK, VI0_G3_MARK, MSIOF2_SYNC_B_MARK,
+ CAN0_TX_B_MARK, AVB_TXD2_MARK, ADICHS0_MARK, AD_NCS_N_MARK,
+ ETH_RXD1_MARK, VI0_G4_MARK, MSIOF2_SS1_B_MARK, SCIF4_RXD_D_MARK,
+ AVB_TXD3_MARK, ADICHS1_MARK, ETH_LINK_MARK, VI0_G5_MARK,
+ MSIOF2_SS2_B_MARK, SCIF4_TXD_D_MARK, AVB_TXD4_MARK, ADICHS2_MARK,
+ ETH_REFCLK_MARK, VI0_G6_MARK, SCIF2_SCK_C_MARK, AVB_TXD5_MARK,
+ SSI_SCK5_B_MARK, ETH_TXD1_MARK, VI0_G7_MARK, SCIF2_RXD_C_MARK,
+ IIC1_SCL_D_MARK, AVB_TXD6_MARK, SSI_WS5_B_MARK, ETH_TX_EN_MARK,
+ VI0_R0_MARK, SCIF2_TXD_C_MARK, IIC1_SDA_D_MARK, AVB_TXD7_MARK,
+ SSI_SDATA5_B_MARK, ETH_MAGIC_MARK, VI0_R1_MARK, SCIF3_SCK_B_MARK,
+ AVB_TX_ER_MARK, SSI_SCK6_B_MARK, ETH_TXD0_MARK, VI0_R2_MARK,
+ SCIF3_RXD_B_MARK, I2C4_SCL_E_MARK, AVB_GTX_CLK_MARK, SSI_WS6_B_MARK,
+ DREQ0_N_MARK, SCIFB1_RXD_MARK,
+
+ /* IPSR8 */
+ ETH_MDC_MARK, VI0_R3_MARK, SCIF3_TXD_B_MARK, I2C4_SDA_E_MARK,
+ AVB_MDC_MARK, SSI_SDATA6_B_MARK, HSCIF0_HRX_MARK, VI0_R4_MARK,
+ I2C1_SCL_C_MARK, AUDIO_CLKA_B_MARK, AVB_MDIO_MARK, SSI_SCK78_B_MARK,
+ HSCIF0_HTX_MARK, VI0_R5_MARK, I2C1_SDA_C_MARK, AUDIO_CLKB_B_MARK,
+ AVB_LINK_MARK, SSI_WS78_B_MARK, HSCIF0_HCTS_N_MARK, VI0_R6_MARK,
+ SCIF0_RXD_D_MARK, I2C0_SCL_E_MARK, AVB_MAGIC_MARK, SSI_SDATA7_B_MARK,
+ HSCIF0_HRTS_N_MARK, VI0_R7_MARK, SCIF0_TXD_D_MARK, I2C0_SDA_E_MARK,
+ AVB_PHY_INT_MARK, SSI_SDATA8_B_MARK,
+ HSCIF0_HSCK_MARK, SCIF_CLK_B_MARK, AVB_CRS_MARK, AUDIO_CLKC_B_MARK,
+ I2C0_SCL_MARK, SCIF0_RXD_C_MARK, PWM5_MARK, TCLK1_B_MARK,
+ AVB_GTXREFCLK_MARK, CAN1_RX_D_MARK, TPUTO0_B_MARK, I2C0_SDA_MARK,
+ SCIF0_TXD_C_MARK, TPUTO0_MARK, CAN_CLK_MARK, DVC_MUTE_MARK,
+ CAN1_TX_D_MARK, I2C1_SCL_MARK, SCIF4_RXD_MARK, PWM5_B_MARK,
+ DU1_DR0_MARK, RIF1_SYNC_B_MARK, TS_SDATA_D_MARK, TPUTO1_B_MARK,
+ I2C1_SDA_MARK, SCIF4_TXD_MARK, IRQ5_MARK, DU1_DR1_MARK, RIF1_CLK_B_MARK,
+ TS_SCK_D_MARK, BPFCLK_C_MARK, MSIOF0_RXD_MARK, SCIF5_RXD_MARK,
+ I2C2_SCL_C_MARK, DU1_DR2_MARK, RIF1_D0_B_MARK, TS_SDEN_D_MARK,
+ FMCLK_C_MARK, RDS_CLK_MARK,
+
+ /* IPSR9 */
+ MSIOF0_TXD_MARK, SCIF5_TXD_MARK, I2C2_SDA_C_MARK, DU1_DR3_MARK,
+ RIF1_D1_B_MARK, TS_SPSYNC_D_MARK, FMIN_C_MARK, RDS_DATA_MARK,
+ MSIOF0_SCK_MARK, IRQ0_MARK, TS_SDATA_MARK, DU1_DR4_MARK, RIF1_SYNC_MARK,
+ TPUTO1_C_MARK, MSIOF0_SYNC_MARK, PWM1_MARK, TS_SCK_MARK, DU1_DR5_MARK,
+ RIF1_CLK_MARK, BPFCLK_B_MARK, MSIOF0_SS1_MARK, SCIFA0_RXD_MARK,
+ TS_SDEN_MARK, DU1_DR6_MARK, RIF1_D0_MARK, FMCLK_B_MARK, RDS_CLK_B_MARK,
+ MSIOF0_SS2_MARK, SCIFA0_TXD_MARK, TS_SPSYNC_MARK, DU1_DR7_MARK,
+ RIF1_D1_MARK, FMIN_B_MARK, RDS_DATA_B_MARK, HSCIF1_HRX_MARK,
+ I2C4_SCL_MARK, PWM6_MARK, DU1_DG0_MARK, HSCIF1_HTX_MARK,
+ I2C4_SDA_MARK, TPUTO1_MARK, DU1_DG1_MARK, HSCIF1_HSCK_MARK,
+ PWM2_MARK, IETX_MARK, DU1_DG2_MARK, REMOCON_B_MARK, SPEEDIN_B_MARK,
+ VSP_B_MARK, HSCIF1_HCTS_N_MARK, SCIFA4_RXD_MARK, IECLK_MARK,
+ DU1_DG3_MARK, SSI_SCK1_B_MARK, CAN_DEBUG_HW_TRIGGER_MARK,
+ CC50_STATE32_MARK, HSCIF1_HRTS_N_MARK, SCIFA4_TXD_MARK, IERX_MARK,
+ DU1_DG4_MARK, SSI_WS1_B_MARK, CAN_STEP0_MARK, CC50_STATE33_MARK,
+ SCIF1_SCK_MARK, PWM3_MARK, TCLK2_MARK, DU1_DG5_MARK, SSI_SDATA1_B_MARK,
+ CAN_TXCLK_MARK, CC50_STATE34_MARK,
+
+ /* IPSR10 */
+ SCIF1_RXD_MARK, IIC0_SCL_MARK, DU1_DG6_MARK, SSI_SCK2_B_MARK,
+ CAN_DEBUGOUT0_MARK, CC50_STATE35_MARK, SCIF1_TXD_MARK, IIC0_SDA_MARK,
+ DU1_DG7_MARK, SSI_WS2_B_MARK, CAN_DEBUGOUT1_MARK, CC50_STATE36_MARK,
+ SCIF2_RXD_MARK, IIC1_SCL_MARK, DU1_DB0_MARK, SSI_SDATA2_B_MARK,
+ USB0_EXTLP_MARK, CAN_DEBUGOUT2_MARK, CC50_STATE37_MARK, SCIF2_TXD_MARK,
+ IIC1_SDA_MARK, DU1_DB1_MARK, SSI_SCK9_B_MARK, USB0_OVC1_MARK,
+ CAN_DEBUGOUT3_MARK, CC50_STATE38_MARK, SCIF2_SCK_MARK, IRQ1_MARK,
+ DU1_DB2_MARK, SSI_WS9_B_MARK, USB0_IDIN_MARK, CAN_DEBUGOUT4_MARK,
+ CC50_STATE39_MARK, SCIF3_SCK_MARK, IRQ2_MARK, BPFCLK_D_MARK,
+ DU1_DB3_MARK, SSI_SDATA9_B_MARK, TANS2_MARK, CAN_DEBUGOUT5_MARK,
+ CC50_OSCOUT_MARK, SCIF3_RXD_MARK, I2C1_SCL_E_MARK, FMCLK_D_MARK,
+ DU1_DB4_MARK, AUDIO_CLKA_C_MARK, SSI_SCK4_B_MARK, CAN_DEBUGOUT6_MARK,
+ RDS_CLK_C_MARK, SCIF3_TXD_MARK, I2C1_SDA_E_MARK, FMIN_D_MARK,
+ DU1_DB5_MARK, AUDIO_CLKB_C_MARK, SSI_WS4_B_MARK, CAN_DEBUGOUT7_MARK,
+ RDS_DATA_C_MARK, I2C2_SCL_MARK, SCIFA5_RXD_MARK, DU1_DB6_MARK,
+ AUDIO_CLKC_C_MARK, SSI_SDATA4_B_MARK, CAN_DEBUGOUT8_MARK, I2C2_SDA_MARK,
+ SCIFA5_TXD_MARK, DU1_DB7_MARK, AUDIO_CLKOUT_C_MARK, CAN_DEBUGOUT9_MARK,
+ SSI_SCK5_MARK, SCIFA3_SCK_MARK, DU1_DOTCLKIN_MARK, CAN_DEBUGOUT10_MARK,
+
+ /* IPSR11 */
+ SSI_WS5_MARK, SCIFA3_RXD_MARK, I2C3_SCL_C_MARK, DU1_DOTCLKOUT0_MARK,
+ CAN_DEBUGOUT11_MARK, SSI_SDATA5_MARK, SCIFA3_TXD_MARK, I2C3_SDA_C_MARK,
+ DU1_DOTCLKOUT1_MARK, CAN_DEBUGOUT12_MARK, SSI_SCK6_MARK,
+ SCIFA1_SCK_B_MARK, DU1_EXHSYNC_DU1_HSYNC_MARK, CAN_DEBUGOUT13_MARK,
+ SSI_WS6_MARK, SCIFA1_RXD_B_MARK, I2C4_SCL_C_MARK,
+ DU1_EXVSYNC_DU1_VSYNC_MARK, CAN_DEBUGOUT14_MARK, SSI_SDATA6_MARK,
+ SCIFA1_TXD_B_MARK, I2C4_SDA_C_MARK, DU1_EXODDF_DU1_ODDF_DISP_CDE_MARK,
+ CAN_DEBUGOUT15_MARK, SSI_SCK78_MARK, SCIFA2_SCK_B_MARK, IIC0_SDA_C_MARK,
+ DU1_DISP_MARK, SSI_WS78_MARK, SCIFA2_RXD_B_MARK, IIC0_SCL_C_MARK,
+ DU1_CDE_MARK, SSI_SDATA7_MARK, SCIFA2_TXD_B_MARK, IRQ8_MARK,
+ AUDIO_CLKA_D_MARK, CAN_CLK_D_MARK, PCMOE_N_MARK, SSI_SCK0129_MARK,
+ MSIOF1_RXD_B_MARK, SCIF5_RXD_D_MARK, ADIDATA_B_MARK, AD_DI_B_MARK,
+ PCMWE_N_MARK, SSI_WS0129_MARK, MSIOF1_TXD_B_MARK, SCIF5_TXD_D_MARK,
+ ADICS_SAMP_B_MARK, AD_DO_B_MARK, SSI_SDATA0_MARK, MSIOF1_SCK_B_MARK,
+ PWM0_B_MARK, ADICLK_B_MARK, AD_CLK_B_MARK,
+
+ /* IPSR12 */
+ SSI_SCK34_MARK, MSIOF1_SYNC_B_MARK, SCIFA1_SCK_C_MARK, ADICHS0_B_MARK,
+ AD_NCS_N_B_MARK, DREQ1_N_B_MARK, SSI_WS34_MARK, MSIOF1_SS1_B_MARK,
+ SCIFA1_RXD_C_MARK, ADICHS1_B_MARK, CAN1_RX_C_MARK, DACK1_B_MARK,
+ SSI_SDATA3_MARK, MSIOF1_SS2_B_MARK, SCIFA1_TXD_C_MARK, ADICHS2_B_MARK,
+ CAN1_TX_C_MARK, DREQ2_N_MARK, SSI_SCK4_MARK, MLB_CLK_MARK, IETX_B_MARK,
+ IRD_TX_MARK, SSI_WS4_MARK, MLB_SIG_MARK, IECLK_B_MARK, IRD_RX_MARK,
+ SSI_SDATA4_MARK, MLB_DAT_MARK, IERX_B_MARK, IRD_SCK_MARK,
+ SSI_SDATA8_MARK, SCIF1_SCK_B_MARK, PWM1_B_MARK, IRQ9_MARK, REMOCON_MARK,
+ DACK2_MARK, ETH_MDIO_B_MARK, SSI_SCK1_MARK, SCIF1_RXD_B_MARK,
+ IIC1_SCL_C_MARK, VI1_CLK_MARK, CAN0_RX_D_MARK, AVB_AVTP_CAPTURE_MARK,
+ ETH_CRS_DV_B_MARK, SSI_WS1_MARK, SCIF1_TXD_B_MARK, IIC1_SDA_C_MARK,
+ VI1_DATA0_MARK, CAN0_TX_D_MARK, AVB_AVTP_MATCH_MARK, ETH_RX_ER_B_MARK,
+ SSI_SDATA1_MARK, HSCIF1_HRX_B_MARK, VI1_DATA1_MARK, SDATA_MARK,
+ ATAG0_N_MARK, ETH_RXD0_B_MARK, SSI_SCK2_MARK, HSCIF1_HTX_B_MARK,
+ VI1_DATA2_MARK, MDATA_MARK, ATAWR0_N_MARK, ETH_RXD1_B_MARK,
+
+ /* IPSR13 */
+ SSI_WS2_MARK, HSCIF1_HCTS_N_B_MARK, SCIFA0_RXD_D_MARK, VI1_DATA3_MARK,
+ SCKZ_MARK, ATACS00_N_MARK, ETH_LINK_B_MARK, SSI_SDATA2_MARK,
+ HSCIF1_HRTS_N_B_MARK, SCIFA0_TXD_D_MARK, VI1_DATA4_MARK, STM_N_MARK,
+ ATACS10_N_MARK, ETH_REFCLK_B_MARK, SSI_SCK9_MARK, SCIF2_SCK_B_MARK,
+ PWM2_B_MARK, VI1_DATA5_MARK, MTS_N_MARK, EX_WAIT1_MARK,
+ ETH_TXD1_B_MARK, SSI_WS9_MARK, SCIF2_RXD_B_MARK, I2C3_SCL_E_MARK,
+ VI1_DATA6_MARK, ATARD0_N_MARK, ETH_TX_EN_B_MARK, SSI_SDATA9_MARK,
+ SCIF2_TXD_B_MARK, I2C3_SDA_E_MARK, VI1_DATA7_MARK, ATADIR0_N_MARK,
+ ETH_MAGIC_B_MARK, AUDIO_CLKA_MARK, I2C0_SCL_B_MARK, SCIFA4_RXD_D_MARK,
+ VI1_CLKENB_MARK, TS_SDATA_C_MARK, RIF0_SYNC_B_MARK, ETH_TXD0_B_MARK,
+ AUDIO_CLKB_MARK, I2C0_SDA_B_MARK, SCIFA4_TXD_D_MARK, VI1_FIELD_MARK,
+ TS_SCK_C_MARK, RIF0_CLK_B_MARK, BPFCLK_E_MARK, ETH_MDC_B_MARK,
+ AUDIO_CLKC_MARK, I2C4_SCL_B_MARK, SCIFA5_RXD_D_MARK, VI1_HSYNC_N_MARK,
+ TS_SDEN_C_MARK, RIF0_D0_B_MARK, FMCLK_E_MARK, RDS_CLK_D_MARK,
+ AUDIO_CLKOUT_MARK, I2C4_SDA_B_MARK, SCIFA5_TXD_D_MARK, VI1_VSYNC_N_MARK,
+ TS_SPSYNC_C_MARK, RIF0_D1_B_MARK, FMIN_E_MARK, RDS_DATA_D_MARK,
+ PINMUX_MARK_END,
+};
+
+static const u16 pinmux_data[] = {
+ PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
+
+ PINMUX_DATA(A2_MARK, FN_A2),
+ PINMUX_DATA(WE0_N_MARK, FN_WE0_N),
+ PINMUX_DATA(WE1_N_MARK, FN_WE1_N),
+ PINMUX_DATA(DACK0_MARK, FN_DACK0),
+ PINMUX_DATA(USB0_PWEN_MARK, FN_USB0_PWEN),
+ PINMUX_DATA(USB0_OVC_MARK, FN_USB0_OVC),
+ PINMUX_DATA(USB1_PWEN_MARK, FN_USB1_PWEN),
+ PINMUX_DATA(USB1_OVC_MARK, FN_USB1_OVC),
+ PINMUX_DATA(SD0_CLK_MARK, FN_SD0_CLK),
+ PINMUX_DATA(SD0_CMD_MARK, FN_SD0_CMD),
+ PINMUX_DATA(SD0_DATA0_MARK, FN_SD0_DATA0),
+ PINMUX_DATA(SD0_DATA1_MARK, FN_SD0_DATA1),
+ PINMUX_DATA(SD0_DATA2_MARK, FN_SD0_DATA2),
+ PINMUX_DATA(SD0_DATA3_MARK, FN_SD0_DATA3),
+ PINMUX_DATA(SD0_CD_MARK, FN_SD0_CD),
+ PINMUX_DATA(SD0_WP_MARK, FN_SD0_WP),
+ PINMUX_DATA(SD1_CLK_MARK, FN_SD1_CLK),
+ PINMUX_DATA(SD1_CMD_MARK, FN_SD1_CMD),
+ PINMUX_DATA(SD1_DATA0_MARK, FN_SD1_DATA0),
+ PINMUX_DATA(SD1_DATA1_MARK, FN_SD1_DATA1),
+ PINMUX_DATA(SD1_DATA2_MARK, FN_SD1_DATA2),
+ PINMUX_DATA(SD1_DATA3_MARK, FN_SD1_DATA3),
+
+ /* IPSR0 */
+ PINMUX_IPSR_DATA(IP0_0, SD1_CD),
+ PINMUX_IPSR_MODSEL_DATA(IP0_0, CAN0_RX, SEL_CAN0_0),
+ PINMUX_IPSR_DATA(IP0_9_8, SD1_WP),
+ PINMUX_IPSR_DATA(IP0_9_8, IRQ7),
+ PINMUX_IPSR_MODSEL_DATA(IP0_9_8, CAN0_TX, SEL_CAN0_0),
+ PINMUX_IPSR_DATA(IP0_10, MMC_CLK),
+ PINMUX_IPSR_DATA(IP0_10, SD2_CLK),
+ PINMUX_IPSR_DATA(IP0_11, MMC_CMD),
+ PINMUX_IPSR_DATA(IP0_11, SD2_CMD),
+ PINMUX_IPSR_DATA(IP0_12, MMC_D0),
+ PINMUX_IPSR_DATA(IP0_12, SD2_DATA0),
+ PINMUX_IPSR_DATA(IP0_13, MMC_D1),
+ PINMUX_IPSR_DATA(IP0_13, SD2_DATA1),
+ PINMUX_IPSR_DATA(IP0_14, MMC_D2),
+ PINMUX_IPSR_DATA(IP0_14, SD2_DATA2),
+ PINMUX_IPSR_DATA(IP0_15, MMC_D3),
+ PINMUX_IPSR_DATA(IP0_15, SD2_DATA3),
+ PINMUX_IPSR_DATA(IP0_16, MMC_D4),
+ PINMUX_IPSR_DATA(IP0_16, SD2_CD),
+ PINMUX_IPSR_DATA(IP0_17, MMC_D5),
+ PINMUX_IPSR_DATA(IP0_17, SD2_WP),
+ PINMUX_IPSR_DATA(IP0_19_18, MMC_D6),
+ PINMUX_IPSR_MODSEL_DATA(IP0_19_18, SCIF0_RXD, SEL_SCIF0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_19_18, I2C2_SCL_B, SEL_I2C02_1),
+ PINMUX_IPSR_MODSEL_DATA(IP0_19_18, CAN1_RX, SEL_CAN1_0),
+ PINMUX_IPSR_DATA(IP0_21_20, MMC_D7),
+ PINMUX_IPSR_MODSEL_DATA(IP0_21_20, SCIF0_TXD, SEL_SCIF0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_21_20, I2C2_SDA_B, SEL_I2C02_1),
+ PINMUX_IPSR_MODSEL_DATA(IP0_21_20, CAN1_TX, SEL_CAN1_0),
+ PINMUX_IPSR_DATA(IP0_23_22, D0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_23_22, SCIFA3_SCK_B, SEL_SCIFA3_1),
+ PINMUX_IPSR_DATA(IP0_23_22, IRQ4),
+ PINMUX_IPSR_DATA(IP0_24, D1),
+ PINMUX_IPSR_MODSEL_DATA(IP0_24, SCIFA3_RXD_B, SEL_SCIFA3_1),
+ PINMUX_IPSR_DATA(IP0_25, D2),
+ PINMUX_IPSR_MODSEL_DATA(IP0_25, SCIFA3_TXD_B, SEL_SCIFA3_1),
+ PINMUX_IPSR_DATA(IP0_27_26, D3),
+ PINMUX_IPSR_MODSEL_DATA(IP0_27_26, I2C3_SCL_B, SEL_I2C03_1),
+ PINMUX_IPSR_MODSEL_DATA(IP0_27_26, SCIF5_RXD_B, SEL_SCIF5_1),
+ PINMUX_IPSR_DATA(IP0_29_28, D4),
+ PINMUX_IPSR_MODSEL_DATA(IP0_29_28, I2C3_SDA_B, SEL_I2C03_1),
+ PINMUX_IPSR_MODSEL_DATA(IP0_29_28, SCIF5_TXD_B, SEL_SCIF5_1),
+ PINMUX_IPSR_DATA(IP0_31_30, D5),
+ PINMUX_IPSR_MODSEL_DATA(IP0_31_30, SCIF4_RXD_B, SEL_SCIF4_1),
+ PINMUX_IPSR_MODSEL_DATA(IP0_31_30, I2C0_SCL_D, SEL_I2C00_3),
+
+ /* IPSR1 */
+ PINMUX_IPSR_DATA(IP1_1_0, D6),
+ PINMUX_IPSR_MODSEL_DATA(IP1_1_0, SCIF4_TXD_B, SEL_SCIF4_1),
+ PINMUX_IPSR_MODSEL_DATA(IP1_1_0, I2C0_SDA_D, SEL_I2C00_3),
+ PINMUX_IPSR_DATA(IP1_3_2, D7),
+ PINMUX_IPSR_DATA(IP1_3_2, IRQ3),
+ PINMUX_IPSR_MODSEL_DATA(IP1_3_2, TCLK1, SEL_TMU_0),
+ PINMUX_IPSR_DATA(IP1_3_2, PWM6_B),
+ PINMUX_IPSR_DATA(IP1_5_4, D8),
+ PINMUX_IPSR_DATA(IP1_5_4, HSCIF2_HRX),
+ PINMUX_IPSR_MODSEL_DATA(IP1_5_4, I2C1_SCL_B, SEL_I2C01_1),
+ PINMUX_IPSR_DATA(IP1_7_6, D9),
+ PINMUX_IPSR_DATA(IP1_7_6, HSCIF2_HTX),
+ PINMUX_IPSR_MODSEL_DATA(IP1_7_6, I2C1_SDA_B, SEL_I2C01_1),
+ PINMUX_IPSR_DATA(IP1_10_8, D10),
+ PINMUX_IPSR_DATA(IP1_10_8, HSCIF2_HSCK),
+ PINMUX_IPSR_MODSEL_DATA(IP1_10_8, SCIF1_SCK_C, SEL_SCIF1_2),
+ PINMUX_IPSR_DATA(IP1_10_8, IRQ6),
+ PINMUX_IPSR_DATA(IP1_10_8, PWM5_C),
+ PINMUX_IPSR_DATA(IP1_12_11, D11),
+ PINMUX_IPSR_DATA(IP1_12_11, HSCIF2_HCTS_N),
+ PINMUX_IPSR_MODSEL_DATA(IP1_12_11, SCIF1_RXD_C, SEL_SCIF1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP1_12_11, I2C1_SCL_D, SEL_I2C01_3),
+ PINMUX_IPSR_DATA(IP1_14_13, D12),
+ PINMUX_IPSR_DATA(IP1_14_13, HSCIF2_HRTS_N),
+ PINMUX_IPSR_MODSEL_DATA(IP1_14_13, SCIF1_TXD_C, SEL_SCIF1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP1_14_13, I2C1_SDA_D, SEL_I2C01_3),
+ PINMUX_IPSR_DATA(IP1_17_15, D13),
+ PINMUX_IPSR_MODSEL_DATA(IP1_17_15, SCIFA1_SCK, SEL_SCIFA1_0),
+ PINMUX_IPSR_DATA(IP1_17_15, TANS1),
+ PINMUX_IPSR_DATA(IP1_17_15, PWM2_C),
+ PINMUX_IPSR_MODSEL_DATA(IP1_17_15, TCLK2_B, SEL_TMU_1),
+ PINMUX_IPSR_DATA(IP1_19_18, D14),
+ PINMUX_IPSR_MODSEL_DATA(IP1_19_18, SCIFA1_RXD, SEL_SCIFA1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_19_18, IIC0_SCL_B, SEL_IIC00_1),
+ PINMUX_IPSR_DATA(IP1_21_20, D15),
+ PINMUX_IPSR_MODSEL_DATA(IP1_21_20, SCIFA1_TXD, SEL_SCIFA1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_21_20, IIC0_SDA_B, SEL_IIC00_1),
+ PINMUX_IPSR_DATA(IP1_23_22, A0),
+ PINMUX_IPSR_DATA(IP1_23_22, SCIFB1_SCK),
+ PINMUX_IPSR_DATA(IP1_23_22, PWM3_B),
+ PINMUX_IPSR_DATA(IP1_24, A1),
+ PINMUX_IPSR_DATA(IP1_24, SCIFB1_TXD),
+ PINMUX_IPSR_DATA(IP1_26, A3),
+ PINMUX_IPSR_DATA(IP1_26, SCIFB0_SCK),
+ PINMUX_IPSR_DATA(IP1_27, A4),
+ PINMUX_IPSR_DATA(IP1_27, SCIFB0_TXD),
+ PINMUX_IPSR_DATA(IP1_29_28, A5),
+ PINMUX_IPSR_DATA(IP1_29_28, SCIFB0_RXD),
+ PINMUX_IPSR_DATA(IP1_29_28, PWM4_B),
+ PINMUX_IPSR_DATA(IP1_29_28, TPUTO3_C),
+ PINMUX_IPSR_DATA(IP1_31_30, A6),
+ PINMUX_IPSR_DATA(IP1_31_30, SCIFB0_CTS_N),
+ PINMUX_IPSR_MODSEL_DATA(IP1_31_30, SCIFA4_RXD_B, SEL_SCIFA4_1),
+ PINMUX_IPSR_DATA(IP1_31_30, TPUTO2_C),
+
+ /* IPSR2 */
+ PINMUX_IPSR_DATA(IP2_1_0, A7),
+ PINMUX_IPSR_DATA(IP2_1_0, SCIFB0_RTS_N),
+ PINMUX_IPSR_MODSEL_DATA(IP2_1_0, SCIFA4_TXD_B, SEL_SCIFA4_1),
+ PINMUX_IPSR_DATA(IP2_3_2, A8),
+ PINMUX_IPSR_MODSEL_DATA(IP2_3_2, MSIOF1_RXD, SEL_MSI1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_3_2, SCIFA0_RXD_B, SEL_SCIFA0_1),
+ PINMUX_IPSR_DATA(IP2_5_4, A9),
+ PINMUX_IPSR_MODSEL_DATA(IP2_5_4, MSIOF1_TXD, SEL_MSI1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_5_4, SCIFA0_TXD_B, SEL_SCIFA0_1),
+ PINMUX_IPSR_DATA(IP2_7_6, A10),
+ PINMUX_IPSR_MODSEL_DATA(IP2_7_6, MSIOF1_SCK, SEL_MSI1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_7_6, IIC1_SCL_B, SEL_IIC01_1),
+ PINMUX_IPSR_DATA(IP2_9_8, A11),
+ PINMUX_IPSR_MODSEL_DATA(IP2_9_8, MSIOF1_SYNC, SEL_MSI1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_9_8, IIC1_SDA_B, SEL_IIC01_1),
+ PINMUX_IPSR_DATA(IP2_11_10, A12),
+ PINMUX_IPSR_MODSEL_DATA(IP2_11_10, MSIOF1_SS1, SEL_MSI1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_11_10, SCIFA5_RXD_B, SEL_SCIFA5_1),
+ PINMUX_IPSR_DATA(IP2_13_12, A13),
+ PINMUX_IPSR_MODSEL_DATA(IP2_13_12, MSIOF1_SS2, SEL_MSI1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_13_12, SCIFA5_TXD_B, SEL_SCIFA5_1),
+ PINMUX_IPSR_DATA(IP2_15_14, A14),
+ PINMUX_IPSR_MODSEL_DATA(IP2_15_14, MSIOF2_RXD, SEL_MSI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_15_14, HSCIF0_HRX_B, SEL_HSCIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP2_15_14, DREQ1_N, SEL_LBS_0),
+ PINMUX_IPSR_DATA(IP2_17_16, A15),
+ PINMUX_IPSR_MODSEL_DATA(IP2_17_16, MSIOF2_TXD, SEL_MSI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_17_16, HSCIF0_HTX_B, SEL_HSCIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP2_17_16, DACK1, SEL_LBS_0),
+ PINMUX_IPSR_DATA(IP2_20_18, A16),
+ PINMUX_IPSR_MODSEL_DATA(IP2_20_18, MSIOF2_SCK, SEL_MSI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_20_18, HSCIF0_HSCK_B, SEL_HSCIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP2_20_18, SPEEDIN, SEL_RSP_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_20_18, VSP, SEL_SPDM_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_20_18, CAN_CLK_C, SEL_CAN_2),
+ PINMUX_IPSR_DATA(IP2_20_18, TPUTO2_B),
+ PINMUX_IPSR_DATA(IP2_23_21, A17),
+ PINMUX_IPSR_MODSEL_DATA(IP2_23_21, MSIOF2_SYNC, SEL_MSI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_23_21, SCIF4_RXD_E, SEL_SCIF4_4),
+ PINMUX_IPSR_MODSEL_DATA(IP2_23_21, CAN1_RX_B, SEL_CAN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP2_23_21, AVB_AVTP_CAPTURE_B, SEL_AVB_1),
+ PINMUX_IPSR_DATA(IP2_26_24, A18),
+ PINMUX_IPSR_MODSEL_DATA(IP2_26_24, MSIOF2_SS1, SEL_MSI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_26_24, SCIF4_TXD_E, SEL_SCIF4_4),
+ PINMUX_IPSR_MODSEL_DATA(IP2_26_24, CAN1_TX_B, SEL_CAN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP2_26_24, AVB_AVTP_MATCH_B, SEL_AVB_1),
+ PINMUX_IPSR_DATA(IP2_29_27, A19),
+ PINMUX_IPSR_MODSEL_DATA(IP2_29_27, MSIOF2_SS2, SEL_MSI2_0),
+ PINMUX_IPSR_DATA(IP2_29_27, PWM4),
+ PINMUX_IPSR_DATA(IP2_29_27, TPUTO2),
+ PINMUX_IPSR_DATA(IP2_29_27, MOUT0),
+ PINMUX_IPSR_DATA(IP2_31_30, A20),
+ PINMUX_IPSR_DATA(IP2_31_30, SPCLK),
+ PINMUX_IPSR_DATA(IP2_29_27, MOUT1),
+
+ /* IPSR3 */
+ PINMUX_IPSR_DATA(IP3_1_0, A21),
+ PINMUX_IPSR_DATA(IP3_1_0, MOSI_IO0),
+ PINMUX_IPSR_DATA(IP3_1_0, MOUT2),
+ PINMUX_IPSR_DATA(IP3_3_2, A22),
+ PINMUX_IPSR_DATA(IP3_3_2, MISO_IO1),
+ PINMUX_IPSR_DATA(IP3_3_2, MOUT5),
+ PINMUX_IPSR_DATA(IP3_3_2, ATADIR1_N),
+ PINMUX_IPSR_DATA(IP3_5_4, A23),
+ PINMUX_IPSR_DATA(IP3_5_4, IO2),
+ PINMUX_IPSR_DATA(IP3_5_4, MOUT6),
+ PINMUX_IPSR_DATA(IP3_5_4, ATAWR1_N),
+ PINMUX_IPSR_DATA(IP3_7_6, A24),
+ PINMUX_IPSR_DATA(IP3_7_6, IO3),
+ PINMUX_IPSR_DATA(IP3_7_6, EX_WAIT2),
+ PINMUX_IPSR_DATA(IP3_9_8, A25),
+ PINMUX_IPSR_DATA(IP3_9_8, SSL),
+ PINMUX_IPSR_DATA(IP3_9_8, ATARD1_N),
+ PINMUX_IPSR_DATA(IP3_10, CS0_N),
+ PINMUX_IPSR_DATA(IP3_10, VI1_DATA8),
+ PINMUX_IPSR_DATA(IP3_11, CS1_N_A26),
+ PINMUX_IPSR_DATA(IP3_11, VI1_DATA9),
+ PINMUX_IPSR_DATA(IP3_12, EX_CS0_N),
+ PINMUX_IPSR_DATA(IP3_12, VI1_DATA10),
+ PINMUX_IPSR_DATA(IP3_14_13, EX_CS1_N),
+ PINMUX_IPSR_DATA(IP3_14_13, TPUTO3_B),
+ PINMUX_IPSR_DATA(IP3_14_13, SCIFB2_RXD),
+ PINMUX_IPSR_DATA(IP3_14_13, VI1_DATA11),
+ PINMUX_IPSR_DATA(IP3_17_15, EX_CS2_N),
+ PINMUX_IPSR_DATA(IP3_17_15, PWM0),
+ PINMUX_IPSR_MODSEL_DATA(IP3_17_15, SCIF4_RXD_C, SEL_SCIF4_2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_17_15, TS_SDATA_B, SEL_TSIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_17_15, RIF0_SYNC, SEL_DR0_0),
+ PINMUX_IPSR_DATA(IP3_17_15, TPUTO3),
+ PINMUX_IPSR_DATA(IP3_17_15, SCIFB2_TXD),
+ PINMUX_IPSR_MODSEL_DATA(IP3_17_15, SDATA_B, SEL_FSN_1),
+ PINMUX_IPSR_DATA(IP3_20_18, EX_CS3_N),
+ PINMUX_IPSR_MODSEL_DATA(IP3_20_18, SCIFA2_SCK, SEL_SCIFA2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP3_20_18, SCIF4_TXD_C, SEL_SCIF4_2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_20_18, TS_SCK_B, SEL_TSIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_20_18, RIF0_CLK, SEL_DR0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP3_20_18, BPFCLK, SEL_DARC_0),
+ PINMUX_IPSR_DATA(IP3_20_18, SCIFB2_SCK),
+ PINMUX_IPSR_MODSEL_DATA(IP3_20_18, MDATA_B, SEL_FSN_1),
+ PINMUX_IPSR_DATA(IP3_23_21, EX_CS4_N),
+ PINMUX_IPSR_MODSEL_DATA(IP3_23_21, SCIFA2_RXD, SEL_SCIFA2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP3_23_21, I2C2_SCL_E, SEL_I2C02_4),
+ PINMUX_IPSR_MODSEL_DATA(IP3_23_21, TS_SDEN_B, SEL_TSIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_23_21, RIF0_D0, SEL_DR0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP3_23_21, FMCLK, SEL_DARC_0),
+ PINMUX_IPSR_DATA(IP3_23_21, SCIFB2_CTS_N),
+ PINMUX_IPSR_MODSEL_DATA(IP3_23_21, SCKZ_B, SEL_FSN_1),
+ PINMUX_IPSR_DATA(IP3_26_24, EX_CS5_N),
+ PINMUX_IPSR_MODSEL_DATA(IP3_26_24, SCIFA2_TXD, SEL_SCIFA2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP3_26_24, I2C2_SDA_E, SEL_I2C02_4),
+ PINMUX_IPSR_MODSEL_DATA(IP3_26_24, TS_SPSYNC_B, SEL_TSIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_26_24, RIF0_D1, SEL_DR1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP3_26_24, FMIN, SEL_DARC_0),
+ PINMUX_IPSR_DATA(IP3_26_24, SCIFB2_RTS_N),
+ PINMUX_IPSR_MODSEL_DATA(IP3_26_24, STM_N_B, SEL_FSN_1),
+ PINMUX_IPSR_DATA(IP3_29_27, BS_N),
+ PINMUX_IPSR_DATA(IP3_29_27, DRACK0),
+ PINMUX_IPSR_DATA(IP3_29_27, PWM1_C),
+ PINMUX_IPSR_DATA(IP3_29_27, TPUTO0_C),
+ PINMUX_IPSR_DATA(IP3_29_27, ATACS01_N),
+ PINMUX_IPSR_MODSEL_DATA(IP3_29_27, MTS_N_B, SEL_FSN_1),
+ PINMUX_IPSR_DATA(IP3_30, RD_N),
+ PINMUX_IPSR_DATA(IP3_30, ATACS11_N),
+ PINMUX_IPSR_DATA(IP3_31, RD_WR_N),
+ PINMUX_IPSR_DATA(IP3_31, ATAG1_N),
+
+ /* IPSR4 */
+ PINMUX_IPSR_DATA(IP4_1_0, EX_WAIT0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_1_0, CAN_CLK_B, SEL_CAN_1),
+ PINMUX_IPSR_MODSEL_DATA(IP4_1_0, SCIF_CLK, SEL_SCIF0_0),
+ PINMUX_IPSR_DATA(IP4_1_0, PWMFSW0),
+ PINMUX_IPSR_DATA(IP4_4_2, DU0_DR0),
+ PINMUX_IPSR_DATA(IP4_4_2, LCDOUT16),
+ PINMUX_IPSR_MODSEL_DATA(IP4_4_2, SCIF5_RXD_C, SEL_SCIF5_2),
+ PINMUX_IPSR_MODSEL_DATA(IP4_4_2, I2C2_SCL_D, SEL_I2C02_3),
+ PINMUX_IPSR_DATA(IP4_4_2, CC50_STATE0),
+ PINMUX_IPSR_DATA(IP4_7_5, DU0_DR1),
+ PINMUX_IPSR_DATA(IP4_7_5, LCDOUT17),
+ PINMUX_IPSR_MODSEL_DATA(IP4_7_5, SCIF5_TXD_C, SEL_SCIF5_2),
+ PINMUX_IPSR_MODSEL_DATA(IP4_7_5, I2C2_SDA_D, SEL_I2C02_3),
+ PINMUX_IPSR_DATA(IP4_9_8, CC50_STATE1),
+ PINMUX_IPSR_DATA(IP4_9_8, DU0_DR2),
+ PINMUX_IPSR_DATA(IP4_9_8, LCDOUT18),
+ PINMUX_IPSR_DATA(IP4_9_8, CC50_STATE2),
+ PINMUX_IPSR_DATA(IP4_11_10, DU0_DR3),
+ PINMUX_IPSR_DATA(IP4_11_10, LCDOUT19),
+ PINMUX_IPSR_DATA(IP4_11_10, CC50_STATE3),
+ PINMUX_IPSR_DATA(IP4_13_12, DU0_DR4),
+ PINMUX_IPSR_DATA(IP4_13_12, LCDOUT20),
+ PINMUX_IPSR_DATA(IP4_13_12, CC50_STATE4),
+ PINMUX_IPSR_DATA(IP4_15_14, DU0_DR5),
+ PINMUX_IPSR_DATA(IP4_15_14, LCDOUT21),
+ PINMUX_IPSR_DATA(IP4_15_14, CC50_STATE5),
+ PINMUX_IPSR_DATA(IP4_17_16, DU0_DR6),
+ PINMUX_IPSR_DATA(IP4_17_16, LCDOUT22),
+ PINMUX_IPSR_DATA(IP4_17_16, CC50_STATE6),
+ PINMUX_IPSR_DATA(IP4_19_18, DU0_DR7),
+ PINMUX_IPSR_DATA(IP4_19_18, LCDOUT23),
+ PINMUX_IPSR_DATA(IP4_19_18, CC50_STATE7),
+ PINMUX_IPSR_DATA(IP4_22_20, DU0_DG0),
+ PINMUX_IPSR_DATA(IP4_22_20, LCDOUT8),
+ PINMUX_IPSR_MODSEL_DATA(IP4_22_20, SCIFA0_RXD_C, SEL_SCIFA0_2),
+ PINMUX_IPSR_MODSEL_DATA(IP4_22_20, I2C3_SCL_D, SEL_I2C03_3),
+ PINMUX_IPSR_DATA(IP4_22_20, CC50_STATE8),
+ PINMUX_IPSR_DATA(IP4_25_23, DU0_DG1),
+ PINMUX_IPSR_DATA(IP4_25_23, LCDOUT9),
+ PINMUX_IPSR_MODSEL_DATA(IP4_25_23, SCIFA0_TXD_C, SEL_SCIFA0_2),
+ PINMUX_IPSR_MODSEL_DATA(IP4_25_23, I2C3_SDA_D, SEL_I2C03_3),
+ PINMUX_IPSR_DATA(IP4_25_23, CC50_STATE9),
+ PINMUX_IPSR_DATA(IP4_27_26, DU0_DG2),
+ PINMUX_IPSR_DATA(IP4_27_26, LCDOUT10),
+ PINMUX_IPSR_DATA(IP4_27_26, CC50_STATE10),
+ PINMUX_IPSR_DATA(IP4_29_28, DU0_DG3),
+ PINMUX_IPSR_DATA(IP4_29_28, LCDOUT11),
+ PINMUX_IPSR_DATA(IP4_29_28, CC50_STATE11),
+ PINMUX_IPSR_DATA(IP4_31_30, DU0_DG4),
+ PINMUX_IPSR_DATA(IP4_31_30, LCDOUT12),
+ PINMUX_IPSR_DATA(IP4_31_30, CC50_STATE12),
+
+ /* IPSR5 */
+ PINMUX_IPSR_DATA(IP5_1_0, DU0_DG5),
+ PINMUX_IPSR_DATA(IP5_1_0, LCDOUT13),
+ PINMUX_IPSR_DATA(IP5_1_0, CC50_STATE13),
+ PINMUX_IPSR_DATA(IP5_3_2, DU0_DG6),
+ PINMUX_IPSR_DATA(IP5_3_2, LCDOUT14),
+ PINMUX_IPSR_DATA(IP5_3_2, CC50_STATE14),
+ PINMUX_IPSR_DATA(IP5_5_4, DU0_DG7),
+ PINMUX_IPSR_DATA(IP5_5_4, LCDOUT15),
+ PINMUX_IPSR_DATA(IP5_5_4, CC50_STATE15),
+ PINMUX_IPSR_DATA(IP5_8_6, DU0_DB0),
+ PINMUX_IPSR_DATA(IP5_8_6, LCDOUT0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_8_6, SCIFA4_RXD_C, SEL_SCIFA4_2),
+ PINMUX_IPSR_MODSEL_DATA(IP5_8_6, I2C4_SCL_D, SEL_I2C04_3),
+ PINMUX_IPSR_MODSEL_DATA(IP7_8_6, CAN0_RX_C, SEL_CAN0_2),
+ PINMUX_IPSR_DATA(IP5_8_6, CC50_STATE16),
+ PINMUX_IPSR_DATA(IP5_11_9, DU0_DB1),
+ PINMUX_IPSR_DATA(IP5_11_9, LCDOUT1),
+ PINMUX_IPSR_MODSEL_DATA(IP5_11_9, SCIFA4_TXD_C, SEL_SCIFA4_2),
+ PINMUX_IPSR_MODSEL_DATA(IP5_11_9, I2C4_SDA_D, SEL_I2C04_3),
+ PINMUX_IPSR_MODSEL_DATA(IP5_11_9, CAN0_TX_C, SEL_CAN0_2),
+ PINMUX_IPSR_DATA(IP5_11_9, CC50_STATE17),
+ PINMUX_IPSR_DATA(IP5_13_12, DU0_DB2),
+ PINMUX_IPSR_DATA(IP5_13_12, LCDOUT2),
+ PINMUX_IPSR_DATA(IP5_13_12, CC50_STATE18),
+ PINMUX_IPSR_DATA(IP5_15_14, DU0_DB3),
+ PINMUX_IPSR_DATA(IP5_15_14, LCDOUT3),
+ PINMUX_IPSR_DATA(IP5_15_14, CC50_STATE19),
+ PINMUX_IPSR_DATA(IP5_17_16, DU0_DB4),
+ PINMUX_IPSR_DATA(IP5_17_16, LCDOUT4),
+ PINMUX_IPSR_DATA(IP5_17_16, CC50_STATE20),
+ PINMUX_IPSR_DATA(IP5_19_18, DU0_DB5),
+ PINMUX_IPSR_DATA(IP5_19_18, LCDOUT5),
+ PINMUX_IPSR_DATA(IP5_19_18, CC50_STATE21),
+ PINMUX_IPSR_DATA(IP5_21_20, DU0_DB6),
+ PINMUX_IPSR_DATA(IP5_21_20, LCDOUT6),
+ PINMUX_IPSR_DATA(IP5_21_20, CC50_STATE22),
+ PINMUX_IPSR_DATA(IP5_23_22, DU0_DB7),
+ PINMUX_IPSR_DATA(IP5_23_22, LCDOUT7),
+ PINMUX_IPSR_DATA(IP5_23_22, CC50_STATE23),
+ PINMUX_IPSR_DATA(IP5_25_24, DU0_DOTCLKIN),
+ PINMUX_IPSR_DATA(IP5_25_24, QSTVA_QVS),
+ PINMUX_IPSR_DATA(IP5_25_24, CC50_STATE24),
+ PINMUX_IPSR_DATA(IP5_27_26, DU0_DOTCLKOUT0),
+ PINMUX_IPSR_DATA(IP5_27_26, QCLK),
+ PINMUX_IPSR_DATA(IP5_27_26, CC50_STATE25),
+ PINMUX_IPSR_DATA(IP5_29_28, DU0_DOTCLKOUT1),
+ PINMUX_IPSR_DATA(IP5_29_28, QSTVB_QVE),
+ PINMUX_IPSR_DATA(IP5_29_28, CC50_STATE26),
+ PINMUX_IPSR_DATA(IP5_31_30, DU0_EXHSYNC_DU0_HSYNC),
+ PINMUX_IPSR_DATA(IP5_31_30, QSTH_QHS),
+ PINMUX_IPSR_DATA(IP5_31_30, CC50_STATE27),
+
+ /* IPSR6 */
+ PINMUX_IPSR_DATA(IP6_1_0, DU0_EXVSYNC_DU0_VSYNC),
+ PINMUX_IPSR_DATA(IP6_1_0, QSTB_QHE),
+ PINMUX_IPSR_DATA(IP6_1_0, CC50_STATE28),
+ PINMUX_IPSR_DATA(IP6_3_2, DU0_EXODDF_DU0_ODDF_DISP_CDE),
+ PINMUX_IPSR_DATA(IP6_3_2, QCPV_QDE),
+ PINMUX_IPSR_DATA(IP6_3_2, CC50_STATE29),
+ PINMUX_IPSR_DATA(IP6_5_4, DU0_DISP),
+ PINMUX_IPSR_DATA(IP6_5_4, QPOLA),
+ PINMUX_IPSR_DATA(IP6_5_4, CC50_STATE30),
+ PINMUX_IPSR_DATA(IP6_7_6, DU0_CDE),
+ PINMUX_IPSR_DATA(IP6_7_6, QPOLB),
+ PINMUX_IPSR_DATA(IP6_7_6, CC50_STATE31),
+ PINMUX_IPSR_DATA(IP6_8, VI0_CLK),
+ PINMUX_IPSR_DATA(IP6_8, AVB_RX_CLK),
+ PINMUX_IPSR_DATA(IP6_9, VI0_DATA0_VI0_B0),
+ PINMUX_IPSR_DATA(IP6_9, AVB_RX_DV),
+ PINMUX_IPSR_DATA(IP6_10, VI0_DATA1_VI0_B1),
+ PINMUX_IPSR_DATA(IP6_10, AVB_RXD0),
+ PINMUX_IPSR_DATA(IP6_11, VI0_DATA2_VI0_B2),
+ PINMUX_IPSR_DATA(IP6_11, AVB_RXD1),
+ PINMUX_IPSR_DATA(IP6_12, VI0_DATA3_VI0_B3),
+ PINMUX_IPSR_DATA(IP6_12, AVB_RXD2),
+ PINMUX_IPSR_DATA(IP6_13, VI0_DATA4_VI0_B4),
+ PINMUX_IPSR_DATA(IP6_13, AVB_RXD3),
+ PINMUX_IPSR_DATA(IP6_14, VI0_DATA5_VI0_B5),
+ PINMUX_IPSR_DATA(IP6_14, AVB_RXD4),
+ PINMUX_IPSR_DATA(IP6_15, VI0_DATA6_VI0_B6),
+ PINMUX_IPSR_DATA(IP6_15, AVB_RXD5),
+ PINMUX_IPSR_DATA(IP6_16, VI0_DATA7_VI0_B7),
+ PINMUX_IPSR_DATA(IP6_16, AVB_RXD6),
+ PINMUX_IPSR_DATA(IP6_19_17, VI0_CLKENB),
+ PINMUX_IPSR_MODSEL_DATA(IP6_19_17, I2C3_SCL, SEL_I2C03_0),
+ PINMUX_IPSR_MODSEL_DATA(IP6_19_17, SCIFA5_RXD_C, SEL_SCIFA5_2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_19_17, IETX_C, SEL_IEB_2),
+ PINMUX_IPSR_DATA(IP6_19_17, AVB_RXD7),
+ PINMUX_IPSR_DATA(IP6_22_20, VI0_FIELD),
+ PINMUX_IPSR_MODSEL_DATA(IP6_22_20, I2C3_SDA, SEL_I2C03_0),
+ PINMUX_IPSR_MODSEL_DATA(IP6_22_20, SCIFA5_TXD_C, SEL_SCIFA5_2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_22_20, IECLK_C, SEL_IEB_2),
+ PINMUX_IPSR_DATA(IP6_22_20, AVB_RX_ER),
+ PINMUX_IPSR_DATA(IP6_25_23, VI0_HSYNC_N),
+ PINMUX_IPSR_MODSEL_DATA(IP6_25_23, SCIF0_RXD_B, SEL_SCIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_25_23, I2C0_SCL_C, SEL_I2C00_2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_25_23, IERX_C, SEL_IEB_2),
+ PINMUX_IPSR_DATA(IP6_25_23, AVB_COL),
+ PINMUX_IPSR_DATA(IP6_28_26, VI0_VSYNC_N),
+ PINMUX_IPSR_MODSEL_DATA(IP6_28_26, SCIF0_TXD_B, SEL_SCIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_28_26, I2C0_SDA_C, SEL_I2C00_2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_28_26, AUDIO_CLKOUT_B, SEL_ADG_1),
+ PINMUX_IPSR_DATA(IP6_28_26, AVB_TX_EN),
+ PINMUX_IPSR_MODSEL_DATA(IP6_31_29, ETH_MDIO, SEL_ETH_0),
+ PINMUX_IPSR_DATA(IP6_31_29, VI0_G0),
+ PINMUX_IPSR_MODSEL_DATA(IP6_31_29, MSIOF2_RXD_B, SEL_MSI2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_31_29, IIC0_SCL_D, SEL_IIC00_3),
+ PINMUX_IPSR_DATA(IP6_31_29, AVB_TX_CLK),
+ PINMUX_IPSR_MODSEL_DATA(IP6_31_29, ADIDATA, SEL_RAD_0),
+ PINMUX_IPSR_MODSEL_DATA(IP6_31_29, AD_DI, SEL_ADI_0),
+
+ /* IPSR7 */
+ PINMUX_IPSR_MODSEL_DATA(IP7_2_0, ETH_CRS_DV, SEL_ETH_0),
+ PINMUX_IPSR_DATA(IP7_2_0, VI0_G1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_2_0, MSIOF2_TXD_B, SEL_MSI2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_2_0, IIC0_SDA_D, SEL_IIC00_3),
+ PINMUX_IPSR_DATA(IP7_2_0, AVB_TXD0),
+ PINMUX_IPSR_MODSEL_DATA(IP7_2_0, ADICS_SAMP, SEL_RAD_0),
+ PINMUX_IPSR_MODSEL_DATA(IP7_2_0, AD_DO, SEL_ADI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP7_5_3, ETH_RX_ER, SEL_ETH_0),
+ PINMUX_IPSR_DATA(IP7_5_3, VI0_G2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_5_3, MSIOF2_SCK_B, SEL_MSI2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_5_3, CAN0_RX_B, SEL_CAN0_1),
+ PINMUX_IPSR_DATA(IP7_5_3, AVB_TXD1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_5_3, ADICLK, SEL_RAD_0),
+ PINMUX_IPSR_MODSEL_DATA(IP7_5_3, AD_CLK, SEL_ADI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP7_8_6, ETH_RXD0, SEL_ETH_0),
+ PINMUX_IPSR_DATA(IP7_8_6, VI0_G3),
+ PINMUX_IPSR_MODSEL_DATA(IP7_8_6, MSIOF2_SYNC_B, SEL_MSI2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_8_6, CAN0_TX_B, SEL_CAN0_1),
+ PINMUX_IPSR_DATA(IP7_8_6, AVB_TXD2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_8_6, ADICHS0, SEL_RAD_0),
+ PINMUX_IPSR_MODSEL_DATA(IP7_8_6, AD_NCS_N, SEL_ADI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP7_11_9, ETH_RXD1, SEL_ETH_0),
+ PINMUX_IPSR_DATA(IP7_11_9, VI0_G4),
+ PINMUX_IPSR_MODSEL_DATA(IP7_11_9, MSIOF2_SS1_B, SEL_MSI2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_11_9, SCIF4_RXD_D, SEL_SCIF4_3),
+ PINMUX_IPSR_DATA(IP7_11_9, AVB_TXD3),
+ PINMUX_IPSR_MODSEL_DATA(IP7_11_9, ADICHS1, SEL_RAD_0),
+ PINMUX_IPSR_MODSEL_DATA(IP7_14_12, ETH_LINK, SEL_ETH_0),
+ PINMUX_IPSR_DATA(IP7_14_12, VI0_G5),
+ PINMUX_IPSR_MODSEL_DATA(IP7_14_12, MSIOF2_SS2_B, SEL_MSI2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_14_12, SCIF4_TXD_D, SEL_SCIF4_3),
+ PINMUX_IPSR_DATA(IP7_14_12, AVB_TXD4),
+ PINMUX_IPSR_MODSEL_DATA(IP7_14_12, ADICHS2, SEL_RAD_0),
+ PINMUX_IPSR_MODSEL_DATA(IP7_17_15, ETH_REFCLK, SEL_ETH_0),
+ PINMUX_IPSR_DATA(IP7_17_15, VI0_G6),
+ PINMUX_IPSR_MODSEL_DATA(IP7_17_15, SCIF2_SCK_C, SEL_SCIF2_2),
+ PINMUX_IPSR_DATA(IP7_17_15, AVB_TXD5),
+ PINMUX_IPSR_MODSEL_DATA(IP7_17_15, SSI_SCK5_B, SEL_SSI5_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_20_18, ETH_TXD1, SEL_ETH_0),
+ PINMUX_IPSR_DATA(IP7_20_18, VI0_G7),
+ PINMUX_IPSR_MODSEL_DATA(IP7_20_18, SCIF2_RXD_C, SEL_SCIF2_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_20_18, IIC1_SCL_D, SEL_IIC01_3),
+ PINMUX_IPSR_DATA(IP7_20_18, AVB_TXD6),
+ PINMUX_IPSR_MODSEL_DATA(IP7_20_18, SSI_WS5_B, SEL_SSI5_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_23_21, ETH_TX_EN, SEL_ETH_0),
+ PINMUX_IPSR_DATA(IP7_23_21, VI0_R0),
+ PINMUX_IPSR_MODSEL_DATA(IP7_23_21, SCIF2_TXD_C, SEL_SCIF2_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_23_21, IIC1_SDA_D, SEL_IIC01_3),
+ PINMUX_IPSR_DATA(IP7_23_21, AVB_TXD7),
+ PINMUX_IPSR_MODSEL_DATA(IP7_23_21, SSI_SDATA5_B, SEL_SSI5_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_26_24, ETH_MAGIC, SEL_ETH_0),
+ PINMUX_IPSR_DATA(IP7_26_24, VI0_R1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_26_24, SCIF3_SCK_B, SEL_SCIF3_1),
+ PINMUX_IPSR_DATA(IP7_26_24, AVB_TX_ER),
+ PINMUX_IPSR_MODSEL_DATA(IP7_26_24, SSI_SCK6_B, SEL_SSI6_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_29_27, ETH_TXD0, SEL_ETH_0),
+ PINMUX_IPSR_DATA(IP7_29_27, VI0_R2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_29_27, SCIF3_RXD_B, SEL_SCIF3_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_29_27, I2C4_SCL_E, SEL_I2C04_4),
+ PINMUX_IPSR_DATA(IP7_29_27, AVB_GTX_CLK),
+ PINMUX_IPSR_MODSEL_DATA(IP7_29_27, SSI_WS6_B, SEL_SSI6_1),
+ PINMUX_IPSR_DATA(IP7_31, DREQ0_N),
+ PINMUX_IPSR_DATA(IP7_31, SCIFB1_RXD),
+
+ /* IPSR8 */
+ PINMUX_IPSR_MODSEL_DATA(IP8_2_0, ETH_MDC, SEL_ETH_0),
+ PINMUX_IPSR_DATA(IP8_2_0, VI0_R3),
+ PINMUX_IPSR_MODSEL_DATA(IP8_2_0, SCIF3_TXD_B, SEL_SCIF3_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_2_0, I2C4_SDA_E, SEL_I2C04_4),
+ PINMUX_IPSR_DATA(IP8_2_0, AVB_MDC),
+ PINMUX_IPSR_MODSEL_DATA(IP8_2_0, SSI_SDATA6_B, SEL_SSI6_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_5_3, HSCIF0_HRX, SEL_HSCIF0_0),
+ PINMUX_IPSR_DATA(IP8_5_3, VI0_R4),
+ PINMUX_IPSR_MODSEL_DATA(IP8_5_3, I2C1_SCL_C, SEL_I2C01_2),
+ PINMUX_IPSR_MODSEL_DATA(IP8_5_3, AUDIO_CLKA_B, SEL_ADG_1),
+ PINMUX_IPSR_DATA(IP8_5_3, AVB_MDIO),
+ PINMUX_IPSR_MODSEL_DATA(IP8_5_3, SSI_SCK78_B, SEL_SSI7_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_8_6, HSCIF0_HTX, SEL_HSCIF0_0),
+ PINMUX_IPSR_DATA(IP8_8_6, VI0_R5),
+ PINMUX_IPSR_MODSEL_DATA(IP8_8_6, I2C1_SDA_C, SEL_I2C01_2),
+ PINMUX_IPSR_MODSEL_DATA(IP8_8_6, AUDIO_CLKB_B, SEL_ADG_1),
+ PINMUX_IPSR_DATA(IP8_5_3, AVB_LINK),
+ PINMUX_IPSR_MODSEL_DATA(IP8_8_6, SSI_WS78_B, SEL_SSI7_1),
+ PINMUX_IPSR_DATA(IP8_11_9, HSCIF0_HCTS_N),
+ PINMUX_IPSR_DATA(IP8_11_9, VI0_R6),
+ PINMUX_IPSR_MODSEL_DATA(IP8_11_9, SCIF0_RXD_D, SEL_SCIF0_3),
+ PINMUX_IPSR_MODSEL_DATA(IP8_11_9, I2C0_SCL_E, SEL_I2C00_4),
+ PINMUX_IPSR_DATA(IP8_11_9, AVB_MAGIC),
+ PINMUX_IPSR_MODSEL_DATA(IP8_11_9, SSI_SDATA7_B, SEL_SSI7_1),
+ PINMUX_IPSR_DATA(IP8_14_12, HSCIF0_HRTS_N),
+ PINMUX_IPSR_DATA(IP8_14_12, VI0_R7),
+ PINMUX_IPSR_MODSEL_DATA(IP8_14_12, SCIF0_TXD_D, SEL_SCIF0_3),
+ PINMUX_IPSR_MODSEL_DATA(IP8_14_12, I2C0_SDA_E, SEL_I2C00_4),
+ PINMUX_IPSR_DATA(IP8_14_12, AVB_PHY_INT),
+ PINMUX_IPSR_MODSEL_DATA(IP8_14_12, SSI_SDATA8_B, SEL_SSI8_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_16_15, HSCIF0_HSCK, SEL_HSCIF0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_16_15, SCIF_CLK_B, SEL_SCIF0_1),
+ PINMUX_IPSR_DATA(IP8_16_15, AVB_CRS),
+ PINMUX_IPSR_MODSEL_DATA(IP8_16_15, AUDIO_CLKC_B, SEL_ADG_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_19_17, I2C0_SCL, SEL_I2C00_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_19_17, SCIF0_RXD_C, SEL_SCIF0_2),
+ PINMUX_IPSR_DATA(IP8_19_17, PWM5),
+ PINMUX_IPSR_MODSEL_DATA(IP8_19_17, TCLK1_B, SEL_TMU_1),
+ PINMUX_IPSR_DATA(IP8_19_17, AVB_GTXREFCLK),
+ PINMUX_IPSR_MODSEL_DATA(IP8_19_17, CAN1_RX_D, SEL_CAN1_3),
+ PINMUX_IPSR_DATA(IP8_19_17, TPUTO0_B),
+ PINMUX_IPSR_MODSEL_DATA(IP8_22_20, I2C0_SDA, SEL_I2C00_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_22_20, SCIF0_TXD_C, SEL_SCIF0_2),
+ PINMUX_IPSR_DATA(IP8_22_20, TPUTO0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_22_20, CAN_CLK, SEL_CAN_0),
+ PINMUX_IPSR_DATA(IP8_22_20, DVC_MUTE),
+ PINMUX_IPSR_MODSEL_DATA(IP8_22_20, CAN1_TX_D, SEL_CAN1_3),
+ PINMUX_IPSR_MODSEL_DATA(IP8_25_23, I2C1_SCL, SEL_I2C01_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_25_23, SCIF4_RXD, SEL_SCIF4_0),
+ PINMUX_IPSR_DATA(IP8_25_23, PWM5_B),
+ PINMUX_IPSR_DATA(IP8_25_23, DU1_DR0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_25_23, RIF1_SYNC_B, SEL_DR2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_25_23, TS_SDATA_D, SEL_TSIF0_3),
+ PINMUX_IPSR_DATA(IP8_25_23, TPUTO1_B),
+ PINMUX_IPSR_MODSEL_DATA(IP8_28_26, I2C1_SDA, SEL_I2C01_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_28_26, SCIF4_TXD, SEL_SCIF4_0),
+ PINMUX_IPSR_DATA(IP8_28_26, IRQ5),
+ PINMUX_IPSR_DATA(IP8_28_26, DU1_DR1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_28_26, RIF1_CLK_B, SEL_DR2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_28_26, TS_SCK_D, SEL_TSIF0_3),
+ PINMUX_IPSR_MODSEL_DATA(IP8_28_26, BPFCLK_C, SEL_DARC_2),
+ PINMUX_IPSR_DATA(IP8_31_29, MSIOF0_RXD),
+ PINMUX_IPSR_MODSEL_DATA(IP8_31_29, SCIF5_RXD, SEL_SCIF5_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_31_29, I2C2_SCL_C, SEL_I2C02_2),
+ PINMUX_IPSR_DATA(IP8_31_29, DU1_DR2),
+ PINMUX_IPSR_MODSEL_DATA(IP8_31_29, RIF1_D0_B, SEL_DR2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_31_29, TS_SDEN_D, SEL_TSIF0_3),
+ PINMUX_IPSR_MODSEL_DATA(IP8_31_29, FMCLK_C, SEL_DARC_2),
+ PINMUX_IPSR_MODSEL_DATA(IP8_31_29, RDS_CLK, SEL_RDS_0),
+
+ /* IPSR9 */
+ PINMUX_IPSR_DATA(IP9_2_0, MSIOF0_TXD),
+ PINMUX_IPSR_MODSEL_DATA(IP9_2_0, SCIF5_TXD, SEL_SCIF5_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_2_0, I2C2_SDA_C, SEL_I2C02_2),
+ PINMUX_IPSR_DATA(IP9_2_0, DU1_DR3),
+ PINMUX_IPSR_MODSEL_DATA(IP9_2_0, RIF1_D1_B, SEL_DR3_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_2_0, TS_SPSYNC_D, SEL_TSIF0_3),
+ PINMUX_IPSR_MODSEL_DATA(IP9_2_0, FMIN_C, SEL_DARC_2),
+ PINMUX_IPSR_MODSEL_DATA(IP9_2_0, RDS_DATA, SEL_RDS_0),
+ PINMUX_IPSR_DATA(IP9_5_3, MSIOF0_SCK),
+ PINMUX_IPSR_DATA(IP9_5_3, IRQ0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_5_3, TS_SDATA, SEL_TSIF0_0),
+ PINMUX_IPSR_DATA(IP9_5_3, DU1_DR4),
+ PINMUX_IPSR_MODSEL_DATA(IP9_5_3, RIF1_SYNC, SEL_DR2_0),
+ PINMUX_IPSR_DATA(IP9_5_3, TPUTO1_C),
+ PINMUX_IPSR_DATA(IP9_8_6, MSIOF0_SYNC),
+ PINMUX_IPSR_DATA(IP9_8_6, PWM1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_8_6, TS_SCK, SEL_TSIF0_0),
+ PINMUX_IPSR_DATA(IP9_8_6, DU1_DR5),
+ PINMUX_IPSR_MODSEL_DATA(IP9_8_6, RIF1_CLK, SEL_DR2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_8_6, BPFCLK_B, SEL_DARC_1),
+ PINMUX_IPSR_DATA(IP9_11_9, MSIOF0_SS1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_11_9, SCIFA0_RXD, SEL_SCIFA0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_11_9, TS_SDEN, SEL_TSIF0_0),
+ PINMUX_IPSR_DATA(IP9_11_9, DU1_DR6),
+ PINMUX_IPSR_MODSEL_DATA(IP9_11_9, RIF1_D0, SEL_DR2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_11_9, FMCLK_B, SEL_DARC_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_11_9, RDS_CLK_B, SEL_RDS_1),
+ PINMUX_IPSR_DATA(IP9_14_12, MSIOF0_SS2),
+ PINMUX_IPSR_MODSEL_DATA(IP9_14_12, SCIFA0_TXD, SEL_SCIFA0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_14_12, TS_SPSYNC, SEL_TSIF0_0),
+ PINMUX_IPSR_DATA(IP9_14_12, DU1_DR7),
+ PINMUX_IPSR_MODSEL_DATA(IP9_14_12, RIF1_D1, SEL_DR3_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_14_12, FMIN_B, SEL_DARC_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_14_12, RDS_DATA_B, SEL_RDS_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_16_15, HSCIF1_HRX, SEL_HSCIF1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_16_15, I2C4_SCL, SEL_I2C04_0),
+ PINMUX_IPSR_DATA(IP9_16_15, PWM6),
+ PINMUX_IPSR_DATA(IP9_16_15, DU1_DG0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_18_17, HSCIF1_HTX, SEL_HSCIF1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_18_17, I2C4_SDA, SEL_I2C04_0),
+ PINMUX_IPSR_DATA(IP9_18_17, TPUTO1),
+ PINMUX_IPSR_DATA(IP9_18_17, DU1_DG1),
+ PINMUX_IPSR_DATA(IP9_21_19, HSCIF1_HSCK),
+ PINMUX_IPSR_DATA(IP9_21_19, PWM2),
+ PINMUX_IPSR_MODSEL_DATA(IP9_21_19, IETX, SEL_IEB_0),
+ PINMUX_IPSR_DATA(IP9_21_19, DU1_DG2),
+ PINMUX_IPSR_MODSEL_DATA(IP9_21_19, REMOCON_B, SEL_RCN_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_21_19, SPEEDIN_B, SEL_RSP_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_21_19, VSP_B, SEL_SPDM_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_24_22, HSCIF1_HCTS_N, SEL_HSCIF1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_24_22, SCIFA4_RXD, SEL_SCIFA4_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_24_22, IECLK, SEL_IEB_0),
+ PINMUX_IPSR_DATA(IP9_24_22, DU1_DG3),
+ PINMUX_IPSR_MODSEL_DATA(IP9_24_22, SSI_SCK1_B, SEL_SSI1_1),
+ PINMUX_IPSR_DATA(IP9_24_22, CAN_DEBUG_HW_TRIGGER),
+ PINMUX_IPSR_DATA(IP9_24_22, CC50_STATE32),
+ PINMUX_IPSR_MODSEL_DATA(IP9_27_25, HSCIF1_HRTS_N, SEL_HSCIF1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_27_25, SCIFA4_TXD, SEL_SCIFA4_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_27_25, IERX, SEL_IEB_0),
+ PINMUX_IPSR_DATA(IP9_27_25, DU1_DG4),
+ PINMUX_IPSR_MODSEL_DATA(IP9_27_25, SSI_WS1_B, SEL_SSI1_1),
+ PINMUX_IPSR_DATA(IP9_27_25, CAN_STEP0),
+ PINMUX_IPSR_DATA(IP9_27_25, CC50_STATE33),
+ PINMUX_IPSR_MODSEL_DATA(IP9_30_28, SCIF1_SCK, SEL_SCIF1_0),
+ PINMUX_IPSR_DATA(IP9_30_28, PWM3),
+ PINMUX_IPSR_MODSEL_DATA(IP9_30_28, TCLK2, SEL_TMU_0),
+ PINMUX_IPSR_DATA(IP9_30_28, DU1_DG5),
+ PINMUX_IPSR_MODSEL_DATA(IP9_30_28, SSI_SDATA1_B, SEL_SSI1_1),
+ PINMUX_IPSR_DATA(IP9_30_28, CAN_TXCLK),
+ PINMUX_IPSR_DATA(IP9_30_28, CC50_STATE34),
+
+ /* IPSR10 */
+ PINMUX_IPSR_MODSEL_DATA(IP10_2_0, SCIF1_RXD, SEL_SCIF1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_2_0, IIC0_SCL, SEL_IIC00_0),
+ PINMUX_IPSR_DATA(IP10_2_0, DU1_DG6),
+ PINMUX_IPSR_MODSEL_DATA(IP10_2_0, SSI_SCK2_B, SEL_SSI2_1),
+ PINMUX_IPSR_DATA(IP10_2_0, CAN_DEBUGOUT0),
+ PINMUX_IPSR_DATA(IP10_2_0, CC50_STATE35),
+ PINMUX_IPSR_MODSEL_DATA(IP10_5_3, SCIF1_TXD, SEL_SCIF1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_5_3, IIC0_SDA, SEL_IIC00_0),
+ PINMUX_IPSR_DATA(IP10_5_3, DU1_DG7),
+ PINMUX_IPSR_MODSEL_DATA(IP10_5_3, SSI_WS2_B, SEL_SSI2_1),
+ PINMUX_IPSR_DATA(IP10_5_3, CAN_DEBUGOUT1),
+ PINMUX_IPSR_DATA(IP10_5_3, CC50_STATE36),
+ PINMUX_IPSR_MODSEL_DATA(IP10_8_6, SCIF2_RXD, SEL_SCIF2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_8_6, IIC1_SCL, SEL_IIC01_0),
+ PINMUX_IPSR_DATA(IP10_8_6, DU1_DB0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_8_6, SSI_SDATA2_B, SEL_SSI2_1),
+ PINMUX_IPSR_DATA(IP10_8_6, USB0_EXTLP),
+ PINMUX_IPSR_DATA(IP10_8_6, CAN_DEBUGOUT2),
+ PINMUX_IPSR_DATA(IP10_8_6, CC50_STATE37),
+ PINMUX_IPSR_MODSEL_DATA(IP10_11_9, SCIF2_TXD, SEL_SCIF2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_11_9, IIC1_SDA, SEL_IIC01_0),
+ PINMUX_IPSR_DATA(IP10_11_9, DU1_DB1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_11_9, SSI_SCK9_B, SEL_SSI9_1),
+ PINMUX_IPSR_DATA(IP10_11_9, USB0_OVC1),
+ PINMUX_IPSR_DATA(IP10_11_9, CAN_DEBUGOUT3),
+ PINMUX_IPSR_DATA(IP10_11_9, CC50_STATE38),
+ PINMUX_IPSR_MODSEL_DATA(IP10_14_12, SCIF2_SCK, SEL_SCIF2_0),
+ PINMUX_IPSR_DATA(IP10_14_12, IRQ1),
+ PINMUX_IPSR_DATA(IP10_14_12, DU1_DB2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_14_12, SSI_WS9_B, SEL_SSI9_1),
+ PINMUX_IPSR_DATA(IP10_14_12, USB0_IDIN),
+ PINMUX_IPSR_DATA(IP10_14_12, CAN_DEBUGOUT4),
+ PINMUX_IPSR_DATA(IP10_14_12, CC50_STATE39),
+ PINMUX_IPSR_MODSEL_DATA(IP10_17_15, SCIF3_SCK, SEL_SCIF3_0),
+ PINMUX_IPSR_DATA(IP10_17_15, IRQ2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_17_15, BPFCLK_D, SEL_DARC_3),
+ PINMUX_IPSR_DATA(IP10_17_15, DU1_DB3),
+ PINMUX_IPSR_MODSEL_DATA(IP10_17_15, SSI_SDATA9_B, SEL_SSI9_1),
+ PINMUX_IPSR_DATA(IP10_17_15, TANS2),
+ PINMUX_IPSR_DATA(IP10_17_15, CAN_DEBUGOUT5),
+ PINMUX_IPSR_DATA(IP10_17_15, CC50_OSCOUT),
+ PINMUX_IPSR_MODSEL_DATA(IP10_20_18, SCIF3_RXD, SEL_SCIF3_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_20_18, I2C1_SCL_E, SEL_I2C01_4),
+ PINMUX_IPSR_MODSEL_DATA(IP10_20_18, FMCLK_D, SEL_DARC_3),
+ PINMUX_IPSR_DATA(IP10_20_18, DU1_DB4),
+ PINMUX_IPSR_MODSEL_DATA(IP10_20_18, AUDIO_CLKA_C, SEL_ADG_2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_20_18, SSI_SCK4_B, SEL_SSI4_1),
+ PINMUX_IPSR_DATA(IP10_20_18, CAN_DEBUGOUT6),
+ PINMUX_IPSR_MODSEL_DATA(IP10_20_18, RDS_CLK_C, SEL_RDS_2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_23_21, SCIF3_TXD, SEL_SCIF3_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_23_21, I2C1_SDA_E, SEL_I2C01_4),
+ PINMUX_IPSR_MODSEL_DATA(IP10_23_21, FMIN_D, SEL_DARC_3),
+ PINMUX_IPSR_DATA(IP10_23_21, DU1_DB5),
+ PINMUX_IPSR_MODSEL_DATA(IP10_23_21, AUDIO_CLKB_C, SEL_ADG_2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_23_21, SSI_WS4_B, SEL_SSI4_1),
+ PINMUX_IPSR_DATA(IP10_23_21, CAN_DEBUGOUT7),
+ PINMUX_IPSR_MODSEL_DATA(IP10_23_21, RDS_DATA_C, SEL_RDS_2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_26_24, I2C2_SCL, SEL_I2C02_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_26_24, SCIFA5_RXD, SEL_SCIFA5_0),
+ PINMUX_IPSR_DATA(IP10_26_24, DU1_DB6),
+ PINMUX_IPSR_MODSEL_DATA(IP10_26_24, AUDIO_CLKC_C, SEL_ADG_2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_26_24, SSI_SDATA4_B, SEL_SSI4_1),
+ PINMUX_IPSR_DATA(IP10_26_24, CAN_DEBUGOUT8),
+ PINMUX_IPSR_MODSEL_DATA(IP10_29_27, I2C2_SDA, SEL_I2C02_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_29_27, SCIFA5_TXD, SEL_SCIFA5_0),
+ PINMUX_IPSR_DATA(IP10_29_27, DU1_DB7),
+ PINMUX_IPSR_MODSEL_DATA(IP10_29_27, AUDIO_CLKOUT_C, SEL_ADG_2),
+ PINMUX_IPSR_DATA(IP10_29_27, CAN_DEBUGOUT9),
+ PINMUX_IPSR_MODSEL_DATA(IP10_31_30, SSI_SCK5, SEL_SSI5_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_31_30, SCIFA3_SCK, SEL_SCIFA3_0),
+ PINMUX_IPSR_DATA(IP10_31_30, DU1_DOTCLKIN),
+ PINMUX_IPSR_DATA(IP10_31_30, CAN_DEBUGOUT10),
+
+ /* IPSR11 */
+ PINMUX_IPSR_MODSEL_DATA(IP11_2_0, SSI_WS5, SEL_SSI5_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_2_0, SCIFA3_RXD, SEL_SCIFA3_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_2_0, I2C3_SCL_C, SEL_I2C03_2),
+ PINMUX_IPSR_DATA(IP11_2_0, DU1_DOTCLKOUT0),
+ PINMUX_IPSR_DATA(IP11_2_0, CAN_DEBUGOUT11),
+ PINMUX_IPSR_MODSEL_DATA(IP11_5_3, SSI_SDATA5, SEL_SSI5_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_5_3, SCIFA3_TXD, SEL_SCIFA3_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_5_3, I2C3_SDA_C, SEL_I2C03_2),
+ PINMUX_IPSR_DATA(IP11_5_3, DU1_DOTCLKOUT1),
+ PINMUX_IPSR_DATA(IP11_5_3, CAN_DEBUGOUT12),
+ PINMUX_IPSR_MODSEL_DATA(IP11_7_6, SSI_SCK6, SEL_SSI6_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_7_6, SCIFA1_SCK_B, SEL_SCIFA1_1),
+ PINMUX_IPSR_DATA(IP11_7_6, DU1_EXHSYNC_DU1_HSYNC),
+ PINMUX_IPSR_DATA(IP11_7_6, CAN_DEBUGOUT13),
+ PINMUX_IPSR_MODSEL_DATA(IP11_10_8, SSI_WS6, SEL_SSI6_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_10_8, SCIFA1_RXD_B, SEL_SCIFA1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_10_8, I2C4_SCL_C, SEL_I2C04_2),
+ PINMUX_IPSR_DATA(IP11_10_8, DU1_EXVSYNC_DU1_VSYNC),
+ PINMUX_IPSR_DATA(IP11_10_8, CAN_DEBUGOUT14),
+ PINMUX_IPSR_MODSEL_DATA(IP11_13_11, SSI_SDATA6, SEL_SSI6_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_13_11, SCIFA1_TXD_B, SEL_SCIFA1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_13_11, I2C4_SDA_C, SEL_I2C04_2),
+ PINMUX_IPSR_DATA(IP11_13_11, DU1_EXODDF_DU1_ODDF_DISP_CDE),
+ PINMUX_IPSR_DATA(IP11_13_11, CAN_DEBUGOUT15),
+ PINMUX_IPSR_MODSEL_DATA(IP11_15_14, SSI_SCK78, SEL_SSI7_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_15_14, SCIFA2_SCK_B, SEL_SCIFA2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_15_14, IIC0_SDA_C, SEL_IIC00_2),
+ PINMUX_IPSR_DATA(IP11_15_14, DU1_DISP),
+ PINMUX_IPSR_MODSEL_DATA(IP11_17_16, SSI_WS78, SEL_SSI7_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_17_16, SCIFA2_RXD_B, SEL_SCIFA2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_17_16, IIC0_SCL_C, SEL_IIC00_2),
+ PINMUX_IPSR_DATA(IP11_17_16, DU1_CDE),
+ PINMUX_IPSR_MODSEL_DATA(IP11_20_18, SSI_SDATA7, SEL_SSI7_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_20_18, SCIFA2_TXD_B, SEL_SCIFA2_1),
+ PINMUX_IPSR_DATA(IP11_20_18, IRQ8),
+ PINMUX_IPSR_MODSEL_DATA(IP11_20_18, AUDIO_CLKA_D, SEL_ADG_3),
+ PINMUX_IPSR_MODSEL_DATA(IP11_20_18, CAN_CLK_D, SEL_CAN_3),
+ PINMUX_IPSR_DATA(IP11_20_18, PCMOE_N),
+ PINMUX_IPSR_DATA(IP11_23_21, SSI_SCK0129),
+ PINMUX_IPSR_MODSEL_DATA(IP11_23_21, MSIOF1_RXD_B, SEL_MSI1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_23_21, SCIF5_RXD_D, SEL_SCIF5_3),
+ PINMUX_IPSR_MODSEL_DATA(IP11_23_21, ADIDATA_B, SEL_RAD_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_23_21, AD_DI_B, SEL_ADI_1),
+ PINMUX_IPSR_DATA(IP11_23_21, PCMWE_N),
+ PINMUX_IPSR_DATA(IP11_26_24, SSI_WS0129),
+ PINMUX_IPSR_MODSEL_DATA(IP11_26_24, MSIOF1_TXD_B, SEL_MSI1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_26_24, SCIF5_TXD_D, SEL_SCIF5_3),
+ PINMUX_IPSR_MODSEL_DATA(IP11_26_24, ADICS_SAMP_B, SEL_RAD_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_26_24, AD_DO_B, SEL_ADI_1),
+ PINMUX_IPSR_DATA(IP11_29_27, SSI_SDATA0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_29_27, MSIOF1_SCK_B, SEL_MSI1_1),
+ PINMUX_IPSR_DATA(IP11_29_27, PWM0_B),
+ PINMUX_IPSR_MODSEL_DATA(IP11_29_27, ADICLK_B, SEL_RAD_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_29_27, AD_CLK_B, SEL_ADI_1),
+
+ /* IPSR12 */
+ PINMUX_IPSR_DATA(IP12_2_0, SSI_SCK34),
+ PINMUX_IPSR_MODSEL_DATA(IP12_2_0, MSIOF1_SYNC_B, SEL_MSI1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP12_2_0, SCIFA1_SCK_C, SEL_SCIFA1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP12_2_0, ADICHS0_B, SEL_RAD_1),
+ PINMUX_IPSR_MODSEL_DATA(IP12_2_0, AD_NCS_N_B, SEL_ADI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP12_2_0, DREQ1_N_B, SEL_LBS_1),
+ PINMUX_IPSR_DATA(IP12_5_3, SSI_WS34),
+ PINMUX_IPSR_MODSEL_DATA(IP12_5_3, MSIOF1_SS1_B, SEL_MSI1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP12_5_3, SCIFA1_RXD_C, SEL_SCIFA1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP12_5_3, ADICHS1_B, SEL_RAD_1),
+ PINMUX_IPSR_MODSEL_DATA(IP12_5_3, CAN1_RX_C, SEL_CAN1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP12_5_3, DACK1_B, SEL_LBS_1),
+ PINMUX_IPSR_DATA(IP12_8_6, SSI_SDATA3),
+ PINMUX_IPSR_MODSEL_DATA(IP12_8_6, MSIOF1_SS2_B, SEL_MSI1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP12_8_6, SCIFA1_TXD_C, SEL_SCIFA1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP12_8_6, ADICHS2_B, SEL_RAD_1),
+ PINMUX_IPSR_MODSEL_DATA(IP12_8_6, CAN1_TX_C, SEL_CAN1_2),
+ PINMUX_IPSR_DATA(IP12_8_6, DREQ2_N),
+ PINMUX_IPSR_MODSEL_DATA(IP12_10_9, SSI_SCK4, SEL_SSI4_0),
+ PINMUX_IPSR_DATA(IP12_10_9, MLB_CLK),
+ PINMUX_IPSR_MODSEL_DATA(IP12_10_9, IETX_B, SEL_IEB_1),
+ PINMUX_IPSR_DATA(IP12_10_9, IRD_TX),
+ PINMUX_IPSR_MODSEL_DATA(IP12_12_11, SSI_WS4, SEL_SSI4_0),
+ PINMUX_IPSR_DATA(IP12_12_11, MLB_SIG),
+ PINMUX_IPSR_MODSEL_DATA(IP12_12_11, IECLK_B, SEL_IEB_1),
+ PINMUX_IPSR_DATA(IP12_12_11, IRD_RX),
+ PINMUX_IPSR_MODSEL_DATA(IP12_14_13, SSI_SDATA4, SEL_SSI4_0),
+ PINMUX_IPSR_DATA(IP12_14_13, MLB_DAT),
+ PINMUX_IPSR_MODSEL_DATA(IP12_14_13, IERX_B, SEL_IEB_1),
+ PINMUX_IPSR_DATA(IP12_14_13, IRD_SCK),
+ PINMUX_IPSR_MODSEL_DATA(IP12_17_15, SSI_SDATA8, SEL_SSI8_0),
+ PINMUX_IPSR_MODSEL_DATA(IP12_17_15, SCIF1_SCK_B, SEL_SCIF1_1),
+ PINMUX_IPSR_DATA(IP12_17_15, PWM1_B),
+ PINMUX_IPSR_DATA(IP12_17_15, IRQ9),
+ PINMUX_IPSR_MODSEL_DATA(IP12_17_15, REMOCON, SEL_RCN_0),
+ PINMUX_IPSR_DATA(IP12_17_15, DACK2),
+ PINMUX_IPSR_MODSEL_DATA(IP12_17_15, ETH_MDIO_B, SEL_ETH_1),
+ PINMUX_IPSR_MODSEL_DATA(IP12_20_18, SSI_SCK1, SEL_SSI1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP12_20_18, SCIF1_RXD_B, SEL_SCIF1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP12_20_18, IIC1_SCL_C, SEL_IIC01_2),
+ PINMUX_IPSR_DATA(IP12_20_18, VI1_CLK),
+ PINMUX_IPSR_MODSEL_DATA(IP12_20_18, CAN0_RX_D, SEL_CAN0_3),
+ PINMUX_IPSR_MODSEL_DATA(IP12_20_18, AVB_AVTP_CAPTURE, SEL_AVB_0),
+ PINMUX_IPSR_MODSEL_DATA(IP12_20_18, ETH_CRS_DV_B, SEL_ETH_1),
+ PINMUX_IPSR_MODSEL_DATA(IP12_23_21, SSI_WS1, SEL_SSI1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP12_23_21, SCIF1_TXD_B, SEL_SCIF1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP12_23_21, IIC1_SDA_C, SEL_IIC01_2),
+ PINMUX_IPSR_DATA(IP12_23_21, VI1_DATA0),
+ PINMUX_IPSR_MODSEL_DATA(IP12_23_21, CAN0_TX_D, SEL_CAN0_3),
+ PINMUX_IPSR_MODSEL_DATA(IP12_23_21, AVB_AVTP_MATCH, SEL_AVB_0),
+ PINMUX_IPSR_MODSEL_DATA(IP12_23_21, ETH_RX_ER_B, SEL_ETH_1),
+ PINMUX_IPSR_MODSEL_DATA(IP12_26_24, SSI_SDATA1, SEL_SSI1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP12_26_24, HSCIF1_HRX_B, SEL_HSCIF1_1),
+ PINMUX_IPSR_DATA(IP12_26_24, VI1_DATA1),
+ PINMUX_IPSR_MODSEL_DATA(IP12_26_24, SDATA, SEL_FSN_0),
+ PINMUX_IPSR_DATA(IP12_26_24, ATAG0_N),
+ PINMUX_IPSR_MODSEL_DATA(IP12_26_24, ETH_RXD0_B, SEL_ETH_1),
+ PINMUX_IPSR_MODSEL_DATA(IP12_29_27, SSI_SCK2, SEL_SSI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP12_29_27, HSCIF1_HTX_B, SEL_HSCIF1_1),
+ PINMUX_IPSR_DATA(IP12_29_27, VI1_DATA2),
+ PINMUX_IPSR_MODSEL_DATA(IP12_29_27, MDATA, SEL_FSN_0),
+ PINMUX_IPSR_DATA(IP12_29_27, ATAWR0_N),
+ PINMUX_IPSR_MODSEL_DATA(IP12_29_27, ETH_RXD1_B, SEL_ETH_1),
+
+ /* IPSR13 */
+ PINMUX_IPSR_MODSEL_DATA(IP13_2_0, SSI_WS2, SEL_SSI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP13_2_0, HSCIF1_HCTS_N_B, SEL_HSCIF1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_2_0, SCIFA0_RXD_D, SEL_SCIFA0_3),
+ PINMUX_IPSR_DATA(IP13_2_0, VI1_DATA3),
+ PINMUX_IPSR_MODSEL_DATA(IP13_2_0, SCKZ, SEL_FSN_0),
+ PINMUX_IPSR_DATA(IP13_2_0, ATACS00_N),
+ PINMUX_IPSR_MODSEL_DATA(IP13_2_0, ETH_LINK_B, SEL_ETH_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_5_3, SSI_SDATA2, SEL_SSI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP13_5_3, HSCIF1_HRTS_N_B, SEL_HSCIF1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_5_3, SCIFA0_TXD_D, SEL_SCIFA0_3),
+ PINMUX_IPSR_DATA(IP13_5_3, VI1_DATA4),
+ PINMUX_IPSR_MODSEL_DATA(IP13_5_3, STM_N, SEL_FSN_0),
+ PINMUX_IPSR_DATA(IP13_5_3, ATACS10_N),
+ PINMUX_IPSR_MODSEL_DATA(IP13_5_3, ETH_REFCLK_B, SEL_ETH_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_8_6, SSI_SCK9, SEL_SSI9_0),
+ PINMUX_IPSR_MODSEL_DATA(IP13_8_6, SCIF2_SCK_B, SEL_SCIF2_1),
+ PINMUX_IPSR_DATA(IP13_8_6, PWM2_B),
+ PINMUX_IPSR_DATA(IP13_8_6, VI1_DATA5),
+ PINMUX_IPSR_MODSEL_DATA(IP13_8_6, MTS_N, SEL_FSN_0),
+ PINMUX_IPSR_DATA(IP13_8_6, EX_WAIT1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_8_6, ETH_TXD1_B, SEL_ETH_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_11_9, SSI_WS9, SEL_SSI9_0),
+ PINMUX_IPSR_MODSEL_DATA(IP13_11_9, SCIF2_RXD_B, SEL_SCIF2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_11_9, I2C3_SCL_E, SEL_I2C03_4),
+ PINMUX_IPSR_DATA(IP13_11_9, VI1_DATA6),
+ PINMUX_IPSR_DATA(IP13_11_9, ATARD0_N),
+ PINMUX_IPSR_MODSEL_DATA(IP13_11_9, ETH_TX_EN_B, SEL_ETH_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_14_12, SSI_SDATA9, SEL_SSI9_0),
+ PINMUX_IPSR_MODSEL_DATA(IP13_14_12, SCIF2_TXD_B, SEL_SCIF2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_14_12, I2C3_SDA_E, SEL_I2C03_4),
+ PINMUX_IPSR_DATA(IP13_14_12, VI1_DATA7),
+ PINMUX_IPSR_DATA(IP13_14_12, ATADIR0_N),
+ PINMUX_IPSR_MODSEL_DATA(IP13_14_12, ETH_MAGIC_B, SEL_ETH_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_17_15, AUDIO_CLKA, SEL_ADG_0),
+ PINMUX_IPSR_MODSEL_DATA(IP13_17_15, I2C0_SCL_B, SEL_I2C00_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_17_15, SCIFA4_RXD_D, SEL_SCIFA4_3),
+ PINMUX_IPSR_DATA(IP13_17_15, VI1_CLKENB),
+ PINMUX_IPSR_MODSEL_DATA(IP13_17_15, TS_SDATA_C, SEL_TSIF0_2),
+ PINMUX_IPSR_MODSEL_DATA(IP13_17_15, RIF0_SYNC_B, SEL_DR0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_17_15, ETH_TXD0_B, SEL_ETH_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_20_18, AUDIO_CLKB, SEL_ADG_0),
+ PINMUX_IPSR_MODSEL_DATA(IP13_20_18, I2C0_SDA_B, SEL_I2C00_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_20_18, SCIFA4_TXD_D, SEL_SCIFA4_3),
+ PINMUX_IPSR_DATA(IP13_20_18, VI1_FIELD),
+ PINMUX_IPSR_MODSEL_DATA(IP13_20_18, TS_SCK_C, SEL_TSIF0_2),
+ PINMUX_IPSR_MODSEL_DATA(IP13_20_18, RIF0_CLK_B, SEL_DR0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_20_18, BPFCLK_E, SEL_DARC_4),
+ PINMUX_IPSR_MODSEL_DATA(IP13_20_18, ETH_MDC_B, SEL_ETH_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_23_21, AUDIO_CLKC, SEL_ADG_0),
+ PINMUX_IPSR_MODSEL_DATA(IP13_23_21, I2C4_SCL_B, SEL_I2C04_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_23_21, SCIFA5_RXD_D, SEL_SCIFA5_3),
+ PINMUX_IPSR_DATA(IP13_23_21, VI1_HSYNC_N),
+ PINMUX_IPSR_MODSEL_DATA(IP13_23_21, TS_SDEN_C, SEL_TSIF0_2),
+ PINMUX_IPSR_MODSEL_DATA(IP13_23_21, RIF0_D0_B, SEL_DR0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_23_21, FMCLK_E, SEL_DARC_4),
+ PINMUX_IPSR_MODSEL_DATA(IP13_23_21, RDS_CLK_D, SEL_RDS_3),
+ PINMUX_IPSR_MODSEL_DATA(IP13_26_24, AUDIO_CLKOUT, SEL_ADG_0),
+ PINMUX_IPSR_MODSEL_DATA(IP13_26_24, I2C4_SDA_B, SEL_I2C04_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_26_24, SCIFA5_TXD_D, SEL_SCIFA5_3),
+ PINMUX_IPSR_DATA(IP13_26_24, VI1_VSYNC_N),
+ PINMUX_IPSR_MODSEL_DATA(IP13_26_24, TS_SPSYNC_C, SEL_TSIF0_2),
+ PINMUX_IPSR_MODSEL_DATA(IP13_26_24, RIF0_D1_B, SEL_DR1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP13_26_24, FMIN_E, SEL_DARC_4),
+ PINMUX_IPSR_MODSEL_DATA(IP13_26_24, RDS_DATA_D, SEL_RDS_3),
+};
+
+static const struct sh_pfc_pin pinmux_pins[] = {
+ PINMUX_GPIO_GP_ALL(),
+};
+
+/* - ETH -------------------------------------------------------------------- */
+static const unsigned int eth_link_pins[] = {
+ /* LINK */
+ RCAR_GP_PIN(3, 18),
+};
+static const unsigned int eth_link_mux[] = {
+ ETH_LINK_MARK,
+};
+static const unsigned int eth_magic_pins[] = {
+ /* MAGIC */
+ RCAR_GP_PIN(3, 22),
+};
+static const unsigned int eth_magic_mux[] = {
+ ETH_MAGIC_MARK,
+};
+static const unsigned int eth_mdio_pins[] = {
+ /* MDC, MDIO */
+ RCAR_GP_PIN(3, 24), RCAR_GP_PIN(3, 13),
+};
+static const unsigned int eth_mdio_mux[] = {
+ ETH_MDC_MARK, ETH_MDIO_MARK,
+};
+static const unsigned int eth_rmii_pins[] = {
+ /* RXD[0:1], RX_ER, CRS_DV, TXD[0:1], TX_EN, REF_CLK */
+ RCAR_GP_PIN(3, 16), RCAR_GP_PIN(3, 17), RCAR_GP_PIN(3, 15),
+ RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 23), RCAR_GP_PIN(3, 20),
+ RCAR_GP_PIN(3, 21), RCAR_GP_PIN(3, 19),
+};
+static const unsigned int eth_rmii_mux[] = {
+ ETH_RXD0_MARK, ETH_RXD1_MARK, ETH_RX_ER_MARK, ETH_CRS_DV_MARK,
+ ETH_TXD0_MARK, ETH_TXD1_MARK, ETH_TX_EN_MARK, ETH_REFCLK_MARK,
+};
+static const unsigned int eth_link_b_pins[] = {
+ /* LINK */
+ RCAR_GP_PIN(5, 15),
+};
+static const unsigned int eth_link_b_mux[] = {
+ ETH_LINK_B_MARK,
+};
+static const unsigned int eth_magic_b_pins[] = {
+ /* MAGIC */
+ RCAR_GP_PIN(5, 19),
+};
+static const unsigned int eth_magic_b_mux[] = {
+ ETH_MAGIC_B_MARK,
+};
+static const unsigned int eth_mdio_b_pins[] = {
+ /* MDC, MDIO */
+ RCAR_GP_PIN(5, 21), RCAR_GP_PIN(5, 10),
+};
+static const unsigned int eth_mdio_b_mux[] = {
+ ETH_MDC_B_MARK, ETH_MDIO_B_MARK,
+};
+static const unsigned int eth_rmii_b_pins[] = {
+ /* RXD[0:1], RX_ER, CRS_DV, TXD[0:1], TX_EN, REF_CLK */
+ RCAR_GP_PIN(5, 13), RCAR_GP_PIN(5, 14), RCAR_GP_PIN(5, 12),
+ RCAR_GP_PIN(5, 11), RCAR_GP_PIN(5, 20), RCAR_GP_PIN(5, 17),
+ RCAR_GP_PIN(5, 18), RCAR_GP_PIN(5, 16),
+};
+static const unsigned int eth_rmii_b_mux[] = {
+ ETH_RXD0_B_MARK, ETH_RXD1_B_MARK, ETH_RX_ER_B_MARK, ETH_CRS_DV_B_MARK,
+ ETH_TXD0_B_MARK, ETH_TXD1_B_MARK, ETH_TX_EN_B_MARK, ETH_REFCLK_B_MARK,
+};
+/* - HSCIF0 ----------------------------------------------------------------- */
+static const unsigned int hscif0_data_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(3, 25), RCAR_GP_PIN(3, 26),
+};
+static const unsigned int hscif0_data_mux[] = {
+ HSCIF0_HRX_MARK, HSCIF0_HTX_MARK,
+};
+static const unsigned int hscif0_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(3, 29),
+};
+static const unsigned int hscif0_clk_mux[] = {
+ HSCIF0_HSCK_MARK,
+};
+static const unsigned int hscif0_ctrl_pins[] = {
+ /* RTS, CTS */
+ RCAR_GP_PIN(3, 28), RCAR_GP_PIN(3, 27),
+};
+static const unsigned int hscif0_ctrl_mux[] = {
+ HSCIF0_HRTS_N_MARK, HSCIF0_HCTS_N_MARK,
+};
+static const unsigned int hscif0_data_b_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(0, 30), RCAR_GP_PIN(0, 31),
+};
+static const unsigned int hscif0_data_b_mux[] = {
+ HSCIF0_HRX_B_MARK, HSCIF0_HTX_B_MARK,
+};
+static const unsigned int hscif0_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 0),
+};
+static const unsigned int hscif0_clk_b_mux[] = {
+ HSCIF0_HSCK_B_MARK,
+};
+/* - HSCIF1 ----------------------------------------------------------------- */
+static const unsigned int hscif1_data_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(4, 8), RCAR_GP_PIN(4, 9),
+};
+static const unsigned int hscif1_data_mux[] = {
+ HSCIF1_HRX_MARK, HSCIF1_HTX_MARK,
+};
+static const unsigned int hscif1_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(4, 10),
+};
+static const unsigned int hscif1_clk_mux[] = {
+ HSCIF1_HSCK_MARK,
+};
+static const unsigned int hscif1_ctrl_pins[] = {
+ /* RTS, CTS */
+ RCAR_GP_PIN(4, 12), RCAR_GP_PIN(4, 11),
+};
+static const unsigned int hscif1_ctrl_mux[] = {
+ HSCIF1_HRTS_N_MARK, HSCIF1_HCTS_N_MARK,
+};
+static const unsigned int hscif1_data_b_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(5, 13), RCAR_GP_PIN(5, 14),
+};
+static const unsigned int hscif1_data_b_mux[] = {
+ HSCIF1_HRX_B_MARK, HSCIF1_HTX_B_MARK,
+};
+static const unsigned int hscif1_ctrl_b_pins[] = {
+ /* RTS, CTS */
+ RCAR_GP_PIN(5, 16), RCAR_GP_PIN(5, 15),
+};
+static const unsigned int hscif1_ctrl_b_mux[] = {
+ HSCIF1_HRTS_N_B_MARK, HSCIF1_HCTS_N_B_MARK,
+};
+/* - HSCIF2 ----------------------------------------------------------------- */
+static const unsigned int hscif2_data_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(0, 8), RCAR_GP_PIN(0, 9),
+};
+static const unsigned int hscif2_data_mux[] = {
+ HSCIF2_HRX_MARK, HSCIF2_HTX_MARK,
+};
+static const unsigned int hscif2_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 10),
+};
+static const unsigned int hscif2_clk_mux[] = {
+ HSCIF2_HSCK_MARK,
+};
+static const unsigned int hscif2_ctrl_pins[] = {
+ /* RTS, CTS */
+ RCAR_GP_PIN(0, 12), RCAR_GP_PIN(0, 11),
+};
+static const unsigned int hscif2_ctrl_mux[] = {
+ HSCIF2_HRTS_N_MARK, HSCIF2_HCTS_N_MARK,
+};
+/* - I2C0 ------------------------------------------------------------------- */
+static const unsigned int i2c0_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(3, 30), RCAR_GP_PIN(3, 31),
+};
+static const unsigned int i2c0_mux[] = {
+ I2C0_SCL_MARK, I2C0_SDA_MARK,
+};
+static const unsigned int i2c0_b_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(5, 20), RCAR_GP_PIN(5, 21),
+};
+static const unsigned int i2c0_b_mux[] = {
+ I2C0_SCL_B_MARK, I2C0_SDA_B_MARK,
+};
+static const unsigned int i2c0_c_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(3, 11), RCAR_GP_PIN(3, 12),
+};
+static const unsigned int i2c0_c_mux[] = {
+ I2C0_SCL_C_MARK, I2C0_SDA_C_MARK,
+};
+static const unsigned int i2c0_d_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(0, 5), RCAR_GP_PIN(0, 6),
+};
+static const unsigned int i2c0_d_mux[] = {
+ I2C0_SCL_D_MARK, I2C0_SDA_D_MARK,
+};
+static const unsigned int i2c0_e_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(3, 27), RCAR_GP_PIN(3, 28),
+};
+static const unsigned int i2c0_e_mux[] = {
+ I2C0_SCL_E_MARK, I2C0_SDA_E_MARK,
+};
+/* - I2C1 ------------------------------------------------------------------- */
+static const unsigned int i2c1_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(4, 0), RCAR_GP_PIN(4, 1),
+};
+static const unsigned int i2c1_mux[] = {
+ I2C1_SCL_MARK, I2C1_SDA_MARK,
+};
+static const unsigned int i2c1_b_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(0, 8), RCAR_GP_PIN(0, 9),
+};
+static const unsigned int i2c1_b_mux[] = {
+ I2C1_SCL_B_MARK, I2C1_SDA_B_MARK,
+};
+static const unsigned int i2c1_c_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(3, 25), RCAR_GP_PIN(3, 26),
+};
+static const unsigned int i2c1_c_mux[] = {
+ I2C1_SCL_C_MARK, I2C1_SDA_C_MARK,
+};
+static const unsigned int i2c1_d_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(0, 11), RCAR_GP_PIN(0, 12),
+};
+static const unsigned int i2c1_d_mux[] = {
+ I2C1_SCL_D_MARK, I2C1_SDA_D_MARK,
+};
+static const unsigned int i2c1_e_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(4, 20), RCAR_GP_PIN(4, 21),
+};
+static const unsigned int i2c1_e_mux[] = {
+ I2C1_SCL_E_MARK, I2C1_SDA_E_MARK,
+};
+/* - I2C2 ------------------------------------------------------------------- */
+static const unsigned int i2c2_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(4, 22), RCAR_GP_PIN(4, 23),
+};
+static const unsigned int i2c2_mux[] = {
+ I2C2_SCL_MARK, I2C2_SDA_MARK,
+};
+static const unsigned int i2c2_b_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(6, 24), RCAR_GP_PIN(6, 25),
+};
+static const unsigned int i2c2_b_mux[] = {
+ I2C2_SCL_B_MARK, I2C2_SDA_B_MARK,
+};
+static const unsigned int i2c2_c_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(4, 2), RCAR_GP_PIN(4, 3),
+};
+static const unsigned int i2c2_c_mux[] = {
+ I2C2_SCL_C_MARK, I2C2_SDA_C_MARK,
+};
+static const unsigned int i2c2_d_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1),
+};
+static const unsigned int i2c2_d_mux[] = {
+ I2C2_SCL_D_MARK, I2C2_SDA_D_MARK,
+};
+static const unsigned int i2c2_e_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(1, 16), RCAR_GP_PIN(1, 17),
+};
+static const unsigned int i2c2_e_mux[] = {
+ I2C2_SCL_E_MARK, I2C2_SDA_E_MARK,
+};
+/* - I2C3 ------------------------------------------------------------------- */
+static const unsigned int i2c3_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(3, 9), RCAR_GP_PIN(3, 10),
+};
+static const unsigned int i2c3_mux[] = {
+ I2C3_SCL_MARK, I2C3_SDA_MARK,
+};
+static const unsigned int i2c3_b_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(0, 3), RCAR_GP_PIN(0, 4),
+};
+static const unsigned int i2c3_b_mux[] = {
+ I2C3_SCL_B_MARK, I2C3_SDA_B_MARK,
+};
+static const unsigned int i2c3_c_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(4, 25), RCAR_GP_PIN(4, 26),
+};
+static const unsigned int i2c3_c_mux[] = {
+ I2C3_SCL_C_MARK, I2C3_SDA_C_MARK,
+};
+static const unsigned int i2c3_d_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(2, 8), RCAR_GP_PIN(2, 9),
+};
+static const unsigned int i2c3_d_mux[] = {
+ I2C3_SCL_D_MARK, I2C3_SDA_D_MARK,
+};
+static const unsigned int i2c3_e_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(5, 18), RCAR_GP_PIN(5, 19),
+};
+static const unsigned int i2c3_e_mux[] = {
+ I2C3_SCL_E_MARK, I2C3_SDA_E_MARK,
+};
+/* - I2C4 ------------------------------------------------------------------- */
+static const unsigned int i2c4_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(4, 8), RCAR_GP_PIN(4, 9),
+};
+static const unsigned int i2c4_mux[] = {
+ I2C4_SCL_MARK, I2C4_SDA_MARK,
+};
+static const unsigned int i2c4_b_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(5, 22), RCAR_GP_PIN(5, 23),
+};
+static const unsigned int i2c4_b_mux[] = {
+ I2C4_SCL_B_MARK, I2C4_SDA_B_MARK,
+};
+static const unsigned int i2c4_c_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(4, 28), RCAR_GP_PIN(4, 29),
+};
+static const unsigned int i2c4_c_mux[] = {
+ I2C4_SCL_C_MARK, I2C4_SDA_C_MARK,
+};
+static const unsigned int i2c4_d_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(2, 16), RCAR_GP_PIN(2, 17),
+};
+static const unsigned int i2c4_d_mux[] = {
+ I2C4_SCL_D_MARK, I2C4_SDA_D_MARK,
+};
+static const unsigned int i2c4_e_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(3, 23), RCAR_GP_PIN(3, 24),
+};
+static const unsigned int i2c4_e_mux[] = {
+ I2C4_SCL_E_MARK, I2C4_SDA_E_MARK,
+};
+/* - INTC ------------------------------------------------------------------- */
+static const unsigned int intc_irq0_pins[] = {
+ /* IRQ0 */
+ RCAR_GP_PIN(4, 4),
+};
+static const unsigned int intc_irq0_mux[] = {
+ IRQ0_MARK,
+};
+static const unsigned int intc_irq1_pins[] = {
+ /* IRQ1 */
+ RCAR_GP_PIN(4, 18),
+};
+static const unsigned int intc_irq1_mux[] = {
+ IRQ1_MARK,
+};
+static const unsigned int intc_irq2_pins[] = {
+ /* IRQ2 */
+ RCAR_GP_PIN(4, 19),
+};
+static const unsigned int intc_irq2_mux[] = {
+ IRQ2_MARK,
+};
+static const unsigned int intc_irq3_pins[] = {
+ /* IRQ3 */
+ RCAR_GP_PIN(0, 7),
+};
+static const unsigned int intc_irq3_mux[] = {
+ IRQ3_MARK,
+};
+static const unsigned int intc_irq4_pins[] = {
+ /* IRQ4 */
+ RCAR_GP_PIN(0, 0),
+};
+static const unsigned int intc_irq4_mux[] = {
+ IRQ4_MARK,
+};
+static const unsigned int intc_irq5_pins[] = {
+ /* IRQ5 */
+ RCAR_GP_PIN(4, 1),
+};
+static const unsigned int intc_irq5_mux[] = {
+ IRQ5_MARK,
+};
+static const unsigned int intc_irq6_pins[] = {
+ /* IRQ6 */
+ RCAR_GP_PIN(0, 10),
+};
+static const unsigned int intc_irq6_mux[] = {
+ IRQ6_MARK,
+};
+static const unsigned int intc_irq7_pins[] = {
+ /* IRQ7 */
+ RCAR_GP_PIN(6, 15),
+};
+static const unsigned int intc_irq7_mux[] = {
+ IRQ7_MARK,
+};
+static const unsigned int intc_irq8_pins[] = {
+ /* IRQ8 */
+ RCAR_GP_PIN(5, 0),
+};
+static const unsigned int intc_irq8_mux[] = {
+ IRQ8_MARK,
+};
+static const unsigned int intc_irq9_pins[] = {
+ /* IRQ9 */
+ RCAR_GP_PIN(5, 10),
+};
+static const unsigned int intc_irq9_mux[] = {
+ IRQ9_MARK,
+};
+/* - MMCIF ------------------------------------------------------------------ */
+static const unsigned int mmc_data1_pins[] = {
+ /* D[0] */
+ RCAR_GP_PIN(6, 18),
+};
+static const unsigned int mmc_data1_mux[] = {
+ MMC_D0_MARK,
+};
+static const unsigned int mmc_data4_pins[] = {
+ /* D[0:3] */
+ RCAR_GP_PIN(6, 18), RCAR_GP_PIN(6, 19),
+ RCAR_GP_PIN(6, 20), RCAR_GP_PIN(6, 21),
+};
+static const unsigned int mmc_data4_mux[] = {
+ MMC_D0_MARK, MMC_D1_MARK, MMC_D2_MARK, MMC_D3_MARK,
+};
+static const unsigned int mmc_data8_pins[] = {
+ /* D[0:7] */
+ RCAR_GP_PIN(6, 18), RCAR_GP_PIN(6, 19),
+ RCAR_GP_PIN(6, 20), RCAR_GP_PIN(6, 21),
+ RCAR_GP_PIN(6, 22), RCAR_GP_PIN(6, 23),
+ RCAR_GP_PIN(6, 24), RCAR_GP_PIN(6, 25),
+};
+static const unsigned int mmc_data8_mux[] = {
+ MMC_D0_MARK, MMC_D1_MARK, MMC_D2_MARK, MMC_D3_MARK,
+ MMC_D4_MARK, MMC_D5_MARK, MMC_D6_MARK, MMC_D7_MARK,
+};
+static const unsigned int mmc_ctrl_pins[] = {
+ /* CLK, CMD */
+ RCAR_GP_PIN(6, 16), RCAR_GP_PIN(6, 17),
+};
+static const unsigned int mmc_ctrl_mux[] = {
+ MMC_CLK_MARK, MMC_CMD_MARK,
+};
+/* - MSIOF0 ----------------------------------------------------------------- */
+static const unsigned int msiof0_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(4, 4),
+};
+static const unsigned int msiof0_clk_mux[] = {
+ MSIOF0_SCK_MARK,
+};
+static const unsigned int msiof0_sync_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(4, 5),
+};
+static const unsigned int msiof0_sync_mux[] = {
+ MSIOF0_SYNC_MARK,
+};
+static const unsigned int msiof0_ss1_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(4, 6),
+};
+static const unsigned int msiof0_ss1_mux[] = {
+ MSIOF0_SS1_MARK,
+};
+static const unsigned int msiof0_ss2_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(4, 7),
+};
+static const unsigned int msiof0_ss2_mux[] = {
+ MSIOF0_SS2_MARK,
+};
+static const unsigned int msiof0_rx_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(4, 2),
+};
+static const unsigned int msiof0_rx_mux[] = {
+ MSIOF0_RXD_MARK,
+};
+static const unsigned int msiof0_tx_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(4, 3),
+};
+static const unsigned int msiof0_tx_mux[] = {
+ MSIOF0_TXD_MARK,
+};
+/* - MSIOF1 ----------------------------------------------------------------- */
+static const unsigned int msiof1_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 26),
+};
+static const unsigned int msiof1_clk_mux[] = {
+ MSIOF1_SCK_MARK,
+};
+static const unsigned int msiof1_sync_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(0, 27),
+};
+static const unsigned int msiof1_sync_mux[] = {
+ MSIOF1_SYNC_MARK,
+};
+static const unsigned int msiof1_ss1_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(0, 28),
+};
+static const unsigned int msiof1_ss1_mux[] = {
+ MSIOF1_SS1_MARK,
+};
+static const unsigned int msiof1_ss2_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(0, 29),
+};
+static const unsigned int msiof1_ss2_mux[] = {
+ MSIOF1_SS2_MARK,
+};
+static const unsigned int msiof1_rx_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(0, 24),
+};
+static const unsigned int msiof1_rx_mux[] = {
+ MSIOF1_RXD_MARK,
+};
+static const unsigned int msiof1_tx_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 25),
+};
+static const unsigned int msiof1_tx_mux[] = {
+ MSIOF1_TXD_MARK,
+};
+static const unsigned int msiof1_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(5, 3),
+};
+static const unsigned int msiof1_clk_b_mux[] = {
+ MSIOF1_SCK_B_MARK,
+};
+static const unsigned int msiof1_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(5, 4),
+};
+static const unsigned int msiof1_sync_b_mux[] = {
+ MSIOF1_SYNC_B_MARK,
+};
+static const unsigned int msiof1_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(5, 5),
+};
+static const unsigned int msiof1_ss1_b_mux[] = {
+ MSIOF1_SS1_B_MARK,
+};
+static const unsigned int msiof1_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(5, 6),
+};
+static const unsigned int msiof1_ss2_b_mux[] = {
+ MSIOF1_SS2_B_MARK,
+};
+static const unsigned int msiof1_rx_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(5, 1),
+};
+static const unsigned int msiof1_rx_b_mux[] = {
+ MSIOF1_RXD_B_MARK,
+};
+static const unsigned int msiof1_tx_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(5, 2),
+};
+static const unsigned int msiof1_tx_b_mux[] = {
+ MSIOF1_TXD_B_MARK,
+};
+/* - MSIOF2 ----------------------------------------------------------------- */
+static const unsigned int msiof2_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 0),
+};
+static const unsigned int msiof2_clk_mux[] = {
+ MSIOF2_SCK_MARK,
+};
+static const unsigned int msiof2_sync_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(1, 1),
+};
+static const unsigned int msiof2_sync_mux[] = {
+ MSIOF2_SYNC_MARK,
+};
+static const unsigned int msiof2_ss1_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(1, 2),
+};
+static const unsigned int msiof2_ss1_mux[] = {
+ MSIOF2_SS1_MARK,
+};
+static const unsigned int msiof2_ss2_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(1, 3),
+};
+static const unsigned int msiof2_ss2_mux[] = {
+ MSIOF2_SS2_MARK,
+};
+static const unsigned int msiof2_rx_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(0, 30),
+};
+static const unsigned int msiof2_rx_mux[] = {
+ MSIOF2_RXD_MARK,
+};
+static const unsigned int msiof2_tx_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 31),
+};
+static const unsigned int msiof2_tx_mux[] = {
+ MSIOF2_TXD_MARK,
+};
+static const unsigned int msiof2_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(3, 15),
+};
+static const unsigned int msiof2_clk_b_mux[] = {
+ MSIOF2_SCK_B_MARK,
+};
+static const unsigned int msiof2_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(3, 16),
+};
+static const unsigned int msiof2_sync_b_mux[] = {
+ MSIOF2_SYNC_B_MARK,
+};
+static const unsigned int msiof2_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(3, 17),
+};
+static const unsigned int msiof2_ss1_b_mux[] = {
+ MSIOF2_SS1_B_MARK,
+};
+static const unsigned int msiof2_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(3, 18),
+};
+static const unsigned int msiof2_ss2_b_mux[] = {
+ MSIOF2_SS2_B_MARK,
+};
+static const unsigned int msiof2_rx_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(3, 13),
+};
+static const unsigned int msiof2_rx_b_mux[] = {
+ MSIOF2_RXD_B_MARK,
+};
+static const unsigned int msiof2_tx_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(3, 14),
+};
+static const unsigned int msiof2_tx_b_mux[] = {
+ MSIOF2_TXD_B_MARK,
+};
+/* - QSPI ------------------------------------------------------------------- */
+static const unsigned int qspi_ctrl_pins[] = {
+ /* SPCLK, SSL */
+ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 9),
+};
+static const unsigned int qspi_ctrl_mux[] = {
+ SPCLK_MARK, SSL_MARK,
+};
+static const unsigned int qspi_data2_pins[] = {
+ /* MOSI_IO0, MISO_IO1 */
+ RCAR_GP_PIN(1, 5), RCAR_GP_PIN(1, 6),
+};
+static const unsigned int qspi_data2_mux[] = {
+ MOSI_IO0_MARK, MISO_IO1_MARK,
+};
+static const unsigned int qspi_data4_pins[] = {
+ /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+ RCAR_GP_PIN(1, 5), RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7),
+ RCAR_GP_PIN(1, 8),
+};
+static const unsigned int qspi_data4_mux[] = {
+ MOSI_IO0_MARK, MISO_IO1_MARK, IO2_MARK, IO3_MARK,
+};
+/* - SCIF0 ------------------------------------------------------------------ */
+static const unsigned int scif0_data_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(6, 24), RCAR_GP_PIN(6, 25),
+};
+static const unsigned int scif0_data_mux[] = {
+ SCIF0_RXD_MARK, SCIF0_TXD_MARK,
+};
+static const unsigned int scif0_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 23),
+};
+static const unsigned int scif0_clk_mux[] = {
+ SCIF_CLK_MARK,
+};
+static const unsigned int scif0_data_b_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(3, 11), RCAR_GP_PIN(3, 12),
+};
+static const unsigned int scif0_data_b_mux[] = {
+ SCIF0_RXD_B_MARK, SCIF0_TXD_B_MARK,
+};
+static const unsigned int scif0_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(3, 29),
+};
+static const unsigned int scif0_clk_b_mux[] = {
+ SCIF_CLK_B_MARK,
+};
+static const unsigned int scif0_data_c_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(3, 30), RCAR_GP_PIN(3, 31),
+};
+static const unsigned int scif0_data_c_mux[] = {
+ SCIF0_RXD_C_MARK, SCIF0_TXD_C_MARK,
+};
+static const unsigned int scif0_data_d_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(3, 27), RCAR_GP_PIN(3, 28),
+};
+static const unsigned int scif0_data_d_mux[] = {
+ SCIF0_RXD_D_MARK, SCIF0_TXD_D_MARK,
+};
+/* - SCIF1 ------------------------------------------------------------------ */
+static const unsigned int scif1_data_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(4, 14), RCAR_GP_PIN(4, 15),
+};
+static const unsigned int scif1_data_mux[] = {
+ SCIF1_RXD_MARK, SCIF1_TXD_MARK,
+};
+static const unsigned int scif1_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(4, 13),
+};
+static const unsigned int scif1_clk_mux[] = {
+ SCIF1_SCK_MARK,
+};
+static const unsigned int scif1_data_b_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(5, 11), RCAR_GP_PIN(5, 12),
+};
+static const unsigned int scif1_data_b_mux[] = {
+ SCIF1_RXD_B_MARK, SCIF1_TXD_B_MARK,
+};
+static const unsigned int scif1_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(5, 10),
+};
+static const unsigned int scif1_clk_b_mux[] = {
+ SCIF1_SCK_B_MARK,
+};
+static const unsigned int scif1_data_c_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(0, 11), RCAR_GP_PIN(0, 12),
+};
+static const unsigned int scif1_data_c_mux[] = {
+ SCIF1_RXD_C_MARK, SCIF1_TXD_C_MARK,
+};
+static const unsigned int scif1_clk_c_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 10),
+};
+static const unsigned int scif1_clk_c_mux[] = {
+ SCIF1_SCK_C_MARK,
+};
+/* - SCIF2 ------------------------------------------------------------------ */
+static const unsigned int scif2_data_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(4, 16), RCAR_GP_PIN(4, 17),
+};
+static const unsigned int scif2_data_mux[] = {
+ SCIF2_RXD_MARK, SCIF2_TXD_MARK,
+};
+static const unsigned int scif2_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(4, 18),
+};
+static const unsigned int scif2_clk_mux[] = {
+ SCIF2_SCK_MARK,
+};
+static const unsigned int scif2_data_b_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(5, 18), RCAR_GP_PIN(5, 19),
+};
+static const unsigned int scif2_data_b_mux[] = {
+ SCIF2_RXD_B_MARK, SCIF2_TXD_B_MARK,
+};
+static const unsigned int scif2_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(5, 17),
+};
+static const unsigned int scif2_clk_b_mux[] = {
+ SCIF2_SCK_B_MARK,
+};
+static const unsigned int scif2_data_c_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(3, 20), RCAR_GP_PIN(3, 21),
+};
+static const unsigned int scif2_data_c_mux[] = {
+ SCIF2_RXD_C_MARK, SCIF2_TXD_C_MARK,
+};
+static const unsigned int scif2_clk_c_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(3, 19),
+};
+static const unsigned int scif2_clk_c_mux[] = {
+ SCIF2_SCK_C_MARK,
+};
+/* - SCIF3 ------------------------------------------------------------------ */
+static const unsigned int scif3_data_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(4, 20), RCAR_GP_PIN(4, 21),
+};
+static const unsigned int scif3_data_mux[] = {
+ SCIF3_RXD_MARK, SCIF3_TXD_MARK,
+};
+static const unsigned int scif3_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(4, 19),
+};
+static const unsigned int scif3_clk_mux[] = {
+ SCIF3_SCK_MARK,
+};
+static const unsigned int scif3_data_b_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(3, 23), RCAR_GP_PIN(3, 24),
+};
+static const unsigned int scif3_data_b_mux[] = {
+ SCIF3_RXD_B_MARK, SCIF3_TXD_B_MARK,
+};
+static const unsigned int scif3_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(3, 22),
+};
+static const unsigned int scif3_clk_b_mux[] = {
+ SCIF3_SCK_B_MARK,
+};
+/* - SCIF4 ------------------------------------------------------------------ */
+static const unsigned int scif4_data_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(4, 0), RCAR_GP_PIN(4, 1),
+};
+static const unsigned int scif4_data_mux[] = {
+ SCIF4_RXD_MARK, SCIF4_TXD_MARK,
+};
+static const unsigned int scif4_data_b_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(0, 5), RCAR_GP_PIN(0, 6),
+};
+static const unsigned int scif4_data_b_mux[] = {
+ SCIF4_RXD_B_MARK, SCIF4_TXD_B_MARK,
+};
+static const unsigned int scif4_data_c_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(1, 14), RCAR_GP_PIN(1, 15),
+};
+static const unsigned int scif4_data_c_mux[] = {
+ SCIF4_RXD_C_MARK, SCIF4_TXD_C_MARK,
+};
+static const unsigned int scif4_data_d_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(3, 17), RCAR_GP_PIN(3, 18),
+};
+static const unsigned int scif4_data_d_mux[] = {
+ SCIF4_RXD_D_MARK, SCIF4_TXD_D_MARK,
+};
+static const unsigned int scif4_data_e_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(1, 1), RCAR_GP_PIN(1, 2),
+};
+static const unsigned int scif4_data_e_mux[] = {
+ SCIF4_RXD_E_MARK, SCIF4_TXD_E_MARK,
+};
+/* - SCIF5 ------------------------------------------------------------------ */
+static const unsigned int scif5_data_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(4, 2), RCAR_GP_PIN(4, 3),
+};
+static const unsigned int scif5_data_mux[] = {
+ SCIF5_RXD_MARK, SCIF5_TXD_MARK,
+};
+static const unsigned int scif5_data_b_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(0, 3), RCAR_GP_PIN(0, 4),
+};
+static const unsigned int scif5_data_b_mux[] = {
+ SCIF5_RXD_B_MARK, SCIF5_TXD_B_MARK,
+};
+static const unsigned int scif5_data_c_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 11),
+};
+static const unsigned int scif5_data_c_mux[] = {
+ SCIF5_RXD_C_MARK, SCIF5_TXD_C_MARK,
+};
+static const unsigned int scif5_data_d_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 2),
+};
+static const unsigned int scif5_data_d_mux[] = {
+ SCIF5_RXD_D_MARK, SCIF5_TXD_D_MARK,
+};
+/* - SCIFA0 ----------------------------------------------------------------- */
+static const unsigned int scifa0_data_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(4, 6), RCAR_GP_PIN(4, 7),
+};
+static const unsigned int scifa0_data_mux[] = {
+ SCIFA0_RXD_MARK, SCIFA0_TXD_MARK,
+};
+static const unsigned int scifa0_data_b_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(0, 24), RCAR_GP_PIN(0, 25),
+};
+static const unsigned int scifa0_data_b_mux[] = {
+ SCIFA0_RXD_B_MARK, SCIFA0_TXD_B_MARK
+};
+static const unsigned int scifa0_data_c_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(2, 8), RCAR_GP_PIN(2, 9),
+};
+static const unsigned int scifa0_data_c_mux[] = {
+ SCIFA0_RXD_C_MARK, SCIFA0_TXD_C_MARK
+};
+static const unsigned int scifa0_data_d_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 16),
+};
+static const unsigned int scifa0_data_d_mux[] = {
+ SCIFA0_RXD_D_MARK, SCIFA0_TXD_D_MARK
+};
+/* - SCIFA1 ----------------------------------------------------------------- */
+static const unsigned int scifa1_data_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 15),
+};
+static const unsigned int scifa1_data_mux[] = {
+ SCIFA1_RXD_MARK, SCIFA1_TXD_MARK,
+};
+static const unsigned int scifa1_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 13),
+};
+static const unsigned int scifa1_clk_mux[] = {
+ SCIFA1_SCK_MARK,
+};
+static const unsigned int scifa1_data_b_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(4, 28), RCAR_GP_PIN(4, 29),
+};
+static const unsigned int scifa1_data_b_mux[] = {
+ SCIFA1_RXD_B_MARK, SCIFA1_TXD_B_MARK,
+};
+static const unsigned int scifa1_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(4, 27),
+};
+static const unsigned int scifa1_clk_b_mux[] = {
+ SCIFA1_SCK_B_MARK,
+};
+static const unsigned int scifa1_data_c_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(5, 5), RCAR_GP_PIN(5, 6),
+};
+static const unsigned int scifa1_data_c_mux[] = {
+ SCIFA1_RXD_C_MARK, SCIFA1_TXD_C_MARK,
+};
+static const unsigned int scifa1_clk_c_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(5, 4),
+};
+static const unsigned int scifa1_clk_c_mux[] = {
+ SCIFA1_SCK_C_MARK,
+};
+/* - SCIFA2 ----------------------------------------------------------------- */
+static const unsigned int scifa2_data_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(1, 16), RCAR_GP_PIN(1, 17),
+};
+static const unsigned int scifa2_data_mux[] = {
+ SCIFA2_RXD_MARK, SCIFA2_TXD_MARK,
+};
+static const unsigned int scifa2_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 15),
+};
+static const unsigned int scifa2_clk_mux[] = {
+ SCIFA2_SCK_MARK,
+};
+static const unsigned int scifa2_data_b_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(4, 31), RCAR_GP_PIN(5, 0),
+};
+static const unsigned int scifa2_data_b_mux[] = {
+ SCIFA2_RXD_B_MARK, SCIFA2_TXD_B_MARK,
+};
+static const unsigned int scifa2_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(4, 30),
+};
+static const unsigned int scifa2_clk_b_mux[] = {
+ SCIFA2_SCK_B_MARK,
+};
+/* - SCIFA3 ----------------------------------------------------------------- */
+static const unsigned int scifa3_data_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(4, 25), RCAR_GP_PIN(4, 26),
+};
+static const unsigned int scifa3_data_mux[] = {
+ SCIFA3_RXD_MARK, SCIFA3_TXD_MARK,
+};
+static const unsigned int scifa3_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(4, 24),
+};
+static const unsigned int scifa3_clk_mux[] = {
+ SCIFA3_SCK_MARK,
+};
+static const unsigned int scifa3_data_b_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(0, 1), RCAR_GP_PIN(0, 2),
+};
+static const unsigned int scifa3_data_b_mux[] = {
+ SCIFA3_RXD_B_MARK, SCIFA3_TXD_B_MARK,
+};
+static const unsigned int scifa3_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 0),
+};
+static const unsigned int scifa3_clk_b_mux[] = {
+ SCIFA3_SCK_B_MARK,
+};
+/* - SCIFA4 ----------------------------------------------------------------- */
+static const unsigned int scifa4_data_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(4, 12), RCAR_GP_PIN(4, 12),
+};
+static const unsigned int scifa4_data_mux[] = {
+ SCIFA4_RXD_MARK, SCIFA4_TXD_MARK,
+};
+static const unsigned int scifa4_data_b_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(0, 22), RCAR_GP_PIN(0, 23),
+};
+static const unsigned int scifa4_data_b_mux[] = {
+ SCIFA4_RXD_B_MARK, SCIFA4_TXD_B_MARK,
+};
+static const unsigned int scifa4_data_c_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(2, 16), RCAR_GP_PIN(2, 17),
+};
+static const unsigned int scifa4_data_c_mux[] = {
+ SCIFA4_RXD_C_MARK, SCIFA4_TXD_C_MARK,
+};
+static const unsigned int scifa4_data_d_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(5, 20), RCAR_GP_PIN(5, 21),
+};
+static const unsigned int scifa4_data_d_mux[] = {
+ SCIFA4_RXD_D_MARK, SCIFA4_TXD_D_MARK,
+};
+/* - SCIFA5 ----------------------------------------------------------------- */
+static const unsigned int scifa5_data_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(4, 22), RCAR_GP_PIN(4, 23),
+};
+static const unsigned int scifa5_data_mux[] = {
+ SCIFA5_RXD_MARK, SCIFA5_TXD_MARK,
+};
+static const unsigned int scifa5_data_b_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(0, 28), RCAR_GP_PIN(0, 29),
+};
+static const unsigned int scifa5_data_b_mux[] = {
+ SCIFA5_RXD_B_MARK, SCIFA5_TXD_B_MARK,
+};
+static const unsigned int scifa5_data_c_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(3, 9), RCAR_GP_PIN(3, 10),
+};
+static const unsigned int scifa5_data_c_mux[] = {
+ SCIFA5_RXD_C_MARK, SCIFA5_TXD_C_MARK,
+};
+static const unsigned int scifa5_data_d_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(5, 22), RCAR_GP_PIN(5, 23),
+};
+static const unsigned int scifa5_data_d_mux[] = {
+ SCIFA5_RXD_D_MARK, SCIFA5_TXD_D_MARK,
+};
+/* - SCIFB0 ----------------------------------------------------------------- */
+static const unsigned int scifb0_data_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(0, 21), RCAR_GP_PIN(0, 20),
+};
+static const unsigned int scifb0_data_mux[] = {
+ SCIFB0_RXD_MARK, SCIFB0_TXD_MARK,
+};
+static const unsigned int scifb0_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 19),
+};
+static const unsigned int scifb0_clk_mux[] = {
+ SCIFB0_SCK_MARK,
+};
+static const unsigned int scifb0_ctrl_pins[] = {
+ /* RTS, CTS */
+ RCAR_GP_PIN(0, 23), RCAR_GP_PIN(0, 22),
+};
+static const unsigned int scifb0_ctrl_mux[] = {
+ SCIFB0_RTS_N_MARK, SCIFB0_CTS_N_MARK,
+};
+/* - SCIFB1 ----------------------------------------------------------------- */
+static const unsigned int scifb1_data_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(1, 24), RCAR_GP_PIN(0, 17),
+};
+static const unsigned int scifb1_data_mux[] = {
+ SCIFB1_RXD_MARK, SCIFB1_TXD_MARK,
+};
+static const unsigned int scifb1_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 16),
+};
+static const unsigned int scifb1_clk_mux[] = {
+ SCIFB1_SCK_MARK,
+};
+/* - SCIFB2 ----------------------------------------------------------------- */
+static const unsigned int scifb2_data_pins[] = {
+ /* RXD, TXD */
+ RCAR_GP_PIN(1, 13), RCAR_GP_PIN(1, 14),
+};
+static const unsigned int scifb2_data_mux[] = {
+ SCIFB2_RXD_MARK, SCIFB2_TXD_MARK,
+};
+static const unsigned int scifb2_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 15),
+};
+static const unsigned int scifb2_clk_mux[] = {
+ SCIFB2_SCK_MARK,
+};
+static const unsigned int scifb2_ctrl_pins[] = {
+ /* RTS, CTS */
+ RCAR_GP_PIN(1, 17), RCAR_GP_PIN(1, 16),
+};
+static const unsigned int scifb2_ctrl_mux[] = {
+ SCIFB2_RTS_N_MARK, SCIFB2_CTS_N_MARK,
+};
+/* - SDHI0 ------------------------------------------------------------------ */
+static const unsigned int sdhi0_data1_pins[] = {
+ /* D0 */
+ RCAR_GP_PIN(6, 2),
+};
+static const unsigned int sdhi0_data1_mux[] = {
+ SD0_DATA0_MARK,
+};
+static const unsigned int sdhi0_data4_pins[] = {
+ /* D[0:3] */
+ RCAR_GP_PIN(6, 2), RCAR_GP_PIN(6, 3),
+ RCAR_GP_PIN(6, 4), RCAR_GP_PIN(6, 5),
+};
+static const unsigned int sdhi0_data4_mux[] = {
+ SD0_DATA0_MARK, SD0_DATA1_MARK, SD0_DATA2_MARK, SD0_DATA3_MARK,
+};
+static const unsigned int sdhi0_ctrl_pins[] = {
+ /* CLK, CMD */
+ RCAR_GP_PIN(6, 0), RCAR_GP_PIN(6, 1),
+};
+static const unsigned int sdhi0_ctrl_mux[] = {
+ SD0_CLK_MARK, SD0_CMD_MARK,
+};
+static const unsigned int sdhi0_cd_pins[] = {
+ /* CD */
+ RCAR_GP_PIN(6, 6),
+};
+static const unsigned int sdhi0_cd_mux[] = {
+ SD0_CD_MARK,
+};
+static const unsigned int sdhi0_wp_pins[] = {
+ /* WP */
+ RCAR_GP_PIN(6, 7),
+};
+static const unsigned int sdhi0_wp_mux[] = {
+ SD0_WP_MARK,
+};
+/* - SDHI1 ------------------------------------------------------------------ */
+static const unsigned int sdhi1_data1_pins[] = {
+ /* D0 */
+ RCAR_GP_PIN(6, 10),
+};
+static const unsigned int sdhi1_data1_mux[] = {
+ SD1_DATA0_MARK,
+};
+static const unsigned int sdhi1_data4_pins[] = {
+ /* D[0:3] */
+ RCAR_GP_PIN(6, 10), RCAR_GP_PIN(6, 11),
+ RCAR_GP_PIN(6, 12), RCAR_GP_PIN(6, 13),
+};
+static const unsigned int sdhi1_data4_mux[] = {
+ SD1_DATA0_MARK, SD1_DATA1_MARK, SD1_DATA2_MARK, SD1_DATA3_MARK,
+};
+static const unsigned int sdhi1_ctrl_pins[] = {
+ /* CLK, CMD */
+ RCAR_GP_PIN(6, 8), RCAR_GP_PIN(6, 9),
+};
+static const unsigned int sdhi1_ctrl_mux[] = {
+ SD1_CLK_MARK, SD1_CMD_MARK,
+};
+static const unsigned int sdhi1_cd_pins[] = {
+ /* CD */
+ RCAR_GP_PIN(6, 14),
+};
+static const unsigned int sdhi1_cd_mux[] = {
+ SD1_CD_MARK,
+};
+static const unsigned int sdhi1_wp_pins[] = {
+ /* WP */
+ RCAR_GP_PIN(6, 15),
+};
+static const unsigned int sdhi1_wp_mux[] = {
+ SD1_WP_MARK,
+};
+/* - SDHI2 ------------------------------------------------------------------ */
+static const unsigned int sdhi2_data1_pins[] = {
+ /* D0 */
+ RCAR_GP_PIN(6, 18),
+};
+static const unsigned int sdhi2_data1_mux[] = {
+ SD2_DATA0_MARK,
+};
+static const unsigned int sdhi2_data4_pins[] = {
+ /* D[0:3] */
+ RCAR_GP_PIN(6, 18), RCAR_GP_PIN(6, 19),
+ RCAR_GP_PIN(6, 20), RCAR_GP_PIN(6, 21),
+};
+static const unsigned int sdhi2_data4_mux[] = {
+ SD2_DATA0_MARK, SD2_DATA1_MARK, SD2_DATA2_MARK, SD2_DATA3_MARK,
+};
+static const unsigned int sdhi2_ctrl_pins[] = {
+ /* CLK, CMD */
+ RCAR_GP_PIN(6, 16), RCAR_GP_PIN(6, 17),
+};
+static const unsigned int sdhi2_ctrl_mux[] = {
+ SD2_CLK_MARK, SD2_CMD_MARK,
+};
+static const unsigned int sdhi2_cd_pins[] = {
+ /* CD */
+ RCAR_GP_PIN(6, 22),
+};
+static const unsigned int sdhi2_cd_mux[] = {
+ SD2_CD_MARK,
+};
+static const unsigned int sdhi2_wp_pins[] = {
+ /* WP */
+ RCAR_GP_PIN(6, 23),
+};
+static const unsigned int sdhi2_wp_mux[] = {
+ SD2_WP_MARK,
+};
+
+static const struct sh_pfc_pin_group pinmux_groups[] = {
+ SH_PFC_PIN_GROUP(eth_link),
+ SH_PFC_PIN_GROUP(eth_magic),
+ SH_PFC_PIN_GROUP(eth_mdio),
+ SH_PFC_PIN_GROUP(eth_rmii),
+ SH_PFC_PIN_GROUP(eth_link_b),
+ SH_PFC_PIN_GROUP(eth_magic_b),
+ SH_PFC_PIN_GROUP(eth_mdio_b),
+ SH_PFC_PIN_GROUP(eth_rmii_b),
+ SH_PFC_PIN_GROUP(hscif0_data),
+ SH_PFC_PIN_GROUP(hscif0_clk),
+ SH_PFC_PIN_GROUP(hscif0_ctrl),
+ SH_PFC_PIN_GROUP(hscif0_data_b),
+ SH_PFC_PIN_GROUP(hscif0_clk_b),
+ SH_PFC_PIN_GROUP(hscif1_data),
+ SH_PFC_PIN_GROUP(hscif1_clk),
+ SH_PFC_PIN_GROUP(hscif1_ctrl),
+ SH_PFC_PIN_GROUP(hscif1_data_b),
+ SH_PFC_PIN_GROUP(hscif1_ctrl_b),
+ SH_PFC_PIN_GROUP(hscif2_data),
+ SH_PFC_PIN_GROUP(hscif2_clk),
+ SH_PFC_PIN_GROUP(hscif2_ctrl),
+ SH_PFC_PIN_GROUP(i2c0),
+ SH_PFC_PIN_GROUP(i2c0_b),
+ SH_PFC_PIN_GROUP(i2c0_c),
+ SH_PFC_PIN_GROUP(i2c0_d),
+ SH_PFC_PIN_GROUP(i2c0_e),
+ SH_PFC_PIN_GROUP(i2c1),
+ SH_PFC_PIN_GROUP(i2c1_b),
+ SH_PFC_PIN_GROUP(i2c1_c),
+ SH_PFC_PIN_GROUP(i2c1_d),
+ SH_PFC_PIN_GROUP(i2c1_e),
+ SH_PFC_PIN_GROUP(i2c2),
+ SH_PFC_PIN_GROUP(i2c2_b),
+ SH_PFC_PIN_GROUP(i2c2_c),
+ SH_PFC_PIN_GROUP(i2c2_d),
+ SH_PFC_PIN_GROUP(i2c2_e),
+ SH_PFC_PIN_GROUP(i2c3),
+ SH_PFC_PIN_GROUP(i2c3_b),
+ SH_PFC_PIN_GROUP(i2c3_c),
+ SH_PFC_PIN_GROUP(i2c3_d),
+ SH_PFC_PIN_GROUP(i2c3_e),
+ SH_PFC_PIN_GROUP(i2c4),
+ SH_PFC_PIN_GROUP(i2c4_b),
+ SH_PFC_PIN_GROUP(i2c4_c),
+ SH_PFC_PIN_GROUP(i2c4_d),
+ SH_PFC_PIN_GROUP(i2c4_e),
+ SH_PFC_PIN_GROUP(intc_irq0),
+ SH_PFC_PIN_GROUP(intc_irq1),
+ SH_PFC_PIN_GROUP(intc_irq2),
+ SH_PFC_PIN_GROUP(intc_irq3),
+ SH_PFC_PIN_GROUP(intc_irq4),
+ SH_PFC_PIN_GROUP(intc_irq5),
+ SH_PFC_PIN_GROUP(intc_irq6),
+ SH_PFC_PIN_GROUP(intc_irq7),
+ SH_PFC_PIN_GROUP(intc_irq8),
+ SH_PFC_PIN_GROUP(intc_irq9),
+ SH_PFC_PIN_GROUP(mmc_data1),
+ SH_PFC_PIN_GROUP(mmc_data4),
+ SH_PFC_PIN_GROUP(mmc_data8),
+ SH_PFC_PIN_GROUP(mmc_ctrl),
+ SH_PFC_PIN_GROUP(msiof0_clk),
+ SH_PFC_PIN_GROUP(msiof0_sync),
+ SH_PFC_PIN_GROUP(msiof0_ss1),
+ SH_PFC_PIN_GROUP(msiof0_ss2),
+ SH_PFC_PIN_GROUP(msiof0_rx),
+ SH_PFC_PIN_GROUP(msiof0_tx),
+ SH_PFC_PIN_GROUP(msiof1_clk),
+ SH_PFC_PIN_GROUP(msiof1_sync),
+ SH_PFC_PIN_GROUP(msiof1_ss1),
+ SH_PFC_PIN_GROUP(msiof1_ss2),
+ SH_PFC_PIN_GROUP(msiof1_rx),
+ SH_PFC_PIN_GROUP(msiof1_tx),
+ SH_PFC_PIN_GROUP(msiof1_clk_b),
+ SH_PFC_PIN_GROUP(msiof1_sync_b),
+ SH_PFC_PIN_GROUP(msiof1_ss1_b),
+ SH_PFC_PIN_GROUP(msiof1_ss2_b),
+ SH_PFC_PIN_GROUP(msiof1_rx_b),
+ SH_PFC_PIN_GROUP(msiof1_tx_b),
+ SH_PFC_PIN_GROUP(msiof2_clk),
+ SH_PFC_PIN_GROUP(msiof2_sync),
+ SH_PFC_PIN_GROUP(msiof2_ss1),
+ SH_PFC_PIN_GROUP(msiof2_ss2),
+ SH_PFC_PIN_GROUP(msiof2_rx),
+ SH_PFC_PIN_GROUP(msiof2_tx),
+ SH_PFC_PIN_GROUP(msiof2_clk_b),
+ SH_PFC_PIN_GROUP(msiof2_sync_b),
+ SH_PFC_PIN_GROUP(msiof2_ss1_b),
+ SH_PFC_PIN_GROUP(msiof2_ss2_b),
+ SH_PFC_PIN_GROUP(msiof2_rx_b),
+ SH_PFC_PIN_GROUP(msiof2_tx_b),
+ SH_PFC_PIN_GROUP(qspi_ctrl),
+ SH_PFC_PIN_GROUP(qspi_data2),
+ SH_PFC_PIN_GROUP(qspi_data4),
+ SH_PFC_PIN_GROUP(scif0_data),
+ SH_PFC_PIN_GROUP(scif0_clk),
+ SH_PFC_PIN_GROUP(scif0_data_b),
+ SH_PFC_PIN_GROUP(scif0_clk_b),
+ SH_PFC_PIN_GROUP(scif0_data_c),
+ SH_PFC_PIN_GROUP(scif0_data_d),
+ SH_PFC_PIN_GROUP(scif1_data),
+ SH_PFC_PIN_GROUP(scif1_clk),
+ SH_PFC_PIN_GROUP(scif1_data_b),
+ SH_PFC_PIN_GROUP(scif1_clk_b),
+ SH_PFC_PIN_GROUP(scif1_data_c),
+ SH_PFC_PIN_GROUP(scif1_clk_c),
+ SH_PFC_PIN_GROUP(scif2_data),
+ SH_PFC_PIN_GROUP(scif2_clk),
+ SH_PFC_PIN_GROUP(scif2_data_b),
+ SH_PFC_PIN_GROUP(scif2_clk_b),
+ SH_PFC_PIN_GROUP(scif2_data_c),
+ SH_PFC_PIN_GROUP(scif2_clk_c),
+ SH_PFC_PIN_GROUP(scif3_data),
+ SH_PFC_PIN_GROUP(scif3_clk),
+ SH_PFC_PIN_GROUP(scif3_data_b),
+ SH_PFC_PIN_GROUP(scif3_clk_b),
+ SH_PFC_PIN_GROUP(scif4_data),
+ SH_PFC_PIN_GROUP(scif4_data_b),
+ SH_PFC_PIN_GROUP(scif4_data_c),
+ SH_PFC_PIN_GROUP(scif4_data_d),
+ SH_PFC_PIN_GROUP(scif4_data_e),
+ SH_PFC_PIN_GROUP(scif5_data),
+ SH_PFC_PIN_GROUP(scif5_data_b),
+ SH_PFC_PIN_GROUP(scif5_data_c),
+ SH_PFC_PIN_GROUP(scif5_data_d),
+ SH_PFC_PIN_GROUP(scifa0_data),
+ SH_PFC_PIN_GROUP(scifa0_data_b),
+ SH_PFC_PIN_GROUP(scifa0_data_c),
+ SH_PFC_PIN_GROUP(scifa0_data_d),
+ SH_PFC_PIN_GROUP(scifa1_data),
+ SH_PFC_PIN_GROUP(scifa1_clk),
+ SH_PFC_PIN_GROUP(scifa1_data_b),
+ SH_PFC_PIN_GROUP(scifa1_clk_b),
+ SH_PFC_PIN_GROUP(scifa1_data_c),
+ SH_PFC_PIN_GROUP(scifa1_clk_c),
+ SH_PFC_PIN_GROUP(scifa2_data),
+ SH_PFC_PIN_GROUP(scifa2_clk),
+ SH_PFC_PIN_GROUP(scifa2_data_b),
+ SH_PFC_PIN_GROUP(scifa2_clk_b),
+ SH_PFC_PIN_GROUP(scifa3_data),
+ SH_PFC_PIN_GROUP(scifa3_clk),
+ SH_PFC_PIN_GROUP(scifa3_data_b),
+ SH_PFC_PIN_GROUP(scifa3_clk_b),
+ SH_PFC_PIN_GROUP(scifa4_data),
+ SH_PFC_PIN_GROUP(scifa4_data_b),
+ SH_PFC_PIN_GROUP(scifa4_data_c),
+ SH_PFC_PIN_GROUP(scifa4_data_d),
+ SH_PFC_PIN_GROUP(scifa5_data),
+ SH_PFC_PIN_GROUP(scifa5_data_b),
+ SH_PFC_PIN_GROUP(scifa5_data_c),
+ SH_PFC_PIN_GROUP(scifa5_data_d),
+ SH_PFC_PIN_GROUP(scifb0_data),
+ SH_PFC_PIN_GROUP(scifb0_clk),
+ SH_PFC_PIN_GROUP(scifb0_ctrl),
+ SH_PFC_PIN_GROUP(scifb1_data),
+ SH_PFC_PIN_GROUP(scifb1_clk),
+ SH_PFC_PIN_GROUP(scifb2_data),
+ SH_PFC_PIN_GROUP(scifb2_clk),
+ SH_PFC_PIN_GROUP(scifb2_ctrl),
+ SH_PFC_PIN_GROUP(sdhi0_data1),
+ SH_PFC_PIN_GROUP(sdhi0_data4),
+ SH_PFC_PIN_GROUP(sdhi0_ctrl),
+ SH_PFC_PIN_GROUP(sdhi0_cd),
+ SH_PFC_PIN_GROUP(sdhi0_wp),
+ SH_PFC_PIN_GROUP(sdhi1_data1),
+ SH_PFC_PIN_GROUP(sdhi1_data4),
+ SH_PFC_PIN_GROUP(sdhi1_ctrl),
+ SH_PFC_PIN_GROUP(sdhi1_cd),
+ SH_PFC_PIN_GROUP(sdhi1_wp),
+ SH_PFC_PIN_GROUP(sdhi2_data1),
+ SH_PFC_PIN_GROUP(sdhi2_data4),
+ SH_PFC_PIN_GROUP(sdhi2_ctrl),
+ SH_PFC_PIN_GROUP(sdhi2_cd),
+ SH_PFC_PIN_GROUP(sdhi2_wp),
+};
+
+static const char * const eth_groups[] = {
+ "eth_link",
+ "eth_magic",
+ "eth_mdio",
+ "eth_rmii",
+ "eth_link_b",
+ "eth_magic_b",
+ "eth_mdio_b",
+ "eth_rmii_b",
+};
+
+static const char * const hscif0_groups[] = {
+ "hscif0_data",
+ "hscif0_clk",
+ "hscif0_ctrl",
+ "hscif0_data_b",
+ "hscif0_clk_b",
+};
+
+static const char * const hscif1_groups[] = {
+ "hscif1_data",
+ "hscif1_clk",
+ "hscif1_ctrl",
+ "hscif1_data_b",
+ "hscif1_ctrl_b",
+};
+
+static const char * const hscif2_groups[] = {
+ "hscif2_data",
+ "hscif2_clk",
+ "hscif2_ctrl",
+};
+
+static const char * const i2c0_groups[] = {
+ "i2c0",
+ "i2c0_b",
+ "i2c0_c",
+ "i2c0_d",
+ "i2c0_e",
+};
+
+static const char * const i2c1_groups[] = {
+ "i2c1",
+ "i2c1_b",
+ "i2c1_c",
+ "i2c1_d",
+ "i2c1_e",
+};
+
+static const char * const i2c2_groups[] = {
+ "i2c2",
+ "i2c2_b",
+ "i2c2_c",
+ "i2c2_d",
+ "i2c2_e",
+};
+
+static const char * const i2c3_groups[] = {
+ "i2c3",
+ "i2c3_b",
+ "i2c3_c",
+ "i2c3_d",
+ "i2c3_e",
+};
+
+static const char * const i2c4_groups[] = {
+ "i2c4",
+ "i2c4_b",
+ "i2c4_c",
+ "i2c4_d",
+ "i2c4_e",
+};
+
+static const char * const intc_groups[] = {
+ "intc_irq0",
+ "intc_irq1",
+ "intc_irq2",
+ "intc_irq3",
+ "intc_irq4",
+ "intc_irq5",
+ "intc_irq6",
+ "intc_irq7",
+ "intc_irq8",
+ "intc_irq9",
+};
+
+static const char * const mmc_groups[] = {
+ "mmc_data1",
+ "mmc_data4",
+ "mmc_data8",
+ "mmc_ctrl",
+};
+
+static const char * const msiof0_groups[] = {
+ "msiof0_clk",
+ "msiof0_sync",
+ "msiof0_ss1",
+ "msiof0_ss2",
+ "msiof0_rx",
+ "msiof0_tx",
+};
+
+static const char * const msiof1_groups[] = {
+ "msiof1_clk",
+ "msiof1_sync",
+ "msiof1_ss1",
+ "msiof1_ss2",
+ "msiof1_rx",
+ "msiof1_tx",
+ "msiof1_clk_b",
+ "msiof1_sync_b",
+ "msiof1_ss1_b",
+ "msiof1_ss2_b",
+ "msiof1_rx_b",
+ "msiof1_tx_b",
+};
+
+static const char * const msiof2_groups[] = {
+ "msiof2_clk",
+ "msiof2_sync",
+ "msiof2_ss1",
+ "msiof2_ss2",
+ "msiof2_rx",
+ "msiof2_tx",
+ "msiof2_clk_b",
+ "msiof2_sync_b",
+ "msiof2_ss1_b",
+ "msiof2_ss2_b",
+ "msiof2_rx_b",
+ "msiof2_tx_b",
+};
+
+static const char * const qspi_groups[] = {
+ "qspi_ctrl",
+ "qspi_data2",
+ "qspi_data4",
+};
+
+static const char * const scif0_groups[] = {
+ "scif0_data",
+ "scif0_clk",
+ "scif0_data_b",
+ "scif0_clk_b",
+ "scif0_data_c",
+ "scif0_data_d",
+};
+
+static const char * const scif1_groups[] = {
+ "scif1_data",
+ "scif1_clk",
+ "scif1_data_b",
+ "scif1_clk_b",
+ "scif1_data_c",
+ "scif1_clk_c",
+};
+
+static const char * const scif2_groups[] = {
+ "scif2_data",
+ "scif2_clk",
+ "scif2_data_b",
+ "scif2_clk_b",
+ "scif2_data_c",
+ "scif2_clk_c",
+};
+
+static const char * const scif3_groups[] = {
+ "scif3_data",
+ "scif3_clk",
+ "scif3_data_b",
+ "scif3_clk_b",
+};
+
+static const char * const scif4_groups[] = {
+ "scif4_data",
+ "scif4_data_b",
+ "scif4_data_c",
+ "scif4_data_d",
+ "scif4_data_e",
+};
+
+static const char * const scif5_groups[] = {
+ "scif5_data",
+ "scif5_data_b",
+ "scif5_data_c",
+ "scif5_data_d",
+};
+
+static const char * const scifa0_groups[] = {
+ "scifa0_data",
+ "scifa0_data_b",
+ "scifa0_data_c",
+ "scifa0_data_d",
+};
+
+static const char * const scifa1_groups[] = {
+ "scifa1_data",
+ "scifa1_clk",
+ "scifa1_data_b",
+ "scifa1_clk_b",
+ "scifa1_data_c",
+ "scifa1_clk_c",
+};
+
+static const char * const scifa2_groups[] = {
+ "scifa2_data",
+ "scifa2_clk",
+ "scifa2_data_b",
+ "scifa2_clk_b",
+};
+
+static const char * const scifa3_groups[] = {
+ "scifa3_data",
+ "scifa3_clk",
+ "scifa3_data_b",
+ "scifa3_clk_b",
+};
+
+static const char * const scifa4_groups[] = {
+ "scifa4_data",
+ "scifa4_data_b",
+ "scifa4_data_c",
+ "scifa4_data_d",
+};
+
+static const char * const scifa5_groups[] = {
+ "scifa5_data",
+ "scifa5_data_b",
+ "scifa5_data_c",
+ "scifa5_data_d",
+};
+
+static const char * const scifb0_groups[] = {
+ "scifb0_data",
+ "scifb0_clk",
+ "scifb0_ctrl",
+};
+
+static const char * const scifb1_groups[] = {
+ "scifb1_data",
+ "scifb1_clk",
+};
+
+static const char * const scifb2_groups[] = {
+ "scifb2_data",
+ "scifb2_clk",
+ "scifb2_ctrl",
+};
+
+static const char * const sdhi0_groups[] = {
+ "sdhi0_data1",
+ "sdhi0_data4",
+ "sdhi0_ctrl",
+ "sdhi0_cd",
+ "sdhi0_wp",
+};
+
+static const char * const sdhi1_groups[] = {
+ "sdhi1_data1",
+ "sdhi1_data4",
+ "sdhi1_ctrl",
+ "sdhi1_cd",
+ "sdhi1_wp",
+};
+
+static const char * const sdhi2_groups[] = {
+ "sdhi2_data1",
+ "sdhi2_data4",
+ "sdhi2_ctrl",
+ "sdhi2_cd",
+ "sdhi2_wp",
+};
+
+static const struct sh_pfc_function pinmux_functions[] = {
+ SH_PFC_FUNCTION(eth),
+ SH_PFC_FUNCTION(hscif0),
+ SH_PFC_FUNCTION(hscif1),
+ SH_PFC_FUNCTION(hscif2),
+ SH_PFC_FUNCTION(i2c0),
+ SH_PFC_FUNCTION(i2c1),
+ SH_PFC_FUNCTION(i2c2),
+ SH_PFC_FUNCTION(i2c3),
+ SH_PFC_FUNCTION(i2c4),
+ SH_PFC_FUNCTION(intc),
+ SH_PFC_FUNCTION(mmc),
+ SH_PFC_FUNCTION(msiof0),
+ SH_PFC_FUNCTION(msiof1),
+ SH_PFC_FUNCTION(msiof2),
+ SH_PFC_FUNCTION(qspi),
+ SH_PFC_FUNCTION(scif0),
+ SH_PFC_FUNCTION(scif1),
+ SH_PFC_FUNCTION(scif2),
+ SH_PFC_FUNCTION(scif3),
+ SH_PFC_FUNCTION(scif4),
+ SH_PFC_FUNCTION(scif5),
+ SH_PFC_FUNCTION(scifa0),
+ SH_PFC_FUNCTION(scifa1),
+ SH_PFC_FUNCTION(scifa2),
+ SH_PFC_FUNCTION(scifa3),
+ SH_PFC_FUNCTION(scifa4),
+ SH_PFC_FUNCTION(scifa5),
+ SH_PFC_FUNCTION(scifb0),
+ SH_PFC_FUNCTION(scifb1),
+ SH_PFC_FUNCTION(scifb2),
+ SH_PFC_FUNCTION(sdhi0),
+ SH_PFC_FUNCTION(sdhi1),
+ SH_PFC_FUNCTION(sdhi2),
+};
+
+static const struct pinmux_cfg_reg pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("GPSR0", 0xE6060004, 32, 1) {
+ GP_0_31_FN, FN_IP2_17_16,
+ GP_0_30_FN, FN_IP2_15_14,
+ GP_0_29_FN, FN_IP2_13_12,
+ GP_0_28_FN, FN_IP2_11_10,
+ GP_0_27_FN, FN_IP2_9_8,
+ GP_0_26_FN, FN_IP2_7_6,
+ GP_0_25_FN, FN_IP2_5_4,
+ GP_0_24_FN, FN_IP2_3_2,
+ GP_0_23_FN, FN_IP2_1_0,
+ GP_0_22_FN, FN_IP1_31_30,
+ GP_0_21_FN, FN_IP1_29_28,
+ GP_0_20_FN, FN_IP1_27,
+ GP_0_19_FN, FN_IP1_26,
+ GP_0_18_FN, FN_A2,
+ GP_0_17_FN, FN_IP1_24,
+ GP_0_16_FN, FN_IP1_23_22,
+ GP_0_15_FN, FN_IP1_21_20,
+ GP_0_14_FN, FN_IP1_19_18,
+ GP_0_13_FN, FN_IP1_17_15,
+ GP_0_12_FN, FN_IP1_14_13,
+ GP_0_11_FN, FN_IP1_12_11,
+ GP_0_10_FN, FN_IP1_10_8,
+ GP_0_9_FN, FN_IP1_7_6,
+ GP_0_8_FN, FN_IP1_5_4,
+ GP_0_7_FN, FN_IP1_3_2,
+ GP_0_6_FN, FN_IP1_1_0,
+ GP_0_5_FN, FN_IP0_31_30,
+ GP_0_4_FN, FN_IP0_29_28,
+ GP_0_3_FN, FN_IP0_27_26,
+ GP_0_2_FN, FN_IP0_25,
+ GP_0_1_FN, FN_IP0_24,
+ GP_0_0_FN, FN_IP0_23_22, }
+ },
+ { PINMUX_CFG_REG("GPSR1", 0xE6060008, 32, 1) {
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ GP_1_25_FN, FN_DACK0,
+ GP_1_24_FN, FN_IP7_31,
+ GP_1_23_FN, FN_IP4_1_0,
+ GP_1_22_FN, FN_WE1_N,
+ GP_1_21_FN, FN_WE0_N,
+ GP_1_20_FN, FN_IP3_31,
+ GP_1_19_FN, FN_IP3_30,
+ GP_1_18_FN, FN_IP3_29_27,
+ GP_1_17_FN, FN_IP3_26_24,
+ GP_1_16_FN, FN_IP3_23_21,
+ GP_1_15_FN, FN_IP3_20_18,
+ GP_1_14_FN, FN_IP3_17_15,
+ GP_1_13_FN, FN_IP3_14_13,
+ GP_1_12_FN, FN_IP3_12,
+ GP_1_11_FN, FN_IP3_11,
+ GP_1_10_FN, FN_IP3_10,
+ GP_1_9_FN, FN_IP3_9_8,
+ GP_1_8_FN, FN_IP3_7_6,
+ GP_1_7_FN, FN_IP3_5_4,
+ GP_1_6_FN, FN_IP3_3_2,
+ GP_1_5_FN, FN_IP3_1_0,
+ GP_1_4_FN, FN_IP2_31_30,
+ GP_1_3_FN, FN_IP2_29_27,
+ GP_1_2_FN, FN_IP2_26_24,
+ GP_1_1_FN, FN_IP2_23_21,
+ GP_1_0_FN, FN_IP2_20_18, }
+ },
+ { PINMUX_CFG_REG("GPSR2", 0xE606000C, 32, 1) {
+ GP_2_31_FN, FN_IP6_7_6,
+ GP_2_30_FN, FN_IP6_5_4,
+ GP_2_29_FN, FN_IP6_3_2,
+ GP_2_28_FN, FN_IP6_1_0,
+ GP_2_27_FN, FN_IP5_31_30,
+ GP_2_26_FN, FN_IP5_29_28,
+ GP_2_25_FN, FN_IP5_27_26,
+ GP_2_24_FN, FN_IP5_25_24,
+ GP_2_23_FN, FN_IP5_23_22,
+ GP_2_22_FN, FN_IP5_21_20,
+ GP_2_21_FN, FN_IP5_19_18,
+ GP_2_20_FN, FN_IP5_17_16,
+ GP_2_19_FN, FN_IP5_15_14,
+ GP_2_18_FN, FN_IP5_13_12,
+ GP_2_17_FN, FN_IP5_11_9,
+ GP_2_16_FN, FN_IP5_8_6,
+ GP_2_15_FN, FN_IP5_5_4,
+ GP_2_14_FN, FN_IP5_3_2,
+ GP_2_13_FN, FN_IP5_1_0,
+ GP_2_12_FN, FN_IP4_31_30,
+ GP_2_11_FN, FN_IP4_29_28,
+ GP_2_10_FN, FN_IP4_27_26,
+ GP_2_9_FN, FN_IP4_25_23,
+ GP_2_8_FN, FN_IP4_22_20,
+ GP_2_7_FN, FN_IP4_19_18,
+ GP_2_6_FN, FN_IP4_17_16,
+ GP_2_5_FN, FN_IP4_15_14,
+ GP_2_4_FN, FN_IP4_13_12,
+ GP_2_3_FN, FN_IP4_11_10,
+ GP_2_2_FN, FN_IP4_9_8,
+ GP_2_1_FN, FN_IP4_7_5,
+ GP_2_0_FN, FN_IP4_4_2 }
+ },
+ { PINMUX_CFG_REG("GPSR3", 0xE6060010, 32, 1) {
+ GP_3_31_FN, FN_IP8_22_20,
+ GP_3_30_FN, FN_IP8_19_17,
+ GP_3_29_FN, FN_IP8_16_15,
+ GP_3_28_FN, FN_IP8_14_12,
+ GP_3_27_FN, FN_IP8_11_9,
+ GP_3_26_FN, FN_IP8_8_6,
+ GP_3_25_FN, FN_IP8_5_3,
+ GP_3_24_FN, FN_IP8_2_0,
+ GP_3_23_FN, FN_IP7_29_27,
+ GP_3_22_FN, FN_IP7_26_24,
+ GP_3_21_FN, FN_IP7_23_21,
+ GP_3_20_FN, FN_IP7_20_18,
+ GP_3_19_FN, FN_IP7_17_15,
+ GP_3_18_FN, FN_IP7_14_12,
+ GP_3_17_FN, FN_IP7_11_9,
+ GP_3_16_FN, FN_IP7_8_6,
+ GP_3_15_FN, FN_IP7_5_3,
+ GP_3_14_FN, FN_IP7_2_0,
+ GP_3_13_FN, FN_IP6_31_29,
+ GP_3_12_FN, FN_IP6_28_26,
+ GP_3_11_FN, FN_IP6_25_23,
+ GP_3_10_FN, FN_IP6_22_20,
+ GP_3_9_FN, FN_IP6_19_17,
+ GP_3_8_FN, FN_IP6_16,
+ GP_3_7_FN, FN_IP6_15,
+ GP_3_6_FN, FN_IP6_14,
+ GP_3_5_FN, FN_IP6_13,
+ GP_3_4_FN, FN_IP6_12,
+ GP_3_3_FN, FN_IP6_11,
+ GP_3_2_FN, FN_IP6_10,
+ GP_3_1_FN, FN_IP6_9,
+ GP_3_0_FN, FN_IP6_8 }
+ },
+ { PINMUX_CFG_REG("GPSR4", 0xE6060014, 32, 1) {
+ GP_4_31_FN, FN_IP11_17_16,
+ GP_4_30_FN, FN_IP11_15_14,
+ GP_4_29_FN, FN_IP11_13_11,
+ GP_4_28_FN, FN_IP11_10_8,
+ GP_4_27_FN, FN_IP11_7_6,
+ GP_4_26_FN, FN_IP11_5_3,
+ GP_4_25_FN, FN_IP11_2_0,
+ GP_4_24_FN, FN_IP10_31_30,
+ GP_4_23_FN, FN_IP10_29_27,
+ GP_4_22_FN, FN_IP10_26_24,
+ GP_4_21_FN, FN_IP10_23_21,
+ GP_4_20_FN, FN_IP10_20_18,
+ GP_4_19_FN, FN_IP10_17_15,
+ GP_4_18_FN, FN_IP10_14_12,
+ GP_4_17_FN, FN_IP10_11_9,
+ GP_4_16_FN, FN_IP10_8_6,
+ GP_4_15_FN, FN_IP10_5_3,
+ GP_4_14_FN, FN_IP10_2_0,
+ GP_4_13_FN, FN_IP9_30_28,
+ GP_4_12_FN, FN_IP9_27_25,
+ GP_4_11_FN, FN_IP9_24_22,
+ GP_4_10_FN, FN_IP9_21_19,
+ GP_4_9_FN, FN_IP9_18_17,
+ GP_4_8_FN, FN_IP9_16_15,
+ GP_4_7_FN, FN_IP9_14_12,
+ GP_4_6_FN, FN_IP9_11_9,
+ GP_4_5_FN, FN_IP9_8_6,
+ GP_4_4_FN, FN_IP9_5_3,
+ GP_4_3_FN, FN_IP9_2_0,
+ GP_4_2_FN, FN_IP8_31_29,
+ GP_4_1_FN, FN_IP8_28_26,
+ GP_4_0_FN, FN_IP8_25_23 }
+ },
+ { PINMUX_CFG_REG("GPSR5", 0xE6060018, 32, 1) {
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ GP_5_27_FN, FN_USB1_OVC,
+ GP_5_26_FN, FN_USB1_PWEN,
+ GP_5_25_FN, FN_USB0_OVC,
+ GP_5_24_FN, FN_USB0_PWEN,
+ GP_5_23_FN, FN_IP13_26_24,
+ GP_5_22_FN, FN_IP13_23_21,
+ GP_5_21_FN, FN_IP13_20_18,
+ GP_5_20_FN, FN_IP13_17_15,
+ GP_5_19_FN, FN_IP13_14_12,
+ GP_5_18_FN, FN_IP13_11_9,
+ GP_5_17_FN, FN_IP13_8_6,
+ GP_5_16_FN, FN_IP13_5_3,
+ GP_5_15_FN, FN_IP13_2_0,
+ GP_5_14_FN, FN_IP12_29_27,
+ GP_5_13_FN, FN_IP12_26_24,
+ GP_5_12_FN, FN_IP12_23_21,
+ GP_5_11_FN, FN_IP12_20_18,
+ GP_5_10_FN, FN_IP12_17_15,
+ GP_5_9_FN, FN_IP12_14_13,
+ GP_5_8_FN, FN_IP12_12_11,
+ GP_5_7_FN, FN_IP12_10_9,
+ GP_5_6_FN, FN_IP12_8_6,
+ GP_5_5_FN, FN_IP12_5_3,
+ GP_5_4_FN, FN_IP12_2_0,
+ GP_5_3_FN, FN_IP11_29_27,
+ GP_5_2_FN, FN_IP11_26_24,
+ GP_5_1_FN, FN_IP11_23_21,
+ GP_5_0_FN, FN_IP11_20_18 }
+ },
+ { PINMUX_CFG_REG("GPSR6", 0xE606001C, 32, 1) {
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ GP_6_25_FN, FN_IP0_21_20,
+ GP_6_24_FN, FN_IP0_19_18,
+ GP_6_23_FN, FN_IP0_17,
+ GP_6_22_FN, FN_IP0_16,
+ GP_6_21_FN, FN_IP0_15,
+ GP_6_20_FN, FN_IP0_14,
+ GP_6_19_FN, FN_IP0_13,
+ GP_6_18_FN, FN_IP0_12,
+ GP_6_17_FN, FN_IP0_11,
+ GP_6_16_FN, FN_IP0_10,
+ GP_6_15_FN, FN_IP0_9_8,
+ GP_6_14_FN, FN_IP0_0,
+ GP_6_13_FN, FN_SD1_DATA3,
+ GP_6_12_FN, FN_SD1_DATA2,
+ GP_6_11_FN, FN_SD1_DATA1,
+ GP_6_10_FN, FN_SD1_DATA0,
+ GP_6_9_FN, FN_SD1_CMD,
+ GP_6_8_FN, FN_SD1_CLK,
+ GP_6_7_FN, FN_SD0_WP,
+ GP_6_6_FN, FN_SD0_CD,
+ GP_6_5_FN, FN_SD0_DATA3,
+ GP_6_4_FN, FN_SD0_DATA2,
+ GP_6_3_FN, FN_SD0_DATA1,
+ GP_6_2_FN, FN_SD0_DATA0,
+ GP_6_1_FN, FN_SD0_CMD,
+ GP_6_0_FN, FN_SD0_CLK }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR0", 0xE6060020, 32,
+ 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1) {
+ /* IP0_31_30 [2] */
+ FN_D5, FN_SCIF4_RXD_B, FN_I2C0_SCL_D, 0,
+ /* IP0_29_28 [2] */
+ FN_D4, FN_I2C3_SDA_B, FN_SCIF5_TXD_B, 0,
+ /* IP0_27_26 [2] */
+ FN_D3, FN_I2C3_SCL_B, FN_SCIF5_RXD_B, 0,
+ /* IP0_25 [1] */
+ FN_D2, FN_SCIFA3_TXD_B,
+ /* IP0_24 [1] */
+ FN_D1, FN_SCIFA3_RXD_B,
+ /* IP0_23_22 [2] */
+ FN_D0, FN_SCIFA3_SCK_B, FN_IRQ4, 0,
+ /* IP0_21_20 [2] */
+ FN_MMC_D7, FN_SCIF0_TXD, FN_I2C2_SDA_B, FN_CAN1_TX,
+ /* IP0_19_18 [2] */
+ FN_MMC_D6, FN_SCIF0_RXD, FN_I2C2_SCL_B, FN_CAN1_RX,
+ /* IP0_17 [1] */
+ FN_MMC_D5, FN_SD2_WP,
+ /* IP0_16 [1] */
+ FN_MMC_D4, FN_SD2_CD,
+ /* IP0_15 [1] */
+ FN_MMC_D3, FN_SD2_DATA3,
+ /* IP0_14 [1] */
+ FN_MMC_D2, FN_SD2_DATA2,
+ /* IP0_13 [1] */
+ FN_MMC_D1, FN_SD2_DATA1,
+ /* IP0_12 [1] */
+ FN_MMC_D0, FN_SD2_DATA0,
+ /* IP0_11 [1] */
+ FN_MMC_CMD, FN_SD2_CMD,
+ /* IP0_10 [1] */
+ FN_MMC_CLK, FN_SD2_CLK,
+ /* IP0_9_8 [2] */
+ FN_SD1_WP, FN_IRQ7, FN_CAN0_TX, 0,
+ /* IP0_7 [1] */
+ 0, 0,
+ /* IP0_6 [1] */
+ 0, 0,
+ /* IP0_5 [1] */
+ 0, 0,
+ /* IP0_4 [1] */
+ 0, 0,
+ /* IP0_3 [1] */
+ 0, 0,
+ /* IP0_2 [1] */
+ 0, 0,
+ /* IP0_1 [1] */
+ 0, 0,
+ /* IP0_0 [1] */
+ FN_SD1_CD, FN_CAN0_RX, }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR1", 0xE6060024, 32,
+ 2, 2, 1, 1, 1, 1, 2, 2, 2, 3, 2, 2, 3, 2, 2,
+ 2, 2) {
+ /* IP1_31_30 [2] */
+ FN_A6, FN_SCIFB0_CTS_N, FN_SCIFA4_RXD_B, FN_TPUTO2_C,
+ /* IP1_29_28 [2] */
+ FN_A5, FN_SCIFB0_RXD, FN_PWM4_B, FN_TPUTO3_C,
+ /* IP1_27 [1] */
+ FN_A4, FN_SCIFB0_TXD,
+ /* IP1_26 [1] */
+ FN_A3, FN_SCIFB0_SCK,
+ /* IP1_25 [1] */
+ 0, 0,
+ /* IP1_24 [1] */
+ FN_A1, FN_SCIFB1_TXD,
+ /* IP1_23_22 [2] */
+ FN_A0, FN_SCIFB1_SCK, FN_PWM3_B, 0,
+ /* IP1_21_20 [2] */
+ FN_D15, FN_SCIFA1_TXD, FN_IIC0_SDA_B, 0,
+ /* IP1_19_18 [2] */
+ FN_D14, FN_SCIFA1_RXD, FN_IIC0_SCL_B, 0,
+ /* IP1_17_15 [3] */
+ FN_D13, FN_SCIFA1_SCK, FN_TANS1, FN_PWM2_C, FN_TCLK2_B,
+ 0, 0, 0,
+ /* IP1_14_13 [2] */
+ FN_D12, FN_HSCIF2_HRTS_N, FN_SCIF1_TXD_C, FN_I2C1_SDA_D,
+ /* IP1_12_11 [2] */
+ FN_D11, FN_HSCIF2_HCTS_N, FN_SCIF1_RXD_C, FN_I2C1_SCL_D,
+ /* IP1_10_8 [3] */
+ FN_D10, FN_HSCIF2_HSCK, FN_SCIF1_SCK_C, FN_IRQ6, FN_PWM5_C,
+ 0, 0, 0,
+ /* IP1_7_6 [2] */
+ FN_D9, FN_HSCIF2_HTX, FN_I2C1_SDA_B, 0,
+ /* IP1_5_4 [2] */
+ FN_D8, FN_HSCIF2_HRX, FN_I2C1_SCL_B, 0,
+ /* IP1_3_2 [2] */
+ FN_D7, FN_IRQ3, FN_TCLK1, FN_PWM6_B,
+ /* IP1_1_0 [2] */
+ FN_D6, FN_SCIF4_TXD_B, FN_I2C0_SDA_D, 0, }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR2", 0xE6060028, 32,
+ 2, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2) {
+ /* IP2_31_30 [2] */
+ FN_A20, FN_SPCLK, FN_MOUT1, 0,
+ /* IP2_29_27 [3] */
+ FN_A19, FN_MSIOF2_SS2, FN_PWM4, FN_TPUTO2,
+ FN_MOUT0, 0, 0, 0,
+ /* IP2_26_24 [3] */
+ FN_A18, FN_MSIOF2_SS1, FN_SCIF4_TXD_E, FN_CAN1_TX_B,
+ FN_AVB_AVTP_MATCH_B, 0, 0, 0,
+ /* IP2_23_21 [3] */
+ FN_A17, FN_MSIOF2_SYNC, FN_SCIF4_RXD_E, FN_CAN1_RX_B,
+ FN_AVB_AVTP_CAPTURE_B, 0, 0, 0,
+ /* IP2_20_18 [3] */
+ FN_A16, FN_MSIOF2_SCK, FN_HSCIF0_HSCK_B, FN_SPEEDIN,
+ FN_VSP, FN_CAN_CLK_C, FN_TPUTO2_B, 0,
+ /* IP2_17_16 [2] */
+ FN_A15, FN_MSIOF2_TXD, FN_HSCIF0_HTX_B, FN_DACK1,
+ /* IP2_15_14 [2] */
+ FN_A14, FN_MSIOF2_RXD, FN_HSCIF0_HRX_B, FN_DREQ1_N,
+ /* IP2_13_12 [2] */
+ FN_A13, FN_MSIOF1_SS2, FN_SCIFA5_TXD_B, 0,
+ /* IP2_11_10 [2] */
+ FN_A12, FN_MSIOF1_SS1, FN_SCIFA5_RXD_B, 0,
+ /* IP2_9_8 [2] */
+ FN_A11, FN_MSIOF1_SYNC, FN_IIC1_SDA_B, 0,
+ /* IP2_7_6 [2] */
+ FN_A10, FN_MSIOF1_SCK, FN_IIC1_SCL_B, 0,
+ /* IP2_5_4 [2] */
+ FN_A9, FN_MSIOF1_TXD, FN_SCIFA0_TXD_B, 0,
+ /* IP2_3_2 [2] */
+ FN_A8, FN_MSIOF1_RXD, FN_SCIFA0_RXD_B, 0,
+ /* IP2_1_0 [2] */
+ FN_A7, FN_SCIFB0_RTS_N, FN_SCIFA4_TXD_B, 0, }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR3", 0xE606002C, 32,
+ 1, 1, 3, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2, 2, 2, 2) {
+ /* IP3_31 [1] */
+ FN_RD_WR_N, FN_ATAG1_N,
+ /* IP3_30 [1] */
+ FN_RD_N, FN_ATACS11_N,
+ /* IP3_29_27 [3] */
+ FN_BS_N, FN_DRACK0, FN_PWM1_C, FN_TPUTO0_C, FN_ATACS01_N,
+ FN_MTS_N_B, 0, 0,
+ /* IP3_26_24 [3] */
+ FN_EX_CS5_N, FN_SCIFA2_TXD, FN_I2C2_SDA_E, FN_TS_SPSYNC_B,
+ FN_RIF0_D1, FN_FMIN, FN_SCIFB2_RTS_N, FN_STM_N_B,
+ /* IP3_23_21 [3] */
+ FN_EX_CS4_N, FN_SCIFA2_RXD, FN_I2C2_SCL_E, FN_TS_SDEN_B,
+ FN_RIF0_D0, FN_FMCLK, FN_SCIFB2_CTS_N, FN_SCKZ_B,
+ /* IP3_20_18 [3] */
+ FN_EX_CS3_N, FN_SCIFA2_SCK, FN_SCIF4_TXD_C, FN_TS_SCK_B,
+ FN_RIF0_CLK, FN_BPFCLK, FN_SCIFB2_SCK, FN_MDATA_B,
+ /* IP3_17_15 [3] */
+ FN_EX_CS2_N, FN_PWM0, FN_SCIF4_RXD_C, FN_TS_SDATA_B,
+ FN_RIF0_SYNC, FN_TPUTO3, FN_SCIFB2_TXD, FN_SDATA_B,
+ /* IP3_14_13 [2] */
+ FN_EX_CS1_N, FN_TPUTO3_B, FN_SCIFB2_RXD, FN_VI1_DATA11,
+ /* IP3_12 [1] */
+ FN_EX_CS0_N, FN_VI1_DATA10,
+ /* IP3_11 [1] */
+ FN_CS1_N_A26, FN_VI1_DATA9,
+ /* IP3_10 [1] */
+ FN_CS0_N, FN_VI1_DATA8,
+ /* IP3_9_8 [2] */
+ FN_A25, FN_SSL, FN_ATARD1_N, 0,
+ /* IP3_7_6 [2] */
+ FN_A24, FN_IO3, FN_EX_WAIT2, 0,
+ /* IP3_5_4 [2] */
+ FN_A23, FN_IO2, FN_MOUT6, FN_ATAWR1_N,
+ /* IP3_3_2 [2] */
+ FN_A22, FN_MISO_IO1, FN_MOUT5, FN_ATADIR1_N,
+ /* IP3_1_0 [2] */
+ FN_A21, FN_MOSI_IO0, FN_MOUT2, 0, }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR4", 0xE6060030, 32,
+ 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2) {
+ /* IP4_31_30 [2] */
+ FN_DU0_DG4, FN_LCDOUT12, FN_CC50_STATE12, 0,
+ /* IP4_29_28 [2] */
+ FN_DU0_DG3, FN_LCDOUT11, FN_CC50_STATE11, 0,
+ /* IP4_27_26 [2] */
+ FN_DU0_DG2, FN_LCDOUT10, FN_CC50_STATE10, 0,
+ /* IP4_25_23 [3] */
+ FN_DU0_DG1, FN_LCDOUT9, FN_SCIFA0_TXD_C, FN_I2C3_SDA_D,
+ FN_CC50_STATE9, 0, 0, 0,
+ /* IP4_22_20 [3] */
+ FN_DU0_DG0, FN_LCDOUT8, FN_SCIFA0_RXD_C, FN_I2C3_SCL_D,
+ FN_CC50_STATE8, 0, 0, 0,
+ /* IP4_19_18 [2] */
+ FN_DU0_DR7, FN_LCDOUT23, FN_CC50_STATE7, 0,
+ /* IP4_17_16 [2] */
+ FN_DU0_DR6, FN_LCDOUT22, FN_CC50_STATE6, 0,
+ /* IP4_15_14 [2] */
+ FN_DU0_DR5, FN_LCDOUT21, FN_CC50_STATE5, 0,
+ /* IP4_13_12 [2] */
+ FN_DU0_DR4, FN_LCDOUT20, FN_CC50_STATE4, 0,
+ /* IP4_11_10 [2] */
+ FN_DU0_DR3, FN_LCDOUT19, FN_CC50_STATE3, 0,
+ /* IP4_9_8 [2] */
+ FN_DU0_DR2, FN_LCDOUT18, FN_CC50_STATE2, 0,
+ /* IP4_7_5 [3] */
+ FN_DU0_DR1, FN_LCDOUT17, FN_SCIF5_TXD_C, FN_I2C2_SDA_D,
+ FN_CC50_STATE1, 0, 0, 0,
+ /* IP4_4_2 [3] */
+ FN_DU0_DR0, FN_LCDOUT16, FN_SCIF5_RXD_C, FN_I2C2_SCL_D,
+ FN_CC50_STATE0, 0, 0, 0,
+ /* IP4_1_0 [2] */
+ FN_EX_WAIT0, FN_CAN_CLK_B, FN_SCIF_CLK, FN_PWMFSW0, }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR5", 0xE6060034, 32,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2) {
+ /* IP5_31_30 [2] */
+ FN_DU0_EXHSYNC_DU0_HSYNC, FN_QSTH_QHS, FN_CC50_STATE27, 0,
+ /* IP5_29_28 [2] */
+ FN_DU0_DOTCLKOUT1, FN_QSTVB_QVE, FN_CC50_STATE26, 0,
+ /* IP5_27_26 [2] */
+ FN_DU0_DOTCLKOUT0, FN_QCLK, FN_CC50_STATE25, 0,
+ /* IP5_25_24 [2] */
+ FN_DU0_DOTCLKIN, FN_QSTVA_QVS, FN_CC50_STATE24, 0,
+ /* IP5_23_22 [2] */
+ FN_DU0_DB7, FN_LCDOUT7, FN_CC50_STATE23, 0,
+ /* IP5_21_20 [2] */
+ FN_DU0_DB6, FN_LCDOUT6, FN_CC50_STATE22, 0,
+ /* IP5_19_18 [2] */
+ FN_DU0_DB5, FN_LCDOUT5, FN_CC50_STATE21, 0,
+ /* IP5_17_16 [2] */
+ FN_DU0_DB4, FN_LCDOUT4, FN_CC50_STATE20, 0,
+ /* IP5_15_14 [2] */
+ FN_DU0_DB3, FN_LCDOUT3, FN_CC50_STATE19, 0,
+ /* IP5_13_12 [2] */
+ FN_DU0_DB2, FN_LCDOUT2, FN_CC50_STATE18, 0,
+ /* IP5_11_9 [3] */
+ FN_DU0_DB1, FN_LCDOUT1, FN_SCIFA4_TXD_C, FN_I2C4_SDA_D,
+ FN_CAN0_TX_C, FN_CC50_STATE17, 0, 0,
+ /* IP5_8_6 [3] */
+ FN_DU0_DB0, FN_LCDOUT0, FN_SCIFA4_RXD_C, FN_I2C4_SCL_D,
+ FN_CAN0_RX_C, FN_CC50_STATE16, 0, 0,
+ /* IP5_5_4 [2] */
+ FN_DU0_DG7, FN_LCDOUT15, FN_CC50_STATE15, 0,
+ /* IP5_3_2 [2] */
+ FN_DU0_DG6, FN_LCDOUT14, FN_CC50_STATE14, 0,
+ /* IP5_1_0 [2] */
+ FN_DU0_DG5, FN_LCDOUT13, FN_CC50_STATE13, 0, }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR6", 0xE6060038, 32,
+ 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+ 2, 2) {
+ /* IP6_31_29 [3] */
+ FN_ETH_MDIO, FN_VI0_G0, FN_MSIOF2_RXD_B, FN_IIC0_SCL_D,
+ FN_AVB_TX_CLK, FN_ADIDATA, FN_AD_DI, 0,
+ /* IP6_28_26 [3] */
+ FN_VI0_VSYNC_N, FN_SCIF0_TXD_B, FN_I2C0_SDA_C,
+ FN_AUDIO_CLKOUT_B, FN_AVB_TX_EN, 0, 0, 0,
+ /* IP6_25_23 [3] */
+ FN_VI0_HSYNC_N, FN_SCIF0_RXD_B, FN_I2C0_SCL_C, FN_IERX_C,
+ FN_AVB_COL, 0, 0, 0,
+ /* IP6_22_20 [3] */
+ FN_VI0_FIELD, FN_I2C3_SDA, FN_SCIFA5_TXD_C, FN_IECLK_C,
+ FN_AVB_RX_ER, 0, 0, 0,
+ /* IP6_19_17 [3] */
+ FN_VI0_CLKENB, FN_I2C3_SCL, FN_SCIFA5_RXD_C, FN_IETX_C,
+ FN_AVB_RXD7, 0, 0, 0,
+ /* IP6_16 [1] */
+ FN_VI0_DATA7_VI0_B7, FN_AVB_RXD6,
+ /* IP6_15 [1] */
+ FN_VI0_DATA6_VI0_B6, FN_AVB_RXD5,
+ /* IP6_14 [1] */
+ FN_VI0_DATA5_VI0_B5, FN_AVB_RXD4,
+ /* IP6_13 [1] */
+ FN_VI0_DATA4_VI0_B4, FN_AVB_RXD3,
+ /* IP6_12 [1] */
+ FN_VI0_DATA3_VI0_B3, FN_AVB_RXD2,
+ /* IP6_11 [1] */
+ FN_VI0_DATA2_VI0_B2, FN_AVB_RXD1,
+ /* IP6_10 [1] */
+ FN_VI0_DATA1_VI0_B1, FN_AVB_RXD0,
+ /* IP6_9 [1] */
+ FN_VI0_DATA0_VI0_B0, FN_AVB_RX_DV,
+ /* IP6_8 [1] */
+ FN_VI0_CLK, FN_AVB_RX_CLK,
+ /* IP6_7_6 [2] */
+ FN_DU0_CDE, FN_QPOLB, FN_CC50_STATE31, 0,
+ /* IP6_5_4 [2] */
+ FN_DU0_DISP, FN_QPOLA, FN_CC50_STATE30, 0,
+ /* IP6_3_2 [2] */
+ FN_DU0_EXODDF_DU0_ODDF_DISP_CDE, FN_QCPV_QDE, FN_CC50_STATE29,
+ /* IP6_1_0 [2] */
+ FN_DU0_EXVSYNC_DU0_VSYNC, FN_QSTB_QHE, FN_CC50_STATE28, 0, }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR7", 0xE606003C, 32,
+ 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) {
+ /* IP7_31 [1] */
+ FN_DREQ0_N, FN_SCIFB1_RXD,
+ /* IP7_30 [1] */
+ 0, 0,
+ /* IP7_29_27 [3] */
+ FN_ETH_TXD0, FN_VI0_R2, FN_SCIF3_RXD_B, FN_I2C4_SCL_E,
+ FN_AVB_GTX_CLK, FN_SSI_WS6_B, 0, 0,
+ /* IP7_26_24 [3] */
+ FN_ETH_MAGIC, FN_VI0_R1, FN_SCIF3_SCK_B, FN_AVB_TX_ER,
+ FN_SSI_SCK6_B, 0, 0, 0,
+ /* IP7_23_21 [3] */
+ FN_ETH_TX_EN, FN_VI0_R0, FN_SCIF2_TXD_C, FN_IIC1_SDA_D,
+ FN_AVB_TXD7, FN_SSI_SDATA5_B, 0, 0,
+ /* IP7_20_18 [3] */
+ FN_ETH_TXD1, FN_VI0_G7, FN_SCIF2_RXD_C, FN_IIC1_SCL_D,
+ FN_AVB_TXD6, FN_SSI_WS5_B, 0, 0,
+ /* IP7_17_15 [3] */
+ FN_ETH_REFCLK, FN_VI0_G6, FN_SCIF2_SCK_C, FN_AVB_TXD5,
+ FN_SSI_SCK5_B, 0, 0, 0,
+ /* IP7_14_12 [3] */
+ FN_ETH_LINK, FN_VI0_G5, FN_MSIOF2_SS2_B, FN_SCIF4_TXD_D,
+ FN_AVB_TXD4, FN_ADICHS2, 0, 0,
+ /* IP7_11_9 [3] */
+ FN_ETH_RXD1, FN_VI0_G4, FN_MSIOF2_SS1_B, FN_SCIF4_RXD_D,
+ FN_AVB_TXD3, FN_ADICHS1, 0, 0,
+ /* IP7_8_6 [3] */
+ FN_ETH_RXD0, FN_VI0_G3, FN_MSIOF2_SYNC_B, FN_CAN0_TX_B,
+ FN_AVB_TXD2, FN_ADICHS0, FN_AD_NCS_N, 0,
+ /* IP7_5_3 [3] */
+ FN_ETH_RX_ER, FN_VI0_G2, FN_MSIOF2_SCK_B, FN_CAN0_RX_B,
+ FN_AVB_TXD1, FN_ADICLK, FN_AD_CLK, 0,
+ /* IP7_2_0 [3] */
+ FN_ETH_CRS_DV, FN_VI0_G1, FN_MSIOF2_TXD_B, FN_IIC0_SDA_D,
+ FN_AVB_TXD0, FN_ADICS_SAMP, FN_AD_DO, 0, }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR8", 0xE6060040, 32,
+ 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3) {
+ /* IP8_31_29 [3] */
+ FN_MSIOF0_RXD, FN_SCIF5_RXD, FN_I2C2_SCL_C, FN_DU1_DR2,
+ FN_RIF1_D0_B, FN_TS_SDEN_D, FN_FMCLK_C, FN_RDS_CLK,
+ /* IP8_28_26 [3] */
+ FN_I2C1_SDA, FN_SCIF4_TXD, FN_IRQ5, FN_DU1_DR1,
+ FN_RIF1_CLK_B, FN_TS_SCK_D, FN_BPFCLK_C, 0,
+ /* IP8_25_23 [3] */
+ FN_I2C1_SCL, FN_SCIF4_RXD, FN_PWM5_B, FN_DU1_DR0,
+ FN_RIF1_SYNC_B, FN_TS_SDATA_D, FN_TPUTO1_B, 0,
+ /* IP8_22_20 [3] */
+ FN_I2C0_SDA, FN_SCIF0_TXD_C, FN_TPUTO0, FN_CAN_CLK,
+ FN_DVC_MUTE, FN_CAN1_TX_D, 0, 0,
+ /* IP8_19_17 [3] */
+ FN_I2C0_SCL, FN_SCIF0_RXD_C, FN_PWM5, FN_TCLK1_B,
+ FN_AVB_GTXREFCLK, FN_CAN1_RX_D, FN_TPUTO0_B, 0,
+ /* IP8_16_15 [2] */
+ FN_HSCIF0_HSCK, FN_SCIF_CLK_B, FN_AVB_CRS, FN_AUDIO_CLKC_B,
+ /* IP8_14_12 [3] */
+ FN_HSCIF0_HRTS_N, FN_VI0_R7, FN_SCIF0_TXD_D, FN_I2C0_SDA_E,
+ FN_AVB_PHY_INT, FN_SSI_SDATA8_B, 0, 0,
+ /* IP8_11_9 [3] */
+ FN_HSCIF0_HCTS_N, FN_VI0_R6, FN_SCIF0_RXD_D, FN_I2C0_SCL_E,
+ FN_AVB_MAGIC, FN_SSI_SDATA7_B, 0, 0,
+ /* IP8_8_6 [3] */
+ FN_HSCIF0_HTX, FN_VI0_R5, FN_I2C1_SDA_C, FN_AUDIO_CLKB_B,
+ FN_AVB_LINK, FN_SSI_WS78_B, 0, 0,
+ /* IP8_5_3 [3] */
+ FN_HSCIF0_HRX, FN_VI0_R4, FN_I2C1_SCL_C, FN_AUDIO_CLKA_B,
+ FN_AVB_MDIO, FN_SSI_SCK78_B, 0, 0,
+ /* IP8_2_0 [3] */
+ FN_ETH_MDC, FN_VI0_R3, FN_SCIF3_TXD_B, FN_I2C4_SDA_E,
+ FN_AVB_MDC, FN_SSI_SDATA6_B, 0, 0, }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR9", 0xE6060044, 32,
+ 1, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3) {
+ /* IP9_31 [1] */
+ 0, 0,
+ /* IP9_30_28 [3] */
+ FN_SCIF1_SCK, FN_PWM3, FN_TCLK2, FN_DU1_DG5,
+ FN_SSI_SDATA1_B, FN_CAN_TXCLK, FN_CC50_STATE34, 0,
+ /* IP9_27_25 [3] */
+ FN_HSCIF1_HRTS_N, FN_SCIFA4_TXD, FN_IERX, FN_DU1_DG4,
+ FN_SSI_WS1_B, FN_CAN_STEP0, FN_CC50_STATE33, 0,
+ /* IP9_24_22 [3] */
+ FN_HSCIF1_HCTS_N, FN_SCIFA4_RXD, FN_IECLK, FN_DU1_DG3,
+ FN_SSI_SCK1_B, FN_CAN_DEBUG_HW_TRIGGER, FN_CC50_STATE32, 0,
+ /* IP9_21_19 [3] */
+ FN_HSCIF1_HSCK, FN_PWM2, FN_IETX, FN_DU1_DG2,
+ FN_REMOCON_B, FN_SPEEDIN_B, FN_VSP_B, 0,
+ /* IP9_18_17 [2] */
+ FN_HSCIF1_HTX, FN_I2C4_SDA, FN_TPUTO1, FN_DU1_DG1,
+ /* IP9_16_15 [2] */
+ FN_HSCIF1_HRX, FN_I2C4_SCL, FN_PWM6, FN_DU1_DG0,
+ /* IP9_14_12 [3] */
+ FN_MSIOF0_SS2, FN_SCIFA0_TXD, FN_TS_SPSYNC, FN_DU1_DR7,
+ FN_RIF1_D1, FN_FMIN_B, FN_RDS_DATA_B, 0,
+ /* IP9_11_9 [3] */
+ FN_MSIOF0_SS1, FN_SCIFA0_RXD, FN_TS_SDEN, FN_DU1_DR6,
+ FN_RIF1_D0, FN_FMCLK_B, FN_RDS_CLK_B, 0,
+ /* IP9_8_6 [3] */
+ FN_MSIOF0_SYNC, FN_PWM1, FN_TS_SCK, FN_DU1_DR5,
+ FN_RIF1_CLK, FN_BPFCLK_B, 0, 0,
+ /* IP9_5_3 [3] */
+ FN_MSIOF0_SCK, FN_IRQ0, FN_TS_SDATA, FN_DU1_DR4,
+ FN_RIF1_SYNC, FN_TPUTO1_C, 0, 0,
+ /* IP9_2_0 [3] */
+ FN_MSIOF0_TXD, FN_SCIF5_TXD, FN_I2C2_SDA_C, FN_DU1_DR3,
+ FN_RIF1_D1_B, FN_TS_SPSYNC_D, FN_FMIN_C, FN_RDS_DATA, }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR10", 0xE6060048, 32,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) {
+ /* IP10_31_30 [2] */
+ FN_SSI_SCK5, FN_SCIFA3_SCK, FN_DU1_DOTCLKIN, FN_CAN_DEBUGOUT10,
+ /* IP10_29_27 [3] */
+ FN_I2C2_SDA, FN_SCIFA5_TXD, FN_DU1_DB7, FN_AUDIO_CLKOUT_C,
+ FN_CAN_DEBUGOUT9, 0, 0, 0,
+ /* IP10_26_24 [3] */
+ FN_I2C2_SCL, FN_SCIFA5_RXD, FN_DU1_DB6, FN_AUDIO_CLKC_C,
+ FN_SSI_SDATA4_B, FN_CAN_DEBUGOUT8, 0, 0,
+ /* IP10_23_21 [3] */
+ FN_SCIF3_TXD, FN_I2C1_SDA_E, FN_FMIN_D, FN_DU1_DB5,
+ FN_AUDIO_CLKB_C, FN_SSI_WS4_B, FN_CAN_DEBUGOUT7, FN_RDS_DATA_C,
+ /* IP10_20_18 [3] */
+ FN_SCIF3_RXD, FN_I2C1_SCL_E, FN_FMCLK_D, FN_DU1_DB4,
+ FN_AUDIO_CLKA_C, FN_SSI_SCK4_B, FN_CAN_DEBUGOUT6, FN_RDS_CLK_C,
+ /* IP10_17_15 [3] */
+ FN_SCIF3_SCK, FN_IRQ2, FN_BPFCLK_D, FN_DU1_DB3,
+ FN_SSI_SDATA9_B, FN_TANS2, FN_CAN_DEBUGOUT5, FN_CC50_OSCOUT,
+ /* IP10_14_12 [3] */
+ FN_SCIF2_SCK, FN_IRQ1, FN_DU1_DB2, FN_SSI_WS9_B,
+ FN_USB0_IDIN, FN_CAN_DEBUGOUT4, FN_CC50_STATE39, 0,
+ /* IP10_11_9 [3] */
+ FN_SCIF2_TXD, FN_IIC1_SDA, FN_DU1_DB1, FN_SSI_SCK9_B,
+ FN_USB0_OVC1, FN_CAN_DEBUGOUT3, FN_CC50_STATE38, 0,
+ /* IP10_8_6 [3] */
+ FN_SCIF2_RXD, FN_IIC1_SCL, FN_DU1_DB0, FN_SSI_SDATA2_B,
+ FN_USB0_EXTLP, FN_CAN_DEBUGOUT2, FN_CC50_STATE37, 0,
+ /* IP10_5_3 [3] */
+ FN_SCIF1_TXD, FN_IIC0_SDA, FN_DU1_DG7, FN_SSI_WS2_B,
+ FN_CAN_DEBUGOUT1, FN_CC50_STATE36, 0, 0,
+ /* IP10_2_0 [3] */
+ FN_SCIF1_RXD, FN_IIC0_SCL, FN_DU1_DG6, FN_SSI_SCK2_B,
+ FN_CAN_DEBUGOUT0, FN_CC50_STATE35, 0, 0, }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR11", 0xE606004C, 32,
+ 2, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3) {
+ /* IP11_31_30 [2] */
+ 0, 0, 0, 0,
+ /* IP11_29_27 [3] */
+ FN_SSI_SDATA0, FN_MSIOF1_SCK_B, FN_PWM0_B, FN_ADICLK_B,
+ FN_AD_CLK_B, 0, 0, 0,
+ /* IP11_26_24 [3] */
+ FN_SSI_WS0129, FN_MSIOF1_TXD_B, FN_SCIF5_TXD_D, FN_ADICS_SAMP_B,
+ FN_AD_DO_B, 0, 0, 0,
+ /* IP11_23_21 [3] */
+ FN_SSI_SCK0129, FN_MSIOF1_RXD_B, FN_SCIF5_RXD_D, FN_ADIDATA_B,
+ FN_AD_DI_B, FN_PCMWE_N, 0, 0,
+ /* IP11_20_18 [3] */
+ FN_SSI_SDATA7, FN_SCIFA2_TXD_B, FN_IRQ8, FN_AUDIO_CLKA_D,
+ FN_CAN_CLK_D, FN_PCMOE_N, 0, 0,
+ /* IP11_17_16 [2] */
+ FN_SSI_WS78, FN_SCIFA2_RXD_B, FN_IIC0_SCL_C, FN_DU1_CDE,
+ /* IP11_15_14 [2] */
+ FN_SSI_SCK78, FN_SCIFA2_SCK_B, FN_IIC0_SDA_C, FN_DU1_DISP,
+ /* IP11_13_11 [3] */
+ FN_SSI_SDATA6, FN_SCIFA1_TXD_B, FN_I2C4_SDA_C,
+ FN_DU1_EXODDF_DU1_ODDF_DISP_CDE, FN_CAN_DEBUGOUT15, 0, 0, 0,
+ /* IP11_10_8 [3] */
+ FN_SSI_WS6, FN_SCIFA1_RXD_B, FN_I2C4_SCL_C,
+ FN_DU1_EXVSYNC_DU1_VSYNC, FN_CAN_DEBUGOUT14, 0, 0, 0,
+ /* IP11_7_6 [2] */
+ FN_SSI_SCK6, FN_SCIFA1_SCK_B, FN_DU1_EXHSYNC_DU1_HSYNC,
+ FN_CAN_DEBUGOUT13,
+ /* IP11_5_3 [3] */
+ FN_SSI_SDATA5, FN_SCIFA3_TXD, FN_I2C3_SDA_C, FN_DU1_DOTCLKOUT1,
+ FN_CAN_DEBUGOUT12, 0, 0, 0,
+ /* IP11_2_0 [3] */
+ FN_SSI_WS5, FN_SCIFA3_RXD, FN_I2C3_SCL_C, FN_DU1_DOTCLKOUT0,
+ FN_CAN_DEBUGOUT11, 0, 0, 0, }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR12", 0xE6060050, 32,
+ 2, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3, 3) {
+ /* IP12_31_30 [2] */
+ 0, 0, 0, 0,
+ /* IP12_29_27 [3] */
+ FN_SSI_SCK2, FN_HSCIF1_HTX_B, FN_VI1_DATA2, FN_MDATA,
+ FN_ATAWR0_N, FN_ETH_RXD1_B, 0, 0,
+ /* IP12_26_24 [3] */
+ FN_SSI_SDATA1, FN_HSCIF1_HRX_B, FN_VI1_DATA1, FN_SDATA,
+ FN_ATAG0_N, FN_ETH_RXD0_B, 0, 0,
+ /* IP12_23_21 [3] */
+ FN_SSI_WS1, FN_SCIF1_TXD_B, FN_IIC1_SDA_C, FN_VI1_DATA0,
+ FN_CAN0_TX_D, FN_AVB_AVTP_MATCH, FN_ETH_RX_ER_B, 0,
+ /* IP12_20_18 [3] */
+ FN_SSI_SCK1, FN_SCIF1_RXD_B, FN_IIC1_SCL_C, FN_VI1_CLK,
+ FN_CAN0_RX_D, FN_AVB_AVTP_CAPTURE, FN_ETH_CRS_DV_B, 0,
+ /* IP12_17_15 [3] */
+ FN_SSI_SDATA8, FN_SCIF1_SCK_B, FN_PWM1_B, FN_IRQ9,
+ FN_REMOCON, FN_DACK2, FN_ETH_MDIO_B, 0,
+ /* IP12_14_13 [2] */
+ FN_SSI_SDATA4, FN_MLB_DAT, FN_IERX_B, FN_IRD_SCK,
+ /* IP12_12_11 [2] */
+ FN_SSI_WS4, FN_MLB_SIG, FN_IECLK_B, FN_IRD_RX,
+ /* IP12_10_9 [2] */
+ FN_SSI_SCK4, FN_MLB_CLK, FN_IETX_B, FN_IRD_TX,
+ /* IP12_8_6 [3] */
+ FN_SSI_SDATA3, FN_MSIOF1_SS2_B, FN_SCIFA1_TXD_C, FN_ADICHS2_B,
+ FN_CAN1_TX_C, FN_DREQ2_N, 0, 0,
+ /* IP12_5_3 [3] */
+ FN_SSI_WS34, FN_MSIOF1_SS1_B, FN_SCIFA1_RXD_C, FN_ADICHS1_B,
+ FN_CAN1_RX_C, FN_DACK1_B, 0, 0,
+ /* IP12_2_0 [3] */
+ FN_SSI_SCK34, FN_MSIOF1_SYNC_B, FN_SCIFA1_SCK_C, FN_ADICHS0_B,
+ FN_AD_NCS_N_B, FN_DREQ1_N_B, 0, 0, }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR13", 0xE6060054, 32,
+ 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3) {
+ /* IP13_31 [1] */
+ 0, 0,
+ /* IP13_30 [1] */
+ 0, 0,
+ /* IP13_29 [1] */
+ 0, 0,
+ /* IP13_28 [1] */
+ 0, 0,
+ /* IP13_27 [1] */
+ 0, 0,
+ /* IP13_26_24 [3] */
+ FN_AUDIO_CLKOUT, FN_I2C4_SDA_B, FN_SCIFA5_TXD_D, FN_VI1_VSYNC_N,
+ FN_TS_SPSYNC_C, FN_RIF0_D1_B, FN_FMIN_E, FN_RDS_DATA_D,
+ /* IP13_23_21 [3] */
+ FN_AUDIO_CLKC, FN_I2C4_SCL_B, FN_SCIFA5_RXD_D, FN_VI1_HSYNC_N,
+ FN_TS_SDEN_C, FN_RIF0_D0_B, FN_FMCLK_E, FN_RDS_CLK_D,
+ /* IP13_20_18 [3] */
+ FN_AUDIO_CLKB, FN_I2C0_SDA_B, FN_SCIFA4_TXD_D, FN_VI1_FIELD,
+ FN_TS_SCK_C, FN_RIF0_CLK_B, FN_BPFCLK_E, FN_ETH_MDC_B,
+ /* IP13_17_15 [3] */
+ FN_AUDIO_CLKA, FN_I2C0_SCL_B, FN_SCIFA4_RXD_D, FN_VI1_CLKENB,
+ FN_TS_SDATA_C, FN_RIF0_SYNC_B, FN_ETH_TXD0_B, 0,
+ /* IP13_14_12 [3] */
+ FN_SSI_SDATA9, FN_SCIF2_TXD_B, FN_I2C3_SDA_E, FN_VI1_DATA7,
+ FN_ATADIR0_N, FN_ETH_MAGIC_B, 0, 0,
+ /* IP13_11_9 [3] */
+ FN_SSI_WS9, FN_SCIF2_RXD_B, FN_I2C3_SCL_E, FN_VI1_DATA6,
+ FN_ATARD0_N, FN_ETH_TX_EN_B, 0, 0,
+ /* IP13_8_6 [3] */
+ FN_SSI_SCK9, FN_SCIF2_SCK_B, FN_PWM2_B, FN_VI1_DATA5,
+ FN_MTS_N, FN_EX_WAIT1, FN_ETH_TXD1_B, 0,
+ /* IP13_5_3 [2] */
+ FN_SSI_SDATA2, FN_HSCIF1_HRTS_N_B, FN_SCIFA0_TXD_D,
+ FN_VI1_DATA4, FN_STM_N, FN_ATACS10_N, FN_ETH_REFCLK_B, 0,
+ /* IP13_2_0 [3] */
+ FN_SSI_WS2, FN_HSCIF1_HCTS_N_B, FN_SCIFA0_RXD_D, FN_VI1_DATA3,
+ FN_SCKZ, FN_ATACS00_N, FN_ETH_LINK_B, 0, }
+ },
+ { PINMUX_CFG_REG_VAR("MOD_SEL", 0xE6060090, 32,
+ 2, 1, 2, 3, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3,
+ 2, 1) {
+ /* SEL_ADG [2] */
+ FN_SEL_ADG_0, FN_SEL_ADG_1, FN_SEL_ADG_2, FN_SEL_ADG_3,
+ /* SEL_ADI [1] */
+ FN_SEL_ADI_0, FN_SEL_ADI_1,
+ /* SEL_CAN [2] */
+ FN_SEL_CAN_0, FN_SEL_CAN_1, FN_SEL_CAN_2, FN_SEL_CAN_3,
+ /* SEL_DARC [3] */
+ FN_SEL_DARC_0, FN_SEL_DARC_1, FN_SEL_DARC_2, FN_SEL_DARC_3,
+ FN_SEL_DARC_4, 0, 0, 0,
+ /* SEL_DR0 [1] */
+ FN_SEL_DR0_0, FN_SEL_DR0_1,
+ /* SEL_DR1 [1] */
+ FN_SEL_DR1_0, FN_SEL_DR1_1,
+ /* SEL_DR2 [1] */
+ FN_SEL_DR2_0, FN_SEL_DR2_1,
+ /* SEL_DR3 [1] */
+ FN_SEL_DR3_0, FN_SEL_DR3_1,
+ /* SEL_ETH [1] */
+ FN_SEL_ETH_0, FN_SEL_ETH_1,
+ /* SLE_FSN [1] */
+ FN_SEL_FSN_0, FN_SEL_FSN_1,
+ /* SEL_IC200 [3] */
+ FN_SEL_I2C00_0, FN_SEL_I2C00_1, FN_SEL_I2C00_2, FN_SEL_I2C00_3,
+ FN_SEL_I2C00_4, 0, 0, 0,
+ /* SEL_I2C01 [3] */
+ FN_SEL_I2C01_0, FN_SEL_I2C01_1, FN_SEL_I2C01_2, FN_SEL_I2C01_3,
+ FN_SEL_I2C01_4, 0, 0, 0,
+ /* SEL_I2C02 [3] */
+ FN_SEL_I2C02_0, FN_SEL_I2C02_1, FN_SEL_I2C02_2, FN_SEL_I2C02_3,
+ FN_SEL_I2C02_4, 0, 0, 0,
+ /* SEL_I2C03 [3] */
+ FN_SEL_I2C03_0, FN_SEL_I2C03_1, FN_SEL_I2C03_2, FN_SEL_I2C03_3,
+ FN_SEL_I2C03_4, 0, 0, 0,
+ /* SEL_I2C04 [3] */
+ FN_SEL_I2C04_0, FN_SEL_I2C04_1, FN_SEL_I2C04_2, FN_SEL_I2C04_3,
+ FN_SEL_I2C04_4, 0, 0, 0,
+ /* SEL_IIC00 [2] */
+ FN_SEL_IIC00_0, FN_SEL_IIC00_1, FN_SEL_IIC00_2, FN_SEL_IIC00_3,
+ /* SEL_AVB [1] */
+ FN_SEL_AVB_0, FN_SEL_AVB_1, }
+ },
+ { PINMUX_CFG_REG_VAR("MOD_SEL2", 0xE6060094, 32,
+ 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1,
+ 2, 2, 2, 1, 1, 2) {
+ /* SEL_IEB [2] */
+ FN_SEL_IEB_0, FN_SEL_IEB_1, FN_SEL_IEB_2, 0,
+ /* SEL_IIC0 [2] */
+ FN_SEL_IIC01_0, FN_SEL_IIC01_1, FN_SEL_IIC01_2, FN_SEL_IIC01_3,
+ /* SEL_LBS [1] */
+ FN_SEL_LBS_0, FN_SEL_LBS_1,
+ /* SEL_MSI1 [1] */
+ FN_SEL_MSI1_0, FN_SEL_MSI1_1,
+ /* SEL_MSI2 [1] */
+ FN_SEL_MSI2_0, FN_SEL_MSI2_1,
+ /* SEL_RAD [1] */
+ FN_SEL_RAD_0, FN_SEL_RAD_1,
+ /* SEL_RCN [1] */
+ FN_SEL_RCN_0, FN_SEL_RCN_1,
+ /* SEL_RSP [1] */
+ FN_SEL_RSP_0, FN_SEL_RSP_1,
+ /* SEL_SCIFA0 [2] */
+ FN_SEL_SCIFA0_0, FN_SEL_SCIFA0_1, FN_SEL_SCIFA0_2,
+ FN_SEL_SCIFA0_3,
+ /* SEL_SCIFA1 [2] */
+ FN_SEL_SCIFA1_0, FN_SEL_SCIFA1_1, FN_SEL_SCIFA1_2, 0,
+ /* SEL_SCIFA2 [1] */
+ FN_SEL_SCIFA2_0, FN_SEL_SCIFA2_1,
+ /* SEL_SCIFA3 [1] */
+ FN_SEL_SCIFA3_0, FN_SEL_SCIFA3_1,
+ /* SEL_SCIFA4 [2] */
+ FN_SEL_SCIFA4_0, FN_SEL_SCIFA4_1, FN_SEL_SCIFA4_2,
+ FN_SEL_SCIFA4_3,
+ /* SEL_SCIFA5 [2] */
+ FN_SEL_SCIFA5_0, FN_SEL_SCIFA5_1, FN_SEL_SCIFA5_2,
+ FN_SEL_SCIFA5_3,
+ /* SEL_SPDM [1] */
+ FN_SEL_SPDM_0, FN_SEL_SPDM_1,
+ /* SEL_TMU [1] */
+ FN_SEL_TMU_0, FN_SEL_TMU_1,
+ /* SEL_TSIF0 [2] */
+ FN_SEL_TSIF0_0, FN_SEL_TSIF0_1, FN_SEL_TSIF0_2, FN_SEL_TSIF0_3,
+ /* SEL_CAN0 [2] */
+ FN_SEL_CAN0_0, FN_SEL_CAN0_1, FN_SEL_CAN0_2, FN_SEL_CAN0_3,
+ /* SEL_CAN1 [2] */
+ FN_SEL_CAN1_0, FN_SEL_CAN1_1, FN_SEL_CAN1_2, FN_SEL_CAN1_3,
+ /* SEL_HSCIF0 [1] */
+ FN_SEL_HSCIF0_0, FN_SEL_HSCIF0_1,
+ /* SEL_HSCIF1 [1] */
+ FN_SEL_HSCIF1_0, FN_SEL_HSCIF1_1,
+ /* SEL_RDS [2] */
+ FN_SEL_RDS_0, FN_SEL_RDS_1, FN_SEL_RDS_2, FN_SEL_RDS_3, }
+ },
+ { PINMUX_CFG_REG_VAR("MOD_SEL3", 0xE6060098, 32,
+ 2, 2, 2, 1, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) {
+ /* SEL_SCIF0 [2] */
+ FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2, FN_SEL_SCIF0_3,
+ /* SEL_SCIF1 [2] */
+ FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2, 0,
+ /* SEL_SCIF2 [2] */
+ FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2, 0,
+ /* SEL_SCIF3 [1] */
+ FN_SEL_SCIF3_0, FN_SEL_SCIF3_1,
+ /* SEL_SCIF4 [3] */
+ FN_SEL_SCIF4_0, FN_SEL_SCIF4_1, FN_SEL_SCIF4_2, FN_SEL_SCIF4_3,
+ FN_SEL_SCIF4_4, 0, 0, 0,
+ /* SEL_SCIF5 [2] */
+ FN_SEL_SCIF5_0, FN_SEL_SCIF5_1, FN_SEL_SCIF5_2, FN_SEL_SCIF5_3,
+ /* SEL_SSI1 [1] */
+ FN_SEL_SSI1_0, FN_SEL_SSI1_1,
+ /* SEL_SSI2 [1] */
+ FN_SEL_SSI2_0, FN_SEL_SSI2_1,
+ /* SEL_SSI4 [1] */
+ FN_SEL_SSI4_0, FN_SEL_SSI4_1,
+ /* SEL_SSI5 [1] */
+ FN_SEL_SSI5_0, FN_SEL_SSI5_1,
+ /* SEL_SSI6 [1] */
+ FN_SEL_SSI6_0, FN_SEL_SSI6_1,
+ /* SEL_SSI7 [1] */
+ FN_SEL_SSI7_0, FN_SEL_SSI7_1,
+ /* SEL_SSI8 [1] */
+ FN_SEL_SSI8_0, FN_SEL_SSI8_1,
+ /* SEL_SSI9 [1] */
+ FN_SEL_SSI9_0, FN_SEL_SSI9_1,
+ /* RESERVED [1] */
+ 0, 0,
+ /* RESERVED [1] */
+ 0, 0,
+ /* RESERVED [1] */
+ 0, 0,
+ /* RESERVED [1] */
+ 0, 0,
+ /* RESERVED [1] */
+ 0, 0,
+ /* RESERVED [1] */
+ 0, 0,
+ /* RESERVED [1] */
+ 0, 0,
+ /* RESERVED [1] */
+ 0, 0,
+ /* RESERVED [1] */
+ 0, 0,
+ /* RESERVED [1] */
+ 0, 0,
+ /* RESERVED [1] */
+ 0, 0,
+ /* RESERVED [1] */
+ 0, 0, }
+ },
+ { },
+};
+
+const struct sh_pfc_soc_info r8a7794_pinmux_info = {
+ .name = "r8a77940_pfc",
+ .unlock_reg = 0xe6060000, /* PMMR */
+
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .pins = pinmux_pins,
+ .nr_pins = ARRAY_SIZE(pinmux_pins),
+ .groups = pinmux_groups,
+ .nr_groups = ARRAY_SIZE(pinmux_groups),
+ .functions = pinmux_functions,
+ .nr_functions = ARRAY_SIZE(pinmux_functions),
+
+ .cfg_regs = pinmux_config_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c
index 072e7c62cab7..ff678966008b 100644
--- a/drivers/pinctrl/sh-pfc/pinctrl.c
+++ b/drivers/pinctrl/sh-pfc/pinctrl.c
@@ -625,8 +625,8 @@ int sh_pfc_register_pinctrl(struct sh_pfc *pfc)
pmx->pctl_desc.npins = pfc->info->nr_pins;
pmx->pctl = pinctrl_register(&pmx->pctl_desc, pfc->dev, pmx);
- if (pmx->pctl == NULL)
- return -EINVAL;
+ if (IS_ERR(pmx->pctl))
+ return PTR_ERR(pmx->pctl);
return 0;
}
diff --git a/drivers/pinctrl/sirf/Makefile b/drivers/pinctrl/sirf/Makefile
index 3ffc475ce40c..fd58e0bacb2a 100644
--- a/drivers/pinctrl/sirf/Makefile
+++ b/drivers/pinctrl/sirf/Makefile
@@ -3,3 +3,4 @@
obj-y += pinctrl-sirf.o
obj-y += pinctrl-prima2.o
obj-y += pinctrl-atlas6.o
+obj-y += pinctrl-atlas7.o
diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c
new file mode 100644
index 000000000000..9384e0aa3996
--- /dev/null
+++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c
@@ -0,0 +1,4637 @@
+/*
+ * pinctrl pads, groups, functions for CSR SiRFatlasVII
+ *
+ * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
+ * company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/gpio.h>
+
+/* Definition of Pad&Mux Properties */
+#define N 0
+
+/* The Bank contains input-disable regisgers */
+#define BANK_DS 0
+
+/* Clear Register offset */
+#define CLR_REG(r) ((r) + 0x04)
+
+/* Definition of multiple function select register */
+#define FUNC_CLEAR_MASK 0x7
+#define FUNC_GPIO 0
+#define FUNC_ANALOGUE 0x8
+#define ANA_CLEAR_MASK 0x1
+
+/* The Atlas7's Pad Type List */
+enum altas7_pad_type {
+ PAD_T_4WE_PD = 0, /* ZIO_PAD3V_4WE_PD */
+ PAD_T_4WE_PU, /* ZIO_PAD3V_4WE_PD */
+ PAD_T_16ST, /* ZIO_PAD3V_SDCLK_PD */
+ PAD_T_M31_0204_PD, /* PRDW0204SDGZ_M311311_PD */
+ PAD_T_M31_0204_PU, /* PRDW0204SDGZ_M311311_PU */
+ PAD_T_M31_0610_PD, /* PRUW0610SDGZ_M311311_PD */
+ PAD_T_M31_0610_PU, /* PRUW0610SDGZ_M311311_PU */
+ PAD_T_AD, /* PRDWUWHW08SCDG_HZ */
+};
+
+/* Raw value of Driver-Strength Bits */
+#define DS3 BIT(3)
+#define DS2 BIT(2)
+#define DS1 BIT(1)
+#define DS0 BIT(0)
+#define DSZ 0
+
+/* Drive-Strength Intermediate Values */
+#define DS_NULL -1
+#define DS_1BIT_IM_VAL DS0
+#define DS_1BIT_MASK 0x1
+#define DS_2BIT_IM_VAL (DS1 | DS0)
+#define DS_2BIT_MASK 0x3
+#define DS_4BIT_IM_VAL (DS3 | DS2 | DS1 | DS0)
+#define DS_4BIT_MASK 0xf
+
+/* The Drive-Strength of 4WE Pad DS1 0 CO */
+#define DS_4WE_3 (DS1 | DS0) /* 1 1 3 */
+#define DS_4WE_2 (DS1) /* 1 0 2 */
+#define DS_4WE_1 (DS0) /* 0 1 1 */
+#define DS_4WE_0 (DSZ) /* 0 0 0 */
+
+/* The Drive-Strength of 16st Pad DS3 2 1 0 CO */
+#define DS_16ST_15 (DS3 | DS2 | DS1 | DS0) /* 1 1 1 1 15 */
+#define DS_16ST_14 (DS3 | DS2 | DS0) /* 1 1 0 1 13 */
+#define DS_16ST_13 (DS3 | DS2 | DS1) /* 1 1 1 0 14 */
+#define DS_16ST_12 (DS2 | DS1 | DS0) /* 0 1 1 1 7 */
+#define DS_16ST_11 (DS2 | DS0) /* 0 1 0 1 5 */
+#define DS_16ST_10 (DS3 | DS1 | DS0) /* 1 0 1 1 11 */
+#define DS_16ST_9 (DS3 | DS0) /* 1 0 0 1 9 */
+#define DS_16ST_8 (DS1 | DS0) /* 0 0 1 1 3 */
+#define DS_16ST_7 (DS2 | DS1) /* 0 1 1 0 6 */
+#define DS_16ST_6 (DS3 | DS2) /* 1 1 0 0 12 */
+#define DS_16ST_5 (DS2) /* 0 1 0 0 4 */
+#define DS_16ST_4 (DS3 | DS1) /* 1 0 1 0 10 */
+#define DS_16ST_3 (DS1) /* 0 0 1 0 2 */
+#define DS_16ST_2 (DS0) /* 0 0 0 1 1 */
+#define DS_16ST_1 (DSZ) /* 0 0 0 0 0 */
+#define DS_16ST_0 (DS3) /* 1 0 0 0 8 */
+
+/* The Drive-Strength of M31 Pad DS0 CO */
+#define DS_M31_0 (DSZ) /* 0 0 */
+#define DS_M31_1 (DS0) /* 1 1 */
+
+/* Raw values of Pull Option Bits */
+#define PUN BIT(1)
+#define PD BIT(0)
+#define PE BIT(0)
+#define PZ 0
+
+/* Definition of Pull Types */
+#define PULL_UP 0
+#define HIGH_HYSTERESIS 1
+#define HIGH_Z 2
+#define PULL_DOWN 3
+#define PULL_DISABLE 4
+#define PULL_ENABLE 5
+#define PULL_UNKNOWN -1
+
+/* Pull Options for 4WE Pad PUN PD CO */
+#define P4WE_PULL_MASK 0x3
+#define P4WE_PULL_DOWN (PUN | PD) /* 1 1 3 */
+#define P4WE_HIGH_Z (PUN) /* 1 0 2 */
+#define P4WE_HIGH_HYSTERESIS (PD) /* 0 1 1 */
+#define P4WE_PULL_UP (PZ) /* 0 0 0 */
+
+/* Pull Options for 16ST Pad PUN PD CO */
+#define P16ST_PULL_MASK 0x3
+#define P16ST_PULL_DOWN (PUN | PD) /* 1 1 3 */
+#define P16ST_HIGH_Z (PUN) /* 1 0 2 */
+#define P16ST_PULL_UP (PZ) /* 0 0 0 */
+
+/* Pull Options for M31 Pad PE */
+#define PM31_PULL_MASK 0x1
+#define PM31_PULL_ENABLED (PE) /* 1 */
+#define PM31_PULL_DISABLED (PZ) /* 0 */
+
+/* Pull Options for A/D Pad PUN PD CO */
+#define PANGD_PULL_MASK 0x3
+#define PANGD_PULL_DOWN (PUN | PD) /* 1 1 3 */
+#define PANGD_HIGH_Z (PUN) /* 1 0 2 */
+#define PANGD_PULL_UP (PZ) /* 0 0 0 */
+
+/* Definition of Input Disable */
+#define DI_MASK 0x1
+#define DI_DISABLE 0x1
+#define DI_ENABLE 0x0
+
+/* Definition of Input Disable Value */
+#define DIV_MASK 0x1
+#define DIV_DISABLE 0x1
+#define DIV_ENABLE 0x0
+
+struct dt_params {
+ const char *property;
+ int value;
+};
+
+/**
+ * struct atlas7_pad_conf - Atlas7 Pad Configuration
+ * @id The ID of this Pad.
+ * @type: The type of this Pad.
+ * @mux_reg: The mux register offset.
+ * This register contains the mux.
+ * @pupd_reg: The pull-up/down register offset.
+ * @drvstr_reg: The drive-strength register offset.
+ * @ad_ctrl_reg: The Analogue/Digital Control register.
+ *
+ * @mux_bit: The start bit of mux register.
+ * @pupd_bit: The start bit of pull-up/down register.
+ * @drvstr_bit: The start bit of drive-strength register.
+ * @ad_ctrl_bit: The start bit of analogue/digital register.
+ */
+struct atlas7_pad_config {
+ const u32 id;
+ u32 type;
+ u32 mux_reg;
+ u32 pupd_reg;
+ u32 drvstr_reg;
+ u32 ad_ctrl_reg;
+ /* bits in register */
+ u8 mux_bit;
+ u8 pupd_bit;
+ u8 drvstr_bit;
+ u8 ad_ctrl_bit;
+};
+
+#define PADCONF(pad, t, mr, pr, dsr, adr, mb, pb, dsb, adb) \
+ { \
+ .id = pad, \
+ .type = t, \
+ .mux_reg = mr, \
+ .pupd_reg = pr, \
+ .drvstr_reg = dsr, \
+ .ad_ctrl_reg = adr, \
+ .mux_bit = mb, \
+ .pupd_bit = pb, \
+ .drvstr_bit = dsb, \
+ .ad_ctrl_bit = adb, \
+ }
+
+/**
+ * struct atlas7_pad_mux - Atlas7 mux
+ * @bank: The bank of this pad's registers on.
+ * @pin : The ID of this Pad.
+ * @func: The mux func on this Pad.
+ * @dinput_reg: The Input-Disable register offset.
+ * @dinput_bit: The start bit of Input-Disable register.
+ * @dinput_val_reg: The Input-Disable-value register offset.
+ * This register is used to set the value of this pad
+ * if this pad was disabled.
+ * @dinput_val_bit: The start bit of Input-Disable Value register.
+ */
+struct atlas7_pad_mux {
+ u32 bank;
+ u32 pin;
+ u32 func;
+ u32 dinput_reg;
+ u32 dinput_bit;
+ u32 dinput_val_reg;
+ u32 dinput_val_bit;
+};
+
+#define MUX(b, pad, f, dr, db, dvr, dvb) \
+ { \
+ .bank = b, \
+ .pin = pad, \
+ .func = f, \
+ .dinput_reg = dr, \
+ .dinput_bit = db, \
+ .dinput_val_reg = dvr, \
+ .dinput_val_bit = dvb, \
+ }
+
+struct atlas7_grp_mux {
+ unsigned int group;
+ unsigned int pad_mux_count;
+ const struct atlas7_pad_mux *pad_mux_list;
+};
+
+ /**
+ * struct sirfsoc_pin_group - describes a SiRFprimaII pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of discrete physical pins used in this group, taken
+ * from the driver-local pin enumeration space
+ * @num_pins: the number of pins in this group array, i.e. the number of
+ * elements in .pins so we can iterate over that array
+ */
+struct atlas7_pin_group {
+ const char *name;
+ const unsigned int *pins;
+ const unsigned num_pins;
+};
+
+#define GROUP(n, p) \
+ { \
+ .name = n, \
+ .pins = p, \
+ .num_pins = ARRAY_SIZE(p), \
+ }
+
+struct atlas7_pmx_func {
+ const char *name;
+ const char * const *groups;
+ const unsigned num_groups;
+ const struct atlas7_grp_mux *grpmux;
+};
+
+#define FUNCTION(n, g, m) \
+ { \
+ .name = n, \
+ .groups = g, \
+ .num_groups = ARRAY_SIZE(g), \
+ .grpmux = m, \
+ }
+
+struct atlas7_pinctrl_data {
+ struct pinctrl_pin_desc *pads;
+ int pads_cnt;
+ struct atlas7_pin_group *grps;
+ int grps_cnt;
+ struct atlas7_pmx_func *funcs;
+ int funcs_cnt;
+ struct atlas7_pad_config *confs;
+ int confs_cnt;
+};
+
+/* Platform info of atlas7 pinctrl */
+#define ATLAS7_PINCTRL_REG_BANKS 2
+#define ATLAS7_PINCTRL_BANK_0_PINS 18
+
+/**
+ * Atlas7 GPIO Chip
+ */
+
+#define NGPIO_OF_BANK 32
+#define GPIO_TO_BANK(gpio) ((gpio) / NGPIO_OF_BANK)
+
+/* Registers of GPIO Controllers */
+#define ATLAS7_GPIO_BASE(g, b) ((g)->reg + 0x100 * (b))
+#define ATLAS7_GPIO_CTRL(b, i) ((b)->base + 4 * (i))
+#define ATLAS7_GPIO_INT_STATUS(b) ((b)->base + 0x8C)
+
+/* Definition bits of GPIO Control Registers */
+#define ATLAS7_GPIO_CTL_INTR_LOW_MASK BIT(0)
+#define ATLAS7_GPIO_CTL_INTR_HIGH_MASK BIT(1)
+#define ATLAS7_GPIO_CTL_INTR_TYPE_MASK BIT(2)
+#define ATLAS7_GPIO_CTL_INTR_EN_MASK BIT(3)
+#define ATLAS7_GPIO_CTL_INTR_STATUS_MASK BIT(4)
+#define ATLAS7_GPIO_CTL_OUT_EN_MASK BIT(5)
+#define ATLAS7_GPIO_CTL_DATAOUT_MASK BIT(6)
+#define ATLAS7_GPIO_CTL_DATAIN_MASK BIT(7)
+
+struct atlas7_gpio_bank {
+ struct pinctrl_dev *pctldev;
+ int id;
+ int irq;
+ void __iomem *base;
+ unsigned int gpio_offset;
+ unsigned int ngpio;
+ const unsigned int *gpio_pins;
+};
+
+struct atlas7_gpio_chip {
+ const char *name;
+ void __iomem *reg;
+ struct clk *clk;
+ int nbank;
+ spinlock_t lock;
+ struct gpio_chip chip;
+ struct atlas7_gpio_bank banks[0];
+};
+
+static inline struct atlas7_gpio_chip *to_atlas7_gpio(struct gpio_chip *gc)
+{
+ return container_of(gc, struct atlas7_gpio_chip, chip);
+}
+
+/**
+ * @dev: a pointer back to containing device
+ * @virtbase: the offset to the controller in virtual memory
+ */
+struct atlas7_pmx {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+ struct pinctrl_desc pctl_desc;
+ struct atlas7_pinctrl_data *pctl_data;
+ void __iomem *regs[ATLAS7_PINCTRL_REG_BANKS];
+};
+
+/*
+ * Pad list for the pinmux subsystem
+ * refer to A7DA IO Summary - CS-314158-DD-4E.xls
+ */
+
+/*Pads in IOC RTC & TOP */
+static const struct pinctrl_pin_desc atlas7_ioc_pads[] = {
+ /* RTC PADs */
+ PINCTRL_PIN(0, "rtc_gpio_0"),
+ PINCTRL_PIN(1, "rtc_gpio_1"),
+ PINCTRL_PIN(2, "rtc_gpio_2"),
+ PINCTRL_PIN(3, "rtc_gpio_3"),
+ PINCTRL_PIN(4, "low_bat_ind_b"),
+ PINCTRL_PIN(5, "on_key_b"),
+ PINCTRL_PIN(6, "ext_on"),
+ PINCTRL_PIN(7, "mem_on"),
+ PINCTRL_PIN(8, "core_on"),
+ PINCTRL_PIN(9, "io_on"),
+ PINCTRL_PIN(10, "can0_tx"),
+ PINCTRL_PIN(11, "can0_rx"),
+ PINCTRL_PIN(12, "spi0_clk"),
+ PINCTRL_PIN(13, "spi0_cs_b"),
+ PINCTRL_PIN(14, "spi0_io_0"),
+ PINCTRL_PIN(15, "spi0_io_1"),
+ PINCTRL_PIN(16, "spi0_io_2"),
+ PINCTRL_PIN(17, "spi0_io_3"),
+
+ /* TOP PADs */
+ PINCTRL_PIN(18, "spi1_en"),
+ PINCTRL_PIN(19, "spi1_clk"),
+ PINCTRL_PIN(20, "spi1_din"),
+ PINCTRL_PIN(21, "spi1_dout"),
+ PINCTRL_PIN(22, "trg_spi_clk"),
+ PINCTRL_PIN(23, "trg_spi_di"),
+ PINCTRL_PIN(24, "trg_spi_do"),
+ PINCTRL_PIN(25, "trg_spi_cs_b"),
+ PINCTRL_PIN(26, "trg_acq_d1"),
+ PINCTRL_PIN(27, "trg_irq_b"),
+ PINCTRL_PIN(28, "trg_acq_d0"),
+ PINCTRL_PIN(29, "trg_acq_clk"),
+ PINCTRL_PIN(30, "trg_shutdown_b_out"),
+ PINCTRL_PIN(31, "sdio2_clk"),
+ PINCTRL_PIN(32, "sdio2_cmd"),
+ PINCTRL_PIN(33, "sdio2_dat_0"),
+ PINCTRL_PIN(34, "sdio2_dat_1"),
+ PINCTRL_PIN(35, "sdio2_dat_2"),
+ PINCTRL_PIN(36, "sdio2_dat_3"),
+ PINCTRL_PIN(37, "df_ad_7"),
+ PINCTRL_PIN(38, "df_ad_6"),
+ PINCTRL_PIN(39, "df_ad_5"),
+ PINCTRL_PIN(40, "df_ad_4"),
+ PINCTRL_PIN(41, "df_ad_3"),
+ PINCTRL_PIN(42, "df_ad_2"),
+ PINCTRL_PIN(43, "df_ad_1"),
+ PINCTRL_PIN(44, "df_ad_0"),
+ PINCTRL_PIN(45, "df_dqs"),
+ PINCTRL_PIN(46, "df_cle"),
+ PINCTRL_PIN(47, "df_ale"),
+ PINCTRL_PIN(48, "df_we_b"),
+ PINCTRL_PIN(49, "df_re_b"),
+ PINCTRL_PIN(50, "df_ry_by"),
+ PINCTRL_PIN(51, "df_cs_b_1"),
+ PINCTRL_PIN(52, "df_cs_b_0"),
+ PINCTRL_PIN(53, "l_pclk"),
+ PINCTRL_PIN(54, "l_lck"),
+ PINCTRL_PIN(55, "l_fck"),
+ PINCTRL_PIN(56, "l_de"),
+ PINCTRL_PIN(57, "ldd_0"),
+ PINCTRL_PIN(58, "ldd_1"),
+ PINCTRL_PIN(59, "ldd_2"),
+ PINCTRL_PIN(60, "ldd_3"),
+ PINCTRL_PIN(61, "ldd_4"),
+ PINCTRL_PIN(62, "ldd_5"),
+ PINCTRL_PIN(63, "ldd_6"),
+ PINCTRL_PIN(64, "ldd_7"),
+ PINCTRL_PIN(65, "ldd_8"),
+ PINCTRL_PIN(66, "ldd_9"),
+ PINCTRL_PIN(67, "ldd_10"),
+ PINCTRL_PIN(68, "ldd_11"),
+ PINCTRL_PIN(69, "ldd_12"),
+ PINCTRL_PIN(70, "ldd_13"),
+ PINCTRL_PIN(71, "ldd_14"),
+ PINCTRL_PIN(72, "ldd_15"),
+ PINCTRL_PIN(73, "lcd_gpio_20"),
+ PINCTRL_PIN(74, "vip_0"),
+ PINCTRL_PIN(75, "vip_1"),
+ PINCTRL_PIN(76, "vip_2"),
+ PINCTRL_PIN(77, "vip_3"),
+ PINCTRL_PIN(78, "vip_4"),
+ PINCTRL_PIN(79, "vip_5"),
+ PINCTRL_PIN(80, "vip_6"),
+ PINCTRL_PIN(81, "vip_7"),
+ PINCTRL_PIN(82, "vip_pxclk"),
+ PINCTRL_PIN(83, "vip_hsync"),
+ PINCTRL_PIN(84, "vip_vsync"),
+ PINCTRL_PIN(85, "sdio3_clk"),
+ PINCTRL_PIN(86, "sdio3_cmd"),
+ PINCTRL_PIN(87, "sdio3_dat_0"),
+ PINCTRL_PIN(88, "sdio3_dat_1"),
+ PINCTRL_PIN(89, "sdio3_dat_2"),
+ PINCTRL_PIN(90, "sdio3_dat_3"),
+ PINCTRL_PIN(91, "sdio5_clk"),
+ PINCTRL_PIN(92, "sdio5_cmd"),
+ PINCTRL_PIN(93, "sdio5_dat_0"),
+ PINCTRL_PIN(94, "sdio5_dat_1"),
+ PINCTRL_PIN(95, "sdio5_dat_2"),
+ PINCTRL_PIN(96, "sdio5_dat_3"),
+ PINCTRL_PIN(97, "rgmii_txd_0"),
+ PINCTRL_PIN(98, "rgmii_txd_1"),
+ PINCTRL_PIN(99, "rgmii_txd_2"),
+ PINCTRL_PIN(100, "rgmii_txd_3"),
+ PINCTRL_PIN(101, "rgmii_txclk"),
+ PINCTRL_PIN(102, "rgmii_tx_ctl"),
+ PINCTRL_PIN(103, "rgmii_rxd_0"),
+ PINCTRL_PIN(104, "rgmii_rxd_1"),
+ PINCTRL_PIN(105, "rgmii_rxd_2"),
+ PINCTRL_PIN(106, "rgmii_rxd_3"),
+ PINCTRL_PIN(107, "rgmii_rx_clk"),
+ PINCTRL_PIN(108, "rgmii_rxc_ctl"),
+ PINCTRL_PIN(109, "rgmii_mdio"),
+ PINCTRL_PIN(110, "rgmii_mdc"),
+ PINCTRL_PIN(111, "rgmii_intr_n"),
+ PINCTRL_PIN(112, "i2s_mclk"),
+ PINCTRL_PIN(113, "i2s_bclk"),
+ PINCTRL_PIN(114, "i2s_ws"),
+ PINCTRL_PIN(115, "i2s_dout0"),
+ PINCTRL_PIN(116, "i2s_dout1"),
+ PINCTRL_PIN(117, "i2s_dout2"),
+ PINCTRL_PIN(118, "i2s_din"),
+ PINCTRL_PIN(119, "gpio_0"),
+ PINCTRL_PIN(120, "gpio_1"),
+ PINCTRL_PIN(121, "gpio_2"),
+ PINCTRL_PIN(122, "gpio_3"),
+ PINCTRL_PIN(123, "gpio_4"),
+ PINCTRL_PIN(124, "gpio_5"),
+ PINCTRL_PIN(125, "gpio_6"),
+ PINCTRL_PIN(126, "gpio_7"),
+ PINCTRL_PIN(127, "sda_0"),
+ PINCTRL_PIN(128, "scl_0"),
+ PINCTRL_PIN(129, "coex_pio_0"),
+ PINCTRL_PIN(130, "coex_pio_1"),
+ PINCTRL_PIN(131, "coex_pio_2"),
+ PINCTRL_PIN(132, "coex_pio_3"),
+ PINCTRL_PIN(133, "uart0_tx"),
+ PINCTRL_PIN(134, "uart0_rx"),
+ PINCTRL_PIN(135, "uart1_tx"),
+ PINCTRL_PIN(136, "uart1_rx"),
+ PINCTRL_PIN(137, "uart3_tx"),
+ PINCTRL_PIN(138, "uart3_rx"),
+ PINCTRL_PIN(139, "uart4_tx"),
+ PINCTRL_PIN(140, "uart4_rx"),
+ PINCTRL_PIN(141, "usp0_clk"),
+ PINCTRL_PIN(142, "usp0_tx"),
+ PINCTRL_PIN(143, "usp0_rx"),
+ PINCTRL_PIN(144, "usp0_fs"),
+ PINCTRL_PIN(145, "usp1_clk"),
+ PINCTRL_PIN(146, "usp1_tx"),
+ PINCTRL_PIN(147, "usp1_rx"),
+ PINCTRL_PIN(148, "usp1_fs"),
+ PINCTRL_PIN(149, "lvds_tx0d4p"),
+ PINCTRL_PIN(150, "lvds_tx0d4n"),
+ PINCTRL_PIN(151, "lvds_tx0d3p"),
+ PINCTRL_PIN(152, "lvds_tx0d3n"),
+ PINCTRL_PIN(153, "lvds_tx0d2p"),
+ PINCTRL_PIN(154, "lvds_tx0d2n"),
+ PINCTRL_PIN(155, "lvds_tx0d1p"),
+ PINCTRL_PIN(156, "lvds_tx0d1n"),
+ PINCTRL_PIN(157, "lvds_tx0d0p"),
+ PINCTRL_PIN(158, "lvds_tx0d0n"),
+};
+
+struct atlas7_pad_config atlas7_ioc_pad_confs[] = {
+ /* The Configuration of IOC_RTC Pads */
+ PADCONF(0, 3, 0x0, 0x100, 0x200, -1, 0, 0, 0, 0),
+ PADCONF(1, 3, 0x0, 0x100, 0x200, -1, 4, 2, 2, 0),
+ PADCONF(2, 3, 0x0, 0x100, 0x200, -1, 8, 4, 4, 0),
+ PADCONF(3, 5, 0x0, 0x100, 0x200, -1, 12, 6, 6, 0),
+ PADCONF(4, 4, 0x0, 0x100, 0x200, -1, 16, 8, 8, 0),
+ PADCONF(5, 4, 0x0, 0x100, 0x200, -1, 20, 10, 10, 0),
+ PADCONF(6, 3, 0x0, 0x100, 0x200, -1, 24, 12, 12, 0),
+ PADCONF(7, 3, 0x0, 0x100, 0x200, -1, 28, 14, 14, 0),
+ PADCONF(8, 3, 0x8, 0x100, 0x200, -1, 0, 16, 16, 0),
+ PADCONF(9, 3, 0x8, 0x100, 0x200, -1, 4, 18, 18, 0),
+ PADCONF(10, 4, 0x8, 0x100, 0x200, -1, 8, 20, 20, 0),
+ PADCONF(11, 4, 0x8, 0x100, 0x200, -1, 12, 22, 22, 0),
+ PADCONF(12, 5, 0x8, 0x100, 0x200, -1, 16, 24, 24, 0),
+ PADCONF(13, 6, 0x8, 0x100, 0x200, -1, 20, 26, 26, 0),
+ PADCONF(14, 5, 0x8, 0x100, 0x200, -1, 24, 28, 28, 0),
+ PADCONF(15, 5, 0x8, 0x100, 0x200, -1, 28, 30, 30, 0),
+ PADCONF(16, 5, 0x10, 0x108, 0x208, -1, 0, 0, 0, 0),
+ PADCONF(17, 5, 0x10, 0x108, 0x208, -1, 4, 2, 2, 0),
+ /* The Configuration of IOC_TOP Pads */
+ PADCONF(18, 5, 0x80, 0x180, 0x300, -1, 0, 0, 0, 0),
+ PADCONF(19, 5, 0x80, 0x180, 0x300, -1, 4, 2, 2, 0),
+ PADCONF(20, 5, 0x80, 0x180, 0x300, -1, 8, 4, 4, 0),
+ PADCONF(21, 5, 0x80, 0x180, 0x300, -1, 12, 6, 6, 0),
+ PADCONF(22, 5, 0x88, 0x188, 0x308, -1, 0, 0, 0, 0),
+ PADCONF(23, 5, 0x88, 0x188, 0x308, -1, 4, 2, 2, 0),
+ PADCONF(24, 5, 0x88, 0x188, 0x308, -1, 8, 4, 4, 0),
+ PADCONF(25, 6, 0x88, 0x188, 0x308, -1, 12, 6, 6, 0),
+ PADCONF(26, 5, 0x88, 0x188, 0x308, -1, 16, 8, 8, 0),
+ PADCONF(27, 6, 0x88, 0x188, 0x308, -1, 20, 10, 10, 0),
+ PADCONF(28, 5, 0x88, 0x188, 0x308, -1, 24, 12, 12, 0),
+ PADCONF(29, 5, 0x88, 0x188, 0x308, -1, 28, 14, 14, 0),
+ PADCONF(30, 5, 0x90, 0x188, 0x308, -1, 0, 16, 16, 0),
+ PADCONF(31, 2, 0x98, 0x190, 0x310, -1, 0, 0, 0, 0),
+ PADCONF(32, 1, 0x98, 0x190, 0x310, -1, 4, 2, 4, 0),
+ PADCONF(33, 1, 0x98, 0x190, 0x310, -1, 8, 4, 6, 0),
+ PADCONF(34, 1, 0x98, 0x190, 0x310, -1, 12, 6, 8, 0),
+ PADCONF(35, 1, 0x98, 0x190, 0x310, -1, 16, 8, 10, 0),
+ PADCONF(36, 1, 0x98, 0x190, 0x310, -1, 20, 10, 12, 0),
+ PADCONF(37, 1, 0xa0, 0x198, 0x318, -1, 0, 0, 0, 0),
+ PADCONF(38, 1, 0xa0, 0x198, 0x318, -1, 4, 2, 2, 0),
+ PADCONF(39, 1, 0xa0, 0x198, 0x318, -1, 8, 4, 4, 0),
+ PADCONF(40, 1, 0xa0, 0x198, 0x318, -1, 12, 6, 6, 0),
+ PADCONF(41, 1, 0xa0, 0x198, 0x318, -1, 16, 8, 8, 0),
+ PADCONF(42, 1, 0xa0, 0x198, 0x318, -1, 20, 10, 10, 0),
+ PADCONF(43, 1, 0xa0, 0x198, 0x318, -1, 24, 12, 12, 0),
+ PADCONF(44, 1, 0xa0, 0x198, 0x318, -1, 28, 14, 14, 0),
+ PADCONF(45, 0, 0xa8, 0x198, 0x318, -1, 0, 16, 16, 0),
+ PADCONF(46, 0, 0xa8, 0x198, 0x318, -1, 4, 18, 18, 0),
+ PADCONF(47, 1, 0xa8, 0x198, 0x318, -1, 8, 20, 20, 0),
+ PADCONF(48, 1, 0xa8, 0x198, 0x318, -1, 12, 22, 22, 0),
+ PADCONF(49, 1, 0xa8, 0x198, 0x318, -1, 16, 24, 24, 0),
+ PADCONF(50, 1, 0xa8, 0x198, 0x318, -1, 20, 26, 26, 0),
+ PADCONF(51, 1, 0xa8, 0x198, 0x318, -1, 24, 28, 28, 0),
+ PADCONF(52, 1, 0xa8, 0x198, 0x318, -1, 28, 30, 30, 0),
+ PADCONF(53, 0, 0xb0, 0x1a0, 0x320, -1, 0, 0, 0, 0),
+ PADCONF(54, 0, 0xb0, 0x1a0, 0x320, -1, 4, 2, 2, 0),
+ PADCONF(55, 0, 0xb0, 0x1a0, 0x320, -1, 8, 4, 4, 0),
+ PADCONF(56, 0, 0xb0, 0x1a0, 0x320, -1, 12, 6, 6, 0),
+ PADCONF(57, 0, 0xb0, 0x1a0, 0x320, -1, 16, 8, 8, 0),
+ PADCONF(58, 0, 0xb0, 0x1a0, 0x320, -1, 20, 10, 10, 0),
+ PADCONF(59, 0, 0xb0, 0x1a0, 0x320, -1, 24, 12, 12, 0),
+ PADCONF(60, 0, 0xb0, 0x1a0, 0x320, -1, 28, 14, 14, 0),
+ PADCONF(61, 0, 0xb8, 0x1a0, 0x320, -1, 0, 16, 16, 0),
+ PADCONF(62, 0, 0xb8, 0x1a0, 0x320, -1, 4, 18, 18, 0),
+ PADCONF(63, 0, 0xb8, 0x1a0, 0x320, -1, 8, 20, 20, 0),
+ PADCONF(64, 0, 0xb8, 0x1a0, 0x320, -1, 12, 22, 22, 0),
+ PADCONF(65, 0, 0xb8, 0x1a0, 0x320, -1, 16, 24, 24, 0),
+ PADCONF(66, 0, 0xb8, 0x1a0, 0x320, -1, 20, 26, 26, 0),
+ PADCONF(67, 0, 0xb8, 0x1a0, 0x320, -1, 24, 28, 28, 0),
+ PADCONF(68, 0, 0xb8, 0x1a0, 0x320, -1, 28, 30, 30, 0),
+ PADCONF(69, 0, 0xc0, 0x1a8, 0x328, -1, 0, 0, 0, 0),
+ PADCONF(70, 0, 0xc0, 0x1a8, 0x328, -1, 4, 2, 2, 0),
+ PADCONF(71, 0, 0xc0, 0x1a8, 0x328, -1, 8, 4, 4, 0),
+ PADCONF(72, 0, 0xc0, 0x1a8, 0x328, -1, 12, 6, 6, 0),
+ PADCONF(73, 0, 0xc0, 0x1a8, 0x328, -1, 16, 8, 8, 0),
+ PADCONF(74, 0, 0xc8, 0x1b0, 0x330, -1, 0, 0, 0, 0),
+ PADCONF(75, 0, 0xc8, 0x1b0, 0x330, -1, 4, 2, 2, 0),
+ PADCONF(76, 0, 0xc8, 0x1b0, 0x330, -1, 8, 4, 4, 0),
+ PADCONF(77, 0, 0xc8, 0x1b0, 0x330, -1, 12, 6, 6, 0),
+ PADCONF(78, 0, 0xc8, 0x1b0, 0x330, -1, 16, 8, 8, 0),
+ PADCONF(79, 0, 0xc8, 0x1b0, 0x330, -1, 20, 10, 10, 0),
+ PADCONF(80, 0, 0xc8, 0x1b0, 0x330, -1, 24, 12, 12, 0),
+ PADCONF(81, 0, 0xc8, 0x1b0, 0x330, -1, 28, 14, 14, 0),
+ PADCONF(82, 0, 0xd0, 0x1b0, 0x330, -1, 0, 16, 16, 0),
+ PADCONF(83, 0, 0xd0, 0x1b0, 0x330, -1, 4, 18, 18, 0),
+ PADCONF(84, 0, 0xd0, 0x1b0, 0x330, -1, 8, 20, 20, 0),
+ PADCONF(85, 2, 0xd8, 0x1b8, 0x338, -1, 0, 0, 0, 0),
+ PADCONF(86, 1, 0xd8, 0x1b8, 0x338, -1, 4, 4, 4, 0),
+ PADCONF(87, 1, 0xd8, 0x1b8, 0x338, -1, 8, 6, 6, 0),
+ PADCONF(88, 1, 0xd8, 0x1b8, 0x338, -1, 12, 8, 8, 0),
+ PADCONF(89, 1, 0xd8, 0x1b8, 0x338, -1, 16, 10, 10, 0),
+ PADCONF(90, 1, 0xd8, 0x1b8, 0x338, -1, 20, 12, 12, 0),
+ PADCONF(91, 2, 0xe0, 0x1c0, 0x340, -1, 0, 0, 0, 0),
+ PADCONF(92, 1, 0xe0, 0x1c0, 0x340, -1, 4, 4, 4, 0),
+ PADCONF(93, 1, 0xe0, 0x1c0, 0x340, -1, 8, 6, 6, 0),
+ PADCONF(94, 1, 0xe0, 0x1c0, 0x340, -1, 12, 8, 8, 0),
+ PADCONF(95, 1, 0xe0, 0x1c0, 0x340, -1, 16, 10, 10, 0),
+ PADCONF(96, 1, 0xe0, 0x1c0, 0x340, -1, 20, 12, 12, 0),
+ PADCONF(97, 0, 0xe8, 0x1c8, 0x348, -1, 0, 0, 0, 0),
+ PADCONF(98, 0, 0xe8, 0x1c8, 0x348, -1, 4, 2, 2, 0),
+ PADCONF(99, 0, 0xe8, 0x1c8, 0x348, -1, 8, 4, 4, 0),
+ PADCONF(100, 0, 0xe8, 0x1c8, 0x348, -1, 12, 6, 6, 0),
+ PADCONF(101, 2, 0xe8, 0x1c8, 0x348, -1, 16, 8, 8, 0),
+ PADCONF(102, 0, 0xe8, 0x1c8, 0x348, -1, 20, 12, 12, 0),
+ PADCONF(103, 0, 0xe8, 0x1c8, 0x348, -1, 24, 14, 14, 0),
+ PADCONF(104, 0, 0xe8, 0x1c8, 0x348, -1, 28, 16, 16, 0),
+ PADCONF(105, 0, 0xf0, 0x1c8, 0x348, -1, 0, 18, 18, 0),
+ PADCONF(106, 0, 0xf0, 0x1c8, 0x348, -1, 4, 20, 20, 0),
+ PADCONF(107, 0, 0xf0, 0x1c8, 0x348, -1, 8, 22, 22, 0),
+ PADCONF(108, 0, 0xf0, 0x1c8, 0x348, -1, 12, 24, 24, 0),
+ PADCONF(109, 1, 0xf0, 0x1c8, 0x348, -1, 16, 26, 26, 0),
+ PADCONF(110, 0, 0xf0, 0x1c8, 0x348, -1, 20, 28, 28, 0),
+ PADCONF(111, 1, 0xf0, 0x1c8, 0x348, -1, 24, 30, 30, 0),
+ PADCONF(112, 5, 0xf8, 0x200, 0x350, -1, 0, 0, 0, 0),
+ PADCONF(113, 5, 0xf8, 0x200, 0x350, -1, 4, 2, 2, 0),
+ PADCONF(114, 5, 0xf8, 0x200, 0x350, -1, 8, 4, 4, 0),
+ PADCONF(115, 5, 0xf8, 0x200, 0x350, -1, 12, 6, 6, 0),
+ PADCONF(116, 5, 0xf8, 0x200, 0x350, -1, 16, 8, 8, 0),
+ PADCONF(117, 5, 0xf8, 0x200, 0x350, -1, 20, 10, 10, 0),
+ PADCONF(118, 5, 0xf8, 0x200, 0x350, -1, 24, 12, 12, 0),
+ PADCONF(119, 5, 0x100, 0x250, 0x358, -1, 0, 0, 0, 0),
+ PADCONF(120, 5, 0x100, 0x250, 0x358, -1, 4, 2, 2, 0),
+ PADCONF(121, 5, 0x100, 0x250, 0x358, -1, 8, 4, 4, 0),
+ PADCONF(122, 5, 0x100, 0x250, 0x358, -1, 12, 6, 6, 0),
+ PADCONF(123, 6, 0x100, 0x250, 0x358, -1, 16, 8, 8, 0),
+ PADCONF(124, 6, 0x100, 0x250, 0x358, -1, 20, 10, 10, 0),
+ PADCONF(125, 6, 0x100, 0x250, 0x358, -1, 24, 12, 12, 0),
+ PADCONF(126, 6, 0x100, 0x250, 0x358, -1, 28, 14, 14, 0),
+ PADCONF(127, 6, 0x108, 0x250, 0x358, -1, 16, 24, 24, 0),
+ PADCONF(128, 6, 0x108, 0x250, 0x358, -1, 20, 26, 26, 0),
+ PADCONF(129, 0, 0x110, 0x258, 0x360, -1, 0, 0, 0, 0),
+ PADCONF(130, 0, 0x110, 0x258, 0x360, -1, 4, 2, 2, 0),
+ PADCONF(131, 0, 0x110, 0x258, 0x360, -1, 8, 4, 4, 0),
+ PADCONF(132, 0, 0x110, 0x258, 0x360, -1, 12, 6, 6, 0),
+ PADCONF(133, 6, 0x118, 0x260, 0x368, -1, 0, 0, 0, 0),
+ PADCONF(134, 6, 0x118, 0x260, 0x368, -1, 4, 2, 2, 0),
+ PADCONF(135, 6, 0x118, 0x260, 0x368, -1, 16, 8, 8, 0),
+ PADCONF(136, 6, 0x118, 0x260, 0x368, -1, 20, 10, 10, 0),
+ PADCONF(137, 6, 0x118, 0x260, 0x368, -1, 24, 12, 12, 0),
+ PADCONF(138, 6, 0x118, 0x260, 0x368, -1, 28, 14, 14, 0),
+ PADCONF(139, 6, 0x120, 0x260, 0x368, -1, 0, 16, 16, 0),
+ PADCONF(140, 6, 0x120, 0x260, 0x368, -1, 4, 18, 18, 0),
+ PADCONF(141, 5, 0x128, 0x268, 0x378, -1, 0, 0, 0, 0),
+ PADCONF(142, 5, 0x128, 0x268, 0x378, -1, 4, 2, 2, 0),
+ PADCONF(143, 5, 0x128, 0x268, 0x378, -1, 8, 4, 4, 0),
+ PADCONF(144, 5, 0x128, 0x268, 0x378, -1, 12, 6, 6, 0),
+ PADCONF(145, 5, 0x128, 0x268, 0x378, -1, 16, 8, 8, 0),
+ PADCONF(146, 5, 0x128, 0x268, 0x378, -1, 20, 10, 10, 0),
+ PADCONF(147, 5, 0x128, 0x268, 0x378, -1, 24, 12, 12, 0),
+ PADCONF(148, 5, 0x128, 0x268, 0x378, -1, 28, 14, 14, 0),
+ PADCONF(149, 7, 0x130, 0x270, -1, 0x480, 0, 0, 0, 0),
+ PADCONF(150, 7, 0x130, 0x270, -1, 0x480, 4, 2, 0, 1),
+ PADCONF(151, 7, 0x130, 0x270, -1, 0x480, 8, 4, 0, 2),
+ PADCONF(152, 7, 0x130, 0x270, -1, 0x480, 12, 6, 0, 3),
+ PADCONF(153, 7, 0x130, 0x270, -1, 0x480, 16, 8, 0, 4),
+ PADCONF(154, 7, 0x130, 0x270, -1, 0x480, 20, 10, 0, 5),
+ PADCONF(155, 7, 0x130, 0x270, -1, 0x480, 24, 12, 0, 6),
+ PADCONF(156, 7, 0x130, 0x270, -1, 0x480, 28, 14, 0, 7),
+ PADCONF(157, 7, 0x138, 0x278, -1, 0x480, 0, 0, 0, 8),
+ PADCONF(158, 7, 0x138, 0x278, -1, 0x480, 4, 2, 0, 9),
+};
+
+/* pin list of each pin group */
+static const unsigned int gnss_gpio_pins[] = { 119, 120, 121, 122, 123, 124,
+ 125, 126, 127, 128, 22, 23, 24, 25, 26, 27, 28, 29, 30, };
+static const unsigned int lcd_vip_gpio_pins[] = { 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, };
+static const unsigned int sdio_i2s_gpio_pins[] = { 31, 32, 33, 34, 35, 36,
+ 85, 86, 87, 88, 89, 90, 129, 130, 131, 132, 91, 92, 93, 94,
+ 95, 96, 112, 113, 114, 115, 116, 117, 118, };
+static const unsigned int sp_rgmii_gpio_pins[] = { 97, 98, 99, 100, 101, 102,
+ 103, 104, 105, 106, 107, 108, 109, 110, 111, 18, 19, 20, 21,
+ 141, 142, 143, 144, 145, 146, 147, 148, };
+static const unsigned int lvds_gpio_pins[] = { 157, 158, 155, 156, 153, 154,
+ 151, 152, 149, 150, };
+static const unsigned int uart_nand_gpio_pins[] = { 44, 43, 42, 41, 40, 39,
+ 38, 37, 46, 47, 48, 49, 50, 52, 51, 45, 133, 134, 135, 136,
+ 137, 138, 139, 140, };
+static const unsigned int rtc_gpio_pins[] = { 0, 1, 2, 3, 4, 10, 11, 12, 13,
+ 14, 15, 16, 17, };
+static const unsigned int audio_ac97_pins[] = { 113, 118, 115, 114, };
+static const unsigned int audio_func_dbg_pins[] = { 141, 144, 44, 43, 42, 41,
+ 40, 39, 38, 37, 74, 75, 76, 77, 78, 79, 81, 113, 114, 118,
+ 115, 49, 50, 142, 143, 80, };
+static const unsigned int audio_i2s_pins[] = { 118, 115, 116, 117, 112, 113,
+ 114, };
+static const unsigned int audio_i2s_2ch_pins[] = { 118, 115, 112, 113, 114, };
+static const unsigned int audio_i2s_extclk_pins[] = { 112, };
+static const unsigned int audio_uart0_pins[] = { 143, 142, 141, 144, };
+static const unsigned int audio_uart1_pins[] = { 147, 146, 145, 148, };
+static const unsigned int audio_uart2_pins0[] = { 20, 21, 19, 18, };
+static const unsigned int audio_uart2_pins1[] = { 109, 110, 101, 111, };
+static const unsigned int c_can_trnsvr_pins[] = { 1, };
+static const unsigned int c0_can_pins0[] = { 11, 10, };
+static const unsigned int c0_can_pins1[] = { 2, 3, };
+static const unsigned int c1_can_pins0[] = { 138, 137, };
+static const unsigned int c1_can_pins1[] = { 147, 146, };
+static const unsigned int c1_can_pins2[] = { 2, 3, };
+static const unsigned int ca_audio_lpc_pins[] = { 62, 63, 64, 65, 66, 67, 68,
+ 69, 70, 71, };
+static const unsigned int ca_bt_lpc_pins[] = { 85, 86, 87, 88, 89, 90, };
+static const unsigned int ca_coex_pins[] = { 129, 130, 131, 132, };
+static const unsigned int ca_curator_lpc_pins[] = { 57, 58, 59, 60, };
+static const unsigned int ca_pcm_debug_pins[] = { 91, 93, 94, 92, };
+static const unsigned int ca_pio_pins[] = { 121, 122, 125, 126, 38, 37, 47,
+ 49, 50, 54, 55, 56, };
+static const unsigned int ca_sdio_debug_pins[] = { 40, 39, 44, 43, 42, 41, };
+static const unsigned int ca_spi_pins[] = { 82, 79, 80, 81, };
+static const unsigned int ca_trb_pins[] = { 91, 93, 94, 95, 96, 78, 74, 75,
+ 76, 77, };
+static const unsigned int ca_uart_debug_pins[] = { 136, 135, 134, 133, };
+static const unsigned int clkc_pins0[] = { 30, 47, };
+static const unsigned int clkc_pins1[] = { 78, 54, };
+static const unsigned int gn_gnss_i2c_pins[] = { 128, 127, };
+static const unsigned int gn_gnss_uart_nopause_pins[] = { 134, 133, };
+static const unsigned int gn_gnss_uart_pins[] = { 134, 133, 136, 135, };
+static const unsigned int gn_trg_spi_pins0[] = { 22, 25, 23, 24, };
+static const unsigned int gn_trg_spi_pins1[] = { 82, 79, 80, 81, };
+static const unsigned int cvbs_dbg_pins[] = { 54, 53, 82, 74, 75, 76, 77, 78,
+ 79, 80, 81, 83, 84, 73, 55, 56, };
+static const unsigned int cvbs_dbg_test_pins0[] = { 57, };
+static const unsigned int cvbs_dbg_test_pins1[] = { 58, };
+static const unsigned int cvbs_dbg_test_pins2[] = { 59, };
+static const unsigned int cvbs_dbg_test_pins3[] = { 60, };
+static const unsigned int cvbs_dbg_test_pins4[] = { 61, };
+static const unsigned int cvbs_dbg_test_pins5[] = { 62, };
+static const unsigned int cvbs_dbg_test_pins6[] = { 63, };
+static const unsigned int cvbs_dbg_test_pins7[] = { 64, };
+static const unsigned int cvbs_dbg_test_pins8[] = { 65, };
+static const unsigned int cvbs_dbg_test_pins9[] = { 66, };
+static const unsigned int cvbs_dbg_test_pins10[] = { 67, };
+static const unsigned int cvbs_dbg_test_pins11[] = { 68, };
+static const unsigned int cvbs_dbg_test_pins12[] = { 69, };
+static const unsigned int cvbs_dbg_test_pins13[] = { 70, };
+static const unsigned int cvbs_dbg_test_pins14[] = { 71, };
+static const unsigned int cvbs_dbg_test_pins15[] = { 72, };
+static const unsigned int gn_gnss_power_pins[] = { 123, 124, 121, 122, 125,
+ 120, };
+static const unsigned int gn_gnss_sw_status_pins[] = { 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 53, 55, 56, 54, };
+static const unsigned int gn_gnss_eclk_pins[] = { 113, };
+static const unsigned int gn_gnss_irq1_pins0[] = { 112, };
+static const unsigned int gn_gnss_irq2_pins0[] = { 118, };
+static const unsigned int gn_gnss_tm_pins[] = { 115, };
+static const unsigned int gn_gnss_tsync_pins[] = { 114, };
+static const unsigned int gn_io_gnsssys_sw_cfg_pins[] = { 44, 43, 42, 41, 40,
+ 39, 38, 37, 49, 50, 91, 92, 93, 94, 95, 96, };
+static const unsigned int gn_trg_pins0[] = { 29, 28, 26, 27, };
+static const unsigned int gn_trg_pins1[] = { 77, 76, 74, 75, };
+static const unsigned int gn_trg_shutdown_pins0[] = { 30, };
+static const unsigned int gn_trg_shutdown_pins1[] = { 83, };
+static const unsigned int gn_trg_shutdown_pins2[] = { 117, };
+static const unsigned int gn_trg_shutdown_pins3[] = { 123, };
+static const unsigned int i2c0_pins[] = { 128, 127, };
+static const unsigned int i2c1_pins[] = { 126, 125, };
+static const unsigned int jtag_pins0[] = { 125, 4, 2, 0, 1, 3, };
+static const unsigned int ks_kas_spi_pins0[] = { 141, 144, 143, 142, };
+static const unsigned int ld_ldd_pins[] = { 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 80,
+ 81, 56, 53, };
+static const unsigned int ld_ldd_16bit_pins[] = { 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 56, 53, };
+static const unsigned int ld_ldd_fck_pins[] = { 55, };
+static const unsigned int ld_ldd_lck_pins[] = { 54, };
+static const unsigned int lr_lcdrom_pins[] = { 73, 54, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 56, 53, 55, };
+static const unsigned int lvds_analog_pins[] = { 149, 150, 151, 152, 153, 154,
+ 155, 156, 157, 158, };
+static const unsigned int nd_df_pins[] = { 44, 43, 42, 41, 40, 39, 38, 37,
+ 47, 46, 52, 51, 45, 49, 50, 48, 124, };
+static const unsigned int nd_df_nowp_pins[] = { 44, 43, 42, 41, 40, 39, 38,
+ 37, 47, 46, 52, 51, 45, 49, 50, 48, };
+static const unsigned int ps_pins[] = { 120, 119, };
+static const unsigned int pwc_core_on_pins[] = { 8, };
+static const unsigned int pwc_ext_on_pins[] = { 6, };
+static const unsigned int pwc_gpio3_clk_pins[] = { 3, };
+static const unsigned int pwc_io_on_pins[] = { 9, };
+static const unsigned int pwc_lowbatt_b_pins0[] = { 4, };
+static const unsigned int pwc_mem_on_pins[] = { 7, };
+static const unsigned int pwc_on_key_b_pins0[] = { 5, };
+static const unsigned int pwc_wakeup_src0_pins[] = { 0, };
+static const unsigned int pwc_wakeup_src1_pins[] = { 1, };
+static const unsigned int pwc_wakeup_src2_pins[] = { 2, };
+static const unsigned int pwc_wakeup_src3_pins[] = { 3, };
+static const unsigned int pw_cko0_pins0[] = { 123, };
+static const unsigned int pw_cko0_pins1[] = { 101, };
+static const unsigned int pw_cko0_pins2[] = { 82, };
+static const unsigned int pw_cko1_pins0[] = { 124, };
+static const unsigned int pw_cko1_pins1[] = { 110, };
+static const unsigned int pw_i2s01_clk_pins0[] = { 125, };
+static const unsigned int pw_i2s01_clk_pins1[] = { 117, };
+static const unsigned int pw_pwm0_pins[] = { 119, };
+static const unsigned int pw_pwm1_pins[] = { 120, };
+static const unsigned int pw_pwm2_pins0[] = { 121, };
+static const unsigned int pw_pwm2_pins1[] = { 98, };
+static const unsigned int pw_pwm3_pins0[] = { 122, };
+static const unsigned int pw_pwm3_pins1[] = { 73, };
+static const unsigned int pw_pwm_cpu_vol_pins0[] = { 121, };
+static const unsigned int pw_pwm_cpu_vol_pins1[] = { 98, };
+static const unsigned int pw_backlight_pins0[] = { 122, };
+static const unsigned int pw_backlight_pins1[] = { 73, };
+static const unsigned int rg_eth_mac_pins[] = { 108, 103, 104, 105, 106, 107,
+ 102, 97, 98, 99, 100, 101, };
+static const unsigned int rg_gmac_phy_intr_n_pins[] = { 111, };
+static const unsigned int rg_rgmii_mac_pins[] = { 109, 110, };
+static const unsigned int rg_rgmii_phy_ref_clk_pins0[] = { 111, };
+static const unsigned int rg_rgmii_phy_ref_clk_pins1[] = { 53, };
+static const unsigned int sd0_pins[] = { 46, 47, 44, 43, 42, 41, 40, 39, 38,
+ 37, };
+static const unsigned int sd0_4bit_pins[] = { 46, 47, 44, 43, 42, 41, };
+static const unsigned int sd1_pins[] = { 48, 49, 44, 43, 42, 41, 40, 39, 38,
+ 37, };
+static const unsigned int sd1_4bit_pins0[] = { 48, 49, 44, 43, 42, 41, };
+static const unsigned int sd1_4bit_pins1[] = { 48, 49, 40, 39, 38, 37, };
+static const unsigned int sd2_pins0[] = { 124, 31, 32, 33, 34, 35, 36, 123, };
+static const unsigned int sd2_no_cdb_pins0[] = { 31, 32, 33, 34, 35, 36, 123, };
+static const unsigned int sd3_pins[] = { 85, 86, 87, 88, 89, 90, };
+static const unsigned int sd5_pins[] = { 91, 92, 93, 94, 95, 96, };
+static const unsigned int sd6_pins0[] = { 79, 78, 74, 75, 76, 77, };
+static const unsigned int sd6_pins1[] = { 101, 99, 100, 110, 109, 111, };
+static const unsigned int sp0_ext_ldo_on_pins[] = { 4, };
+static const unsigned int sp0_qspi_pins[] = { 12, 13, 14, 15, 16, 17, };
+static const unsigned int sp1_spi_pins[] = { 19, 20, 21, 18, };
+static const unsigned int tpiu_trace_pins[] = { 53, 56, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, };
+static const unsigned int uart0_pins[] = { 121, 120, 134, 133, };
+static const unsigned int uart0_nopause_pins[] = { 134, 133, };
+static const unsigned int uart1_pins[] = { 136, 135, };
+static const unsigned int uart2_pins[] = { 11, 10, };
+static const unsigned int uart3_pins0[] = { 125, 126, 138, 137, };
+static const unsigned int uart3_pins1[] = { 111, 109, 84, 83, };
+static const unsigned int uart3_pins2[] = { 140, 139, 138, 137, };
+static const unsigned int uart3_pins3[] = { 139, 140, 84, 83, };
+static const unsigned int uart3_nopause_pins0[] = { 138, 137, };
+static const unsigned int uart3_nopause_pins1[] = { 84, 83, };
+static const unsigned int uart4_pins0[] = { 122, 123, 140, 139, };
+static const unsigned int uart4_pins1[] = { 100, 99, 140, 139, };
+static const unsigned int uart4_pins2[] = { 117, 116, 140, 139, };
+static const unsigned int uart4_nopause_pins[] = { 140, 139, };
+static const unsigned int usb0_drvvbus_pins[] = { 51, };
+static const unsigned int usb1_drvvbus_pins[] = { 134, };
+static const unsigned int visbus_dout_pins[] = { 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 53, 54, 55, 56, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, };
+static const unsigned int vi_vip1_pins[] = { 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 103, 104, 105, 106, 107, 102, 97, 98, };
+static const unsigned int vi_vip1_ext_pins[] = { 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 108, 103, 104, 105, 106, 107, 102, 97, 98,
+ 99, 100, };
+static const unsigned int vi_vip1_low8bit_pins[] = { 74, 75, 76, 77, 78, 79,
+ 80, 81, };
+static const unsigned int vi_vip1_high8bit_pins[] = { 82, 83, 84, 108, 103,
+ 104, 105, 106, };
+
+/* definition of pin group table */
+struct atlas7_pin_group altas7_pin_groups[] = {
+ GROUP("gnss_gpio_grp", gnss_gpio_pins),
+ GROUP("lcd_vip_gpio_grp", lcd_vip_gpio_pins),
+ GROUP("sdio_i2s_gpio_grp", sdio_i2s_gpio_pins),
+ GROUP("sp_rgmii_gpio_grp", sp_rgmii_gpio_pins),
+ GROUP("lvds_gpio_grp", lvds_gpio_pins),
+ GROUP("uart_nand_gpio_grp", uart_nand_gpio_pins),
+ GROUP("rtc_gpio_grp", rtc_gpio_pins),
+ GROUP("audio_ac97_grp", audio_ac97_pins),
+ GROUP("audio_func_dbg_grp", audio_func_dbg_pins),
+ GROUP("audio_i2s_grp", audio_i2s_pins),
+ GROUP("audio_i2s_2ch_grp", audio_i2s_2ch_pins),
+ GROUP("audio_i2s_extclk_grp", audio_i2s_extclk_pins),
+ GROUP("audio_uart0_grp", audio_uart0_pins),
+ GROUP("audio_uart1_grp", audio_uart1_pins),
+ GROUP("audio_uart2_grp0", audio_uart2_pins0),
+ GROUP("audio_uart2_grp1", audio_uart2_pins1),
+ GROUP("c_can_trnsvr_grp", c_can_trnsvr_pins),
+ GROUP("c0_can_grp0", c0_can_pins0),
+ GROUP("c0_can_grp1", c0_can_pins1),
+ GROUP("c1_can_grp0", c1_can_pins0),
+ GROUP("c1_can_grp1", c1_can_pins1),
+ GROUP("c1_can_grp2", c1_can_pins2),
+ GROUP("ca_audio_lpc_grp", ca_audio_lpc_pins),
+ GROUP("ca_bt_lpc_grp", ca_bt_lpc_pins),
+ GROUP("ca_coex_grp", ca_coex_pins),
+ GROUP("ca_curator_lpc_grp", ca_curator_lpc_pins),
+ GROUP("ca_pcm_debug_grp", ca_pcm_debug_pins),
+ GROUP("ca_pio_grp", ca_pio_pins),
+ GROUP("ca_sdio_debug_grp", ca_sdio_debug_pins),
+ GROUP("ca_spi_grp", ca_spi_pins),
+ GROUP("ca_trb_grp", ca_trb_pins),
+ GROUP("ca_uart_debug_grp", ca_uart_debug_pins),
+ GROUP("clkc_grp0", clkc_pins0),
+ GROUP("clkc_grp1", clkc_pins1),
+ GROUP("gn_gnss_i2c_grp", gn_gnss_i2c_pins),
+ GROUP("gn_gnss_uart_nopause_grp", gn_gnss_uart_nopause_pins),
+ GROUP("gn_gnss_uart_grp", gn_gnss_uart_pins),
+ GROUP("gn_trg_spi_grp0", gn_trg_spi_pins0),
+ GROUP("gn_trg_spi_grp1", gn_trg_spi_pins1),
+ GROUP("cvbs_dbg_grp", cvbs_dbg_pins),
+ GROUP("cvbs_dbg_test_grp0", cvbs_dbg_test_pins0),
+ GROUP("cvbs_dbg_test_grp1", cvbs_dbg_test_pins1),
+ GROUP("cvbs_dbg_test_grp2", cvbs_dbg_test_pins2),
+ GROUP("cvbs_dbg_test_grp3", cvbs_dbg_test_pins3),
+ GROUP("cvbs_dbg_test_grp4", cvbs_dbg_test_pins4),
+ GROUP("cvbs_dbg_test_grp5", cvbs_dbg_test_pins5),
+ GROUP("cvbs_dbg_test_grp6", cvbs_dbg_test_pins6),
+ GROUP("cvbs_dbg_test_grp7", cvbs_dbg_test_pins7),
+ GROUP("cvbs_dbg_test_grp8", cvbs_dbg_test_pins8),
+ GROUP("cvbs_dbg_test_grp9", cvbs_dbg_test_pins9),
+ GROUP("cvbs_dbg_test_grp10", cvbs_dbg_test_pins10),
+ GROUP("cvbs_dbg_test_grp11", cvbs_dbg_test_pins11),
+ GROUP("cvbs_dbg_test_grp12", cvbs_dbg_test_pins12),
+ GROUP("cvbs_dbg_test_grp13", cvbs_dbg_test_pins13),
+ GROUP("cvbs_dbg_test_grp14", cvbs_dbg_test_pins14),
+ GROUP("cvbs_dbg_test_grp15", cvbs_dbg_test_pins15),
+ GROUP("gn_gnss_power_grp", gn_gnss_power_pins),
+ GROUP("gn_gnss_sw_status_grp", gn_gnss_sw_status_pins),
+ GROUP("gn_gnss_eclk_grp", gn_gnss_eclk_pins),
+ GROUP("gn_gnss_irq1_grp0", gn_gnss_irq1_pins0),
+ GROUP("gn_gnss_irq2_grp0", gn_gnss_irq2_pins0),
+ GROUP("gn_gnss_tm_grp", gn_gnss_tm_pins),
+ GROUP("gn_gnss_tsync_grp", gn_gnss_tsync_pins),
+ GROUP("gn_io_gnsssys_sw_cfg_grp", gn_io_gnsssys_sw_cfg_pins),
+ GROUP("gn_trg_grp0", gn_trg_pins0),
+ GROUP("gn_trg_grp1", gn_trg_pins1),
+ GROUP("gn_trg_shutdown_grp0", gn_trg_shutdown_pins0),
+ GROUP("gn_trg_shutdown_grp1", gn_trg_shutdown_pins1),
+ GROUP("gn_trg_shutdown_grp2", gn_trg_shutdown_pins2),
+ GROUP("gn_trg_shutdown_grp3", gn_trg_shutdown_pins3),
+ GROUP("i2c0_grp", i2c0_pins),
+ GROUP("i2c1_grp", i2c1_pins),
+ GROUP("jtag_grp0", jtag_pins0),
+ GROUP("ks_kas_spi_grp0", ks_kas_spi_pins0),
+ GROUP("ld_ldd_grp", ld_ldd_pins),
+ GROUP("ld_ldd_16bit_grp", ld_ldd_16bit_pins),
+ GROUP("ld_ldd_fck_grp", ld_ldd_fck_pins),
+ GROUP("ld_ldd_lck_grp", ld_ldd_lck_pins),
+ GROUP("lr_lcdrom_grp", lr_lcdrom_pins),
+ GROUP("lvds_analog_grp", lvds_analog_pins),
+ GROUP("nd_df_grp", nd_df_pins),
+ GROUP("nd_df_nowp_grp", nd_df_nowp_pins),
+ GROUP("ps_grp", ps_pins),
+ GROUP("pwc_core_on_grp", pwc_core_on_pins),
+ GROUP("pwc_ext_on_grp", pwc_ext_on_pins),
+ GROUP("pwc_gpio3_clk_grp", pwc_gpio3_clk_pins),
+ GROUP("pwc_io_on_grp", pwc_io_on_pins),
+ GROUP("pwc_lowbatt_b_grp0", pwc_lowbatt_b_pins0),
+ GROUP("pwc_mem_on_grp", pwc_mem_on_pins),
+ GROUP("pwc_on_key_b_grp0", pwc_on_key_b_pins0),
+ GROUP("pwc_wakeup_src0_grp", pwc_wakeup_src0_pins),
+ GROUP("pwc_wakeup_src1_grp", pwc_wakeup_src1_pins),
+ GROUP("pwc_wakeup_src2_grp", pwc_wakeup_src2_pins),
+ GROUP("pwc_wakeup_src3_grp", pwc_wakeup_src3_pins),
+ GROUP("pw_cko0_grp0", pw_cko0_pins0),
+ GROUP("pw_cko0_grp1", pw_cko0_pins1),
+ GROUP("pw_cko0_grp2", pw_cko0_pins2),
+ GROUP("pw_cko1_grp0", pw_cko1_pins0),
+ GROUP("pw_cko1_grp1", pw_cko1_pins1),
+ GROUP("pw_i2s01_clk_grp0", pw_i2s01_clk_pins0),
+ GROUP("pw_i2s01_clk_grp1", pw_i2s01_clk_pins1),
+ GROUP("pw_pwm0_grp", pw_pwm0_pins),
+ GROUP("pw_pwm1_grp", pw_pwm1_pins),
+ GROUP("pw_pwm2_grp0", pw_pwm2_pins0),
+ GROUP("pw_pwm2_grp1", pw_pwm2_pins1),
+ GROUP("pw_pwm3_grp0", pw_pwm3_pins0),
+ GROUP("pw_pwm3_grp1", pw_pwm3_pins1),
+ GROUP("pw_pwm_cpu_vol_grp0", pw_pwm_cpu_vol_pins0),
+ GROUP("pw_pwm_cpu_vol_grp1", pw_pwm_cpu_vol_pins1),
+ GROUP("pw_backlight_grp0", pw_backlight_pins0),
+ GROUP("pw_backlight_grp1", pw_backlight_pins1),
+ GROUP("rg_eth_mac_grp", rg_eth_mac_pins),
+ GROUP("rg_gmac_phy_intr_n_grp", rg_gmac_phy_intr_n_pins),
+ GROUP("rg_rgmii_mac_grp", rg_rgmii_mac_pins),
+ GROUP("rg_rgmii_phy_ref_clk_grp0", rg_rgmii_phy_ref_clk_pins0),
+ GROUP("rg_rgmii_phy_ref_clk_grp1", rg_rgmii_phy_ref_clk_pins1),
+ GROUP("sd0_grp", sd0_pins),
+ GROUP("sd0_4bit_grp", sd0_4bit_pins),
+ GROUP("sd1_grp", sd1_pins),
+ GROUP("sd1_4bit_grp0", sd1_4bit_pins0),
+ GROUP("sd1_4bit_grp1", sd1_4bit_pins1),
+ GROUP("sd2_grp0", sd2_pins0),
+ GROUP("sd2_no_cdb_grp0", sd2_no_cdb_pins0),
+ GROUP("sd3_grp", sd3_pins),
+ GROUP("sd5_grp", sd5_pins),
+ GROUP("sd6_grp0", sd6_pins0),
+ GROUP("sd6_grp1", sd6_pins1),
+ GROUP("sp0_ext_ldo_on_grp", sp0_ext_ldo_on_pins),
+ GROUP("sp0_qspi_grp", sp0_qspi_pins),
+ GROUP("sp1_spi_grp", sp1_spi_pins),
+ GROUP("tpiu_trace_grp", tpiu_trace_pins),
+ GROUP("uart0_grp", uart0_pins),
+ GROUP("uart0_nopause_grp", uart0_nopause_pins),
+ GROUP("uart1_grp", uart1_pins),
+ GROUP("uart2_grp", uart2_pins),
+ GROUP("uart3_grp0", uart3_pins0),
+ GROUP("uart3_grp1", uart3_pins1),
+ GROUP("uart3_grp2", uart3_pins2),
+ GROUP("uart3_grp3", uart3_pins3),
+ GROUP("uart3_nopause_grp0", uart3_nopause_pins0),
+ GROUP("uart3_nopause_grp1", uart3_nopause_pins1),
+ GROUP("uart4_grp0", uart4_pins0),
+ GROUP("uart4_grp1", uart4_pins1),
+ GROUP("uart4_grp2", uart4_pins2),
+ GROUP("uart4_nopause_grp", uart4_nopause_pins),
+ GROUP("usb0_drvvbus_grp", usb0_drvvbus_pins),
+ GROUP("usb1_drvvbus_grp", usb1_drvvbus_pins),
+ GROUP("visbus_dout_grp", visbus_dout_pins),
+ GROUP("vi_vip1_grp", vi_vip1_pins),
+ GROUP("vi_vip1_ext_grp", vi_vip1_ext_pins),
+ GROUP("vi_vip1_low8bit_grp", vi_vip1_low8bit_pins),
+ GROUP("vi_vip1_high8bit_grp", vi_vip1_high8bit_pins),
+};
+
+/* How many groups that a function can use */
+static const char * const gnss_gpio_grp[] = { "gnss_gpio_grp", };
+static const char * const lcd_vip_gpio_grp[] = { "lcd_vip_gpio_grp", };
+static const char * const sdio_i2s_gpio_grp[] = { "sdio_i2s_gpio_grp", };
+static const char * const sp_rgmii_gpio_grp[] = { "sp_rgmii_gpio_grp", };
+static const char * const lvds_gpio_grp[] = { "lvds_gpio_grp", };
+static const char * const uart_nand_gpio_grp[] = { "uart_nand_gpio_grp", };
+static const char * const rtc_gpio_grp[] = { "rtc_gpio_grp", };
+static const char * const audio_ac97_grp[] = { "audio_ac97_grp", };
+static const char * const audio_func_dbg_grp[] = { "audio_func_dbg_grp", };
+static const char * const audio_i2s_grp[] = { "audio_i2s_grp", };
+static const char * const audio_i2s_2ch_grp[] = { "audio_i2s_2ch_grp", };
+static const char * const audio_i2s_extclk_grp[] = { "audio_i2s_extclk_grp", };
+static const char * const audio_uart0_grp[] = { "audio_uart0_grp", };
+static const char * const audio_uart1_grp[] = { "audio_uart1_grp", };
+static const char * const audio_uart2_grp0[] = { "audio_uart2_grp0", };
+static const char * const audio_uart2_grp1[] = { "audio_uart2_grp1", };
+static const char * const c_can_trnsvr_grp[] = { "c_can_trnsvr_grp", };
+static const char * const c0_can_grp0[] = { "c0_can_grp0", };
+static const char * const c0_can_grp1[] = { "c0_can_grp1", };
+static const char * const c1_can_grp0[] = { "c1_can_grp0", };
+static const char * const c1_can_grp1[] = { "c1_can_grp1", };
+static const char * const c1_can_grp2[] = { "c1_can_grp2", };
+static const char * const ca_audio_lpc_grp[] = { "ca_audio_lpc_grp", };
+static const char * const ca_bt_lpc_grp[] = { "ca_bt_lpc_grp", };
+static const char * const ca_coex_grp[] = { "ca_coex_grp", };
+static const char * const ca_curator_lpc_grp[] = { "ca_curator_lpc_grp", };
+static const char * const ca_pcm_debug_grp[] = { "ca_pcm_debug_grp", };
+static const char * const ca_pio_grp[] = { "ca_pio_grp", };
+static const char * const ca_sdio_debug_grp[] = { "ca_sdio_debug_grp", };
+static const char * const ca_spi_grp[] = { "ca_spi_grp", };
+static const char * const ca_trb_grp[] = { "ca_trb_grp", };
+static const char * const ca_uart_debug_grp[] = { "ca_uart_debug_grp", };
+static const char * const clkc_grp0[] = { "clkc_grp0", };
+static const char * const clkc_grp1[] = { "clkc_grp1", };
+static const char * const gn_gnss_i2c_grp[] = { "gn_gnss_i2c_grp", };
+static const char * const gn_gnss_uart_nopause_grp[] = {
+ "gn_gnss_uart_nopause_grp", };
+static const char * const gn_gnss_uart_grp[] = { "gn_gnss_uart_grp", };
+static const char * const gn_trg_spi_grp0[] = { "gn_trg_spi_grp0", };
+static const char * const gn_trg_spi_grp1[] = { "gn_trg_spi_grp1", };
+static const char * const cvbs_dbg_grp[] = { "cvbs_dbg_grp", };
+static const char * const cvbs_dbg_test_grp0[] = { "cvbs_dbg_test_grp0", };
+static const char * const cvbs_dbg_test_grp1[] = { "cvbs_dbg_test_grp1", };
+static const char * const cvbs_dbg_test_grp2[] = { "cvbs_dbg_test_grp2", };
+static const char * const cvbs_dbg_test_grp3[] = { "cvbs_dbg_test_grp3", };
+static const char * const cvbs_dbg_test_grp4[] = { "cvbs_dbg_test_grp4", };
+static const char * const cvbs_dbg_test_grp5[] = { "cvbs_dbg_test_grp5", };
+static const char * const cvbs_dbg_test_grp6[] = { "cvbs_dbg_test_grp6", };
+static const char * const cvbs_dbg_test_grp7[] = { "cvbs_dbg_test_grp7", };
+static const char * const cvbs_dbg_test_grp8[] = { "cvbs_dbg_test_grp8", };
+static const char * const cvbs_dbg_test_grp9[] = { "cvbs_dbg_test_grp9", };
+static const char * const cvbs_dbg_test_grp10[] = { "cvbs_dbg_test_grp10", };
+static const char * const cvbs_dbg_test_grp11[] = { "cvbs_dbg_test_grp11", };
+static const char * const cvbs_dbg_test_grp12[] = { "cvbs_dbg_test_grp12", };
+static const char * const cvbs_dbg_test_grp13[] = { "cvbs_dbg_test_grp13", };
+static const char * const cvbs_dbg_test_grp14[] = { "cvbs_dbg_test_grp14", };
+static const char * const cvbs_dbg_test_grp15[] = { "cvbs_dbg_test_grp15", };
+static const char * const gn_gnss_power_grp[] = { "gn_gnss_power_grp", };
+static const char * const gn_gnss_sw_status_grp[] = {
+ "gn_gnss_sw_status_grp", };
+static const char * const gn_gnss_eclk_grp[] = { "gn_gnss_eclk_grp", };
+static const char * const gn_gnss_irq1_grp0[] = { "gn_gnss_irq1_grp0", };
+static const char * const gn_gnss_irq2_grp0[] = { "gn_gnss_irq2_grp0", };
+static const char * const gn_gnss_tm_grp[] = { "gn_gnss_tm_grp", };
+static const char * const gn_gnss_tsync_grp[] = { "gn_gnss_tsync_grp", };
+static const char * const gn_io_gnsssys_sw_cfg_grp[] = {
+ "gn_io_gnsssys_sw_cfg_grp", };
+static const char * const gn_trg_grp0[] = { "gn_trg_grp0", };
+static const char * const gn_trg_grp1[] = { "gn_trg_grp1", };
+static const char * const gn_trg_shutdown_grp0[] = { "gn_trg_shutdown_grp0", };
+static const char * const gn_trg_shutdown_grp1[] = { "gn_trg_shutdown_grp1", };
+static const char * const gn_trg_shutdown_grp2[] = { "gn_trg_shutdown_grp2", };
+static const char * const gn_trg_shutdown_grp3[] = { "gn_trg_shutdown_grp3", };
+static const char * const i2c0_grp[] = { "i2c0_grp", };
+static const char * const i2c1_grp[] = { "i2c1_grp", };
+static const char * const jtag_grp0[] = { "jtag_grp0", };
+static const char * const ks_kas_spi_grp0[] = { "ks_kas_spi_grp0", };
+static const char * const ld_ldd_grp[] = { "ld_ldd_grp", };
+static const char * const ld_ldd_16bit_grp[] = { "ld_ldd_16bit_grp", };
+static const char * const ld_ldd_fck_grp[] = { "ld_ldd_fck_grp", };
+static const char * const ld_ldd_lck_grp[] = { "ld_ldd_lck_grp", };
+static const char * const lr_lcdrom_grp[] = { "lr_lcdrom_grp", };
+static const char * const lvds_analog_grp[] = { "lvds_analog_grp", };
+static const char * const nd_df_grp[] = { "nd_df_grp", };
+static const char * const nd_df_nowp_grp[] = { "nd_df_nowp_grp", };
+static const char * const ps_grp[] = { "ps_grp", };
+static const char * const pwc_core_on_grp[] = { "pwc_core_on_grp", };
+static const char * const pwc_ext_on_grp[] = { "pwc_ext_on_grp", };
+static const char * const pwc_gpio3_clk_grp[] = { "pwc_gpio3_clk_grp", };
+static const char * const pwc_io_on_grp[] = { "pwc_io_on_grp", };
+static const char * const pwc_lowbatt_b_grp0[] = { "pwc_lowbatt_b_grp0", };
+static const char * const pwc_mem_on_grp[] = { "pwc_mem_on_grp", };
+static const char * const pwc_on_key_b_grp0[] = { "pwc_on_key_b_grp0", };
+static const char * const pwc_wakeup_src0_grp[] = { "pwc_wakeup_src0_grp", };
+static const char * const pwc_wakeup_src1_grp[] = { "pwc_wakeup_src1_grp", };
+static const char * const pwc_wakeup_src2_grp[] = { "pwc_wakeup_src2_grp", };
+static const char * const pwc_wakeup_src3_grp[] = { "pwc_wakeup_src3_grp", };
+static const char * const pw_cko0_grp0[] = { "pw_cko0_grp0", };
+static const char * const pw_cko0_grp1[] = { "pw_cko0_grp1", };
+static const char * const pw_cko0_grp2[] = { "pw_cko0_grp2", };
+static const char * const pw_cko1_grp0[] = { "pw_cko1_grp0", };
+static const char * const pw_cko1_grp1[] = { "pw_cko1_grp1", };
+static const char * const pw_i2s01_clk_grp0[] = { "pw_i2s01_clk_grp0", };
+static const char * const pw_i2s01_clk_grp1[] = { "pw_i2s01_clk_grp1", };
+static const char * const pw_pwm0_grp[] = { "pw_pwm0_grp", };
+static const char * const pw_pwm1_grp[] = { "pw_pwm1_grp", };
+static const char * const pw_pwm2_grp0[] = { "pw_pwm2_grp0", };
+static const char * const pw_pwm2_grp1[] = { "pw_pwm2_grp1", };
+static const char * const pw_pwm3_grp0[] = { "pw_pwm3_grp0", };
+static const char * const pw_pwm3_grp1[] = { "pw_pwm3_grp1", };
+static const char * const pw_pwm_cpu_vol_grp0[] = { "pw_pwm_cpu_vol_grp0", };
+static const char * const pw_pwm_cpu_vol_grp1[] = { "pw_pwm_cpu_vol_grp1", };
+static const char * const pw_backlight_grp0[] = { "pw_backlight_grp0", };
+static const char * const pw_backlight_grp1[] = { "pw_backlight_grp1", };
+static const char * const rg_eth_mac_grp[] = { "rg_eth_mac_grp", };
+static const char * const rg_gmac_phy_intr_n_grp[] = {
+ "rg_gmac_phy_intr_n_grp", };
+static const char * const rg_rgmii_mac_grp[] = { "rg_rgmii_mac_grp", };
+static const char * const rg_rgmii_phy_ref_clk_grp0[] = {
+ "rg_rgmii_phy_ref_clk_grp0", };
+static const char * const rg_rgmii_phy_ref_clk_grp1[] = {
+ "rg_rgmii_phy_ref_clk_grp1", };
+static const char * const sd0_grp[] = { "sd0_grp", };
+static const char * const sd0_4bit_grp[] = { "sd0_4bit_grp", };
+static const char * const sd1_grp[] = { "sd1_grp", };
+static const char * const sd1_4bit_grp0[] = { "sd1_4bit_grp0", };
+static const char * const sd1_4bit_grp1[] = { "sd1_4bit_grp1", };
+static const char * const sd2_grp0[] = { "sd2_grp0", };
+static const char * const sd2_no_cdb_grp0[] = { "sd2_no_cdb_grp0", };
+static const char * const sd3_grp[] = { "sd3_grp", };
+static const char * const sd5_grp[] = { "sd5_grp", };
+static const char * const sd6_grp0[] = { "sd6_grp0", };
+static const char * const sd6_grp1[] = { "sd6_grp1", };
+static const char * const sp0_ext_ldo_on_grp[] = { "sp0_ext_ldo_on_grp", };
+static const char * const sp0_qspi_grp[] = { "sp0_qspi_grp", };
+static const char * const sp1_spi_grp[] = { "sp1_spi_grp", };
+static const char * const tpiu_trace_grp[] = { "tpiu_trace_grp", };
+static const char * const uart0_grp[] = { "uart0_grp", };
+static const char * const uart0_nopause_grp[] = { "uart0_nopause_grp", };
+static const char * const uart1_grp[] = { "uart1_grp", };
+static const char * const uart2_grp[] = { "uart2_grp", };
+static const char * const uart3_grp0[] = { "uart3_grp0", };
+static const char * const uart3_grp1[] = { "uart3_grp1", };
+static const char * const uart3_grp2[] = { "uart3_grp2", };
+static const char * const uart3_grp3[] = { "uart3_grp3", };
+static const char * const uart3_nopause_grp0[] = { "uart3_nopause_grp0", };
+static const char * const uart3_nopause_grp1[] = { "uart3_nopause_grp1", };
+static const char * const uart4_grp0[] = { "uart4_grp0", };
+static const char * const uart4_grp1[] = { "uart4_grp1", };
+static const char * const uart4_grp2[] = { "uart4_grp2", };
+static const char * const uart4_nopause_grp[] = { "uart4_nopause_grp", };
+static const char * const usb0_drvvbus_grp[] = { "usb0_drvvbus_grp", };
+static const char * const usb1_drvvbus_grp[] = { "usb1_drvvbus_grp", };
+static const char * const visbus_dout_grp[] = { "visbus_dout_grp", };
+static const char * const vi_vip1_grp[] = { "vi_vip1_grp", };
+static const char * const vi_vip1_ext_grp[] = { "vi_vip1_ext_grp", };
+static const char * const vi_vip1_low8bit_grp[] = { "vi_vip1_low8bit_grp", };
+static const char * const vi_vip1_high8bit_grp[] = { "vi_vip1_high8bit_grp", };
+
+static struct atlas7_pad_mux gnss_gpio_grp_pad_mux[] = {
+ MUX(1, 119, 0, N, N, N, N),
+ MUX(1, 120, 0, N, N, N, N),
+ MUX(1, 121, 0, N, N, N, N),
+ MUX(1, 122, 0, N, N, N, N),
+ MUX(1, 123, 0, N, N, N, N),
+ MUX(1, 124, 0, N, N, N, N),
+ MUX(1, 125, 0, N, N, N, N),
+ MUX(1, 126, 0, N, N, N, N),
+ MUX(1, 127, 0, N, N, N, N),
+ MUX(1, 128, 0, N, N, N, N),
+ MUX(1, 22, 0, N, N, N, N),
+ MUX(1, 23, 0, N, N, N, N),
+ MUX(1, 24, 0, N, N, N, N),
+ MUX(1, 25, 0, N, N, N, N),
+ MUX(1, 26, 0, N, N, N, N),
+ MUX(1, 27, 0, N, N, N, N),
+ MUX(1, 28, 0, N, N, N, N),
+ MUX(1, 29, 0, N, N, N, N),
+ MUX(1, 30, 0, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gnss_gpio_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(gnss_gpio_grp_pad_mux),
+ .pad_mux_list = gnss_gpio_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux lcd_vip_gpio_grp_pad_mux[] = {
+ MUX(1, 74, 0, N, N, N, N),
+ MUX(1, 75, 0, N, N, N, N),
+ MUX(1, 76, 0, N, N, N, N),
+ MUX(1, 77, 0, N, N, N, N),
+ MUX(1, 78, 0, N, N, N, N),
+ MUX(1, 79, 0, N, N, N, N),
+ MUX(1, 80, 0, N, N, N, N),
+ MUX(1, 81, 0, N, N, N, N),
+ MUX(1, 82, 0, N, N, N, N),
+ MUX(1, 83, 0, N, N, N, N),
+ MUX(1, 84, 0, N, N, N, N),
+ MUX(1, 53, 0, N, N, N, N),
+ MUX(1, 54, 0, N, N, N, N),
+ MUX(1, 55, 0, N, N, N, N),
+ MUX(1, 56, 0, N, N, N, N),
+ MUX(1, 57, 0, N, N, N, N),
+ MUX(1, 58, 0, N, N, N, N),
+ MUX(1, 59, 0, N, N, N, N),
+ MUX(1, 60, 0, N, N, N, N),
+ MUX(1, 61, 0, N, N, N, N),
+ MUX(1, 62, 0, N, N, N, N),
+ MUX(1, 63, 0, N, N, N, N),
+ MUX(1, 64, 0, N, N, N, N),
+ MUX(1, 65, 0, N, N, N, N),
+ MUX(1, 66, 0, N, N, N, N),
+ MUX(1, 67, 0, N, N, N, N),
+ MUX(1, 68, 0, N, N, N, N),
+ MUX(1, 69, 0, N, N, N, N),
+ MUX(1, 70, 0, N, N, N, N),
+ MUX(1, 71, 0, N, N, N, N),
+ MUX(1, 72, 0, N, N, N, N),
+ MUX(1, 73, 0, N, N, N, N),
+};
+
+static struct atlas7_grp_mux lcd_vip_gpio_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(lcd_vip_gpio_grp_pad_mux),
+ .pad_mux_list = lcd_vip_gpio_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux sdio_i2s_gpio_grp_pad_mux[] = {
+ MUX(1, 31, 0, N, N, N, N),
+ MUX(1, 32, 0, N, N, N, N),
+ MUX(1, 33, 0, N, N, N, N),
+ MUX(1, 34, 0, N, N, N, N),
+ MUX(1, 35, 0, N, N, N, N),
+ MUX(1, 36, 0, N, N, N, N),
+ MUX(1, 85, 0, N, N, N, N),
+ MUX(1, 86, 0, N, N, N, N),
+ MUX(1, 87, 0, N, N, N, N),
+ MUX(1, 88, 0, N, N, N, N),
+ MUX(1, 89, 0, N, N, N, N),
+ MUX(1, 90, 0, N, N, N, N),
+ MUX(1, 129, 0, N, N, N, N),
+ MUX(1, 130, 0, N, N, N, N),
+ MUX(1, 131, 0, N, N, N, N),
+ MUX(1, 132, 0, N, N, N, N),
+ MUX(1, 91, 0, N, N, N, N),
+ MUX(1, 92, 0, N, N, N, N),
+ MUX(1, 93, 0, N, N, N, N),
+ MUX(1, 94, 0, N, N, N, N),
+ MUX(1, 95, 0, N, N, N, N),
+ MUX(1, 96, 0, N, N, N, N),
+ MUX(1, 112, 0, N, N, N, N),
+ MUX(1, 113, 0, N, N, N, N),
+ MUX(1, 114, 0, N, N, N, N),
+ MUX(1, 115, 0, N, N, N, N),
+ MUX(1, 116, 0, N, N, N, N),
+ MUX(1, 117, 0, N, N, N, N),
+ MUX(1, 118, 0, N, N, N, N),
+};
+
+static struct atlas7_grp_mux sdio_i2s_gpio_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(sdio_i2s_gpio_grp_pad_mux),
+ .pad_mux_list = sdio_i2s_gpio_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux sp_rgmii_gpio_grp_pad_mux[] = {
+ MUX(1, 97, 0, N, N, N, N),
+ MUX(1, 98, 0, N, N, N, N),
+ MUX(1, 99, 0, N, N, N, N),
+ MUX(1, 100, 0, N, N, N, N),
+ MUX(1, 101, 0, N, N, N, N),
+ MUX(1, 102, 0, N, N, N, N),
+ MUX(1, 103, 0, N, N, N, N),
+ MUX(1, 104, 0, N, N, N, N),
+ MUX(1, 105, 0, N, N, N, N),
+ MUX(1, 106, 0, N, N, N, N),
+ MUX(1, 107, 0, N, N, N, N),
+ MUX(1, 108, 0, N, N, N, N),
+ MUX(1, 109, 0, N, N, N, N),
+ MUX(1, 110, 0, N, N, N, N),
+ MUX(1, 111, 0, N, N, N, N),
+ MUX(1, 18, 0, N, N, N, N),
+ MUX(1, 19, 0, N, N, N, N),
+ MUX(1, 20, 0, N, N, N, N),
+ MUX(1, 21, 0, N, N, N, N),
+ MUX(1, 141, 0, N, N, N, N),
+ MUX(1, 142, 0, N, N, N, N),
+ MUX(1, 143, 0, N, N, N, N),
+ MUX(1, 144, 0, N, N, N, N),
+ MUX(1, 145, 0, N, N, N, N),
+ MUX(1, 146, 0, N, N, N, N),
+ MUX(1, 147, 0, N, N, N, N),
+ MUX(1, 148, 0, N, N, N, N),
+};
+
+static struct atlas7_grp_mux sp_rgmii_gpio_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(sp_rgmii_gpio_grp_pad_mux),
+ .pad_mux_list = sp_rgmii_gpio_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux lvds_gpio_grp_pad_mux[] = {
+ MUX(1, 157, 0, N, N, N, N),
+ MUX(1, 158, 0, N, N, N, N),
+ MUX(1, 155, 0, N, N, N, N),
+ MUX(1, 156, 0, N, N, N, N),
+ MUX(1, 153, 0, N, N, N, N),
+ MUX(1, 154, 0, N, N, N, N),
+ MUX(1, 151, 0, N, N, N, N),
+ MUX(1, 152, 0, N, N, N, N),
+ MUX(1, 149, 0, N, N, N, N),
+ MUX(1, 150, 0, N, N, N, N),
+};
+
+static struct atlas7_grp_mux lvds_gpio_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(lvds_gpio_grp_pad_mux),
+ .pad_mux_list = lvds_gpio_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux uart_nand_gpio_grp_pad_mux[] = {
+ MUX(1, 44, 0, N, N, N, N),
+ MUX(1, 43, 0, N, N, N, N),
+ MUX(1, 42, 0, N, N, N, N),
+ MUX(1, 41, 0, N, N, N, N),
+ MUX(1, 40, 0, N, N, N, N),
+ MUX(1, 39, 0, N, N, N, N),
+ MUX(1, 38, 0, N, N, N, N),
+ MUX(1, 37, 0, N, N, N, N),
+ MUX(1, 46, 0, N, N, N, N),
+ MUX(1, 47, 0, N, N, N, N),
+ MUX(1, 48, 0, N, N, N, N),
+ MUX(1, 49, 0, N, N, N, N),
+ MUX(1, 50, 0, N, N, N, N),
+ MUX(1, 52, 0, N, N, N, N),
+ MUX(1, 51, 0, N, N, N, N),
+ MUX(1, 45, 0, N, N, N, N),
+ MUX(1, 133, 0, N, N, N, N),
+ MUX(1, 134, 0, N, N, N, N),
+ MUX(1, 135, 0, N, N, N, N),
+ MUX(1, 136, 0, N, N, N, N),
+ MUX(1, 137, 0, N, N, N, N),
+ MUX(1, 138, 0, N, N, N, N),
+ MUX(1, 139, 0, N, N, N, N),
+ MUX(1, 140, 0, N, N, N, N),
+};
+
+static struct atlas7_grp_mux uart_nand_gpio_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(uart_nand_gpio_grp_pad_mux),
+ .pad_mux_list = uart_nand_gpio_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux rtc_gpio_grp_pad_mux[] = {
+ MUX(0, 0, 0, N, N, N, N),
+ MUX(0, 1, 0, N, N, N, N),
+ MUX(0, 2, 0, N, N, N, N),
+ MUX(0, 3, 0, N, N, N, N),
+ MUX(0, 4, 0, N, N, N, N),
+ MUX(0, 10, 0, N, N, N, N),
+ MUX(0, 11, 0, N, N, N, N),
+ MUX(0, 12, 0, N, N, N, N),
+ MUX(0, 13, 0, N, N, N, N),
+ MUX(0, 14, 0, N, N, N, N),
+ MUX(0, 15, 0, N, N, N, N),
+ MUX(0, 16, 0, N, N, N, N),
+ MUX(0, 17, 0, N, N, N, N),
+};
+
+static struct atlas7_grp_mux rtc_gpio_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(rtc_gpio_grp_pad_mux),
+ .pad_mux_list = rtc_gpio_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux audio_ac97_grp_pad_mux[] = {
+ MUX(1, 113, 2, N, N, N, N),
+ MUX(1, 118, 2, N, N, N, N),
+ MUX(1, 115, 2, N, N, N, N),
+ MUX(1, 114, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux audio_ac97_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(audio_ac97_grp_pad_mux),
+ .pad_mux_list = audio_ac97_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux audio_func_dbg_grp_pad_mux[] = {
+ MUX(1, 141, 4, N, N, N, N),
+ MUX(1, 144, 4, N, N, N, N),
+ MUX(1, 44, 6, N, N, N, N),
+ MUX(1, 43, 6, N, N, N, N),
+ MUX(1, 42, 6, N, N, N, N),
+ MUX(1, 41, 6, N, N, N, N),
+ MUX(1, 40, 6, N, N, N, N),
+ MUX(1, 39, 6, N, N, N, N),
+ MUX(1, 38, 6, N, N, N, N),
+ MUX(1, 37, 6, N, N, N, N),
+ MUX(1, 74, 6, N, N, N, N),
+ MUX(1, 75, 6, N, N, N, N),
+ MUX(1, 76, 6, N, N, N, N),
+ MUX(1, 77, 6, N, N, N, N),
+ MUX(1, 78, 6, N, N, N, N),
+ MUX(1, 79, 6, N, N, N, N),
+ MUX(1, 81, 6, N, N, N, N),
+ MUX(1, 113, 6, N, N, N, N),
+ MUX(1, 114, 6, N, N, N, N),
+ MUX(1, 118, 6, N, N, N, N),
+ MUX(1, 115, 6, N, N, N, N),
+ MUX(1, 49, 6, N, N, N, N),
+ MUX(1, 50, 6, N, N, N, N),
+ MUX(1, 142, 4, N, N, N, N),
+ MUX(1, 143, 4, N, N, N, N),
+ MUX(1, 80, 6, N, N, N, N),
+};
+
+static struct atlas7_grp_mux audio_func_dbg_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(audio_func_dbg_grp_pad_mux),
+ .pad_mux_list = audio_func_dbg_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux audio_i2s_grp_pad_mux[] = {
+ MUX(1, 118, 1, N, N, N, N),
+ MUX(1, 115, 1, N, N, N, N),
+ MUX(1, 116, 1, N, N, N, N),
+ MUX(1, 117, 1, N, N, N, N),
+ MUX(1, 112, 1, N, N, N, N),
+ MUX(1, 113, 1, N, N, N, N),
+ MUX(1, 114, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux audio_i2s_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(audio_i2s_grp_pad_mux),
+ .pad_mux_list = audio_i2s_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux audio_i2s_2ch_grp_pad_mux[] = {
+ MUX(1, 118, 1, N, N, N, N),
+ MUX(1, 115, 1, N, N, N, N),
+ MUX(1, 112, 1, N, N, N, N),
+ MUX(1, 113, 1, N, N, N, N),
+ MUX(1, 114, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux audio_i2s_2ch_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(audio_i2s_2ch_grp_pad_mux),
+ .pad_mux_list = audio_i2s_2ch_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux audio_i2s_extclk_grp_pad_mux[] = {
+ MUX(1, 112, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux audio_i2s_extclk_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(audio_i2s_extclk_grp_pad_mux),
+ .pad_mux_list = audio_i2s_extclk_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux audio_uart0_grp_pad_mux[] = {
+ MUX(1, 143, 1, N, N, N, N),
+ MUX(1, 142, 1, N, N, N, N),
+ MUX(1, 141, 1, N, N, N, N),
+ MUX(1, 144, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux audio_uart0_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(audio_uart0_grp_pad_mux),
+ .pad_mux_list = audio_uart0_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux audio_uart1_grp_pad_mux[] = {
+ MUX(1, 147, 1, N, N, N, N),
+ MUX(1, 146, 1, N, N, N, N),
+ MUX(1, 145, 1, N, N, N, N),
+ MUX(1, 148, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux audio_uart1_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(audio_uart1_grp_pad_mux),
+ .pad_mux_list = audio_uart1_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux audio_uart2_grp0_pad_mux[] = {
+ MUX(1, 20, 2, 0xa00, 24, 0xa80, 24),
+ MUX(1, 21, 2, 0xa00, 25, 0xa80, 25),
+ MUX(1, 19, 2, 0xa00, 23, 0xa80, 23),
+ MUX(1, 18, 2, 0xa00, 22, 0xa80, 22),
+};
+
+static struct atlas7_grp_mux audio_uart2_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(audio_uart2_grp0_pad_mux),
+ .pad_mux_list = audio_uart2_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux audio_uart2_grp1_pad_mux[] = {
+ MUX(1, 109, 2, 0xa00, 24, 0xa80, 24),
+ MUX(1, 110, 2, 0xa00, 25, 0xa80, 25),
+ MUX(1, 101, 2, 0xa00, 23, 0xa80, 23),
+ MUX(1, 111, 2, 0xa00, 22, 0xa80, 22),
+};
+
+static struct atlas7_grp_mux audio_uart2_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(audio_uart2_grp1_pad_mux),
+ .pad_mux_list = audio_uart2_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux c_can_trnsvr_grp_pad_mux[] = {
+ MUX(0, 1, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux c_can_trnsvr_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(c_can_trnsvr_grp_pad_mux),
+ .pad_mux_list = c_can_trnsvr_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux c0_can_grp0_pad_mux[] = {
+ MUX(0, 11, 1, 0xa08, 9, 0xa88, 9),
+ MUX(0, 10, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux c0_can_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(c0_can_grp0_pad_mux),
+ .pad_mux_list = c0_can_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux c0_can_grp1_pad_mux[] = {
+ MUX(0, 2, 5, 0xa08, 9, 0xa88, 9),
+ MUX(0, 3, 5, N, N, N, N),
+};
+
+static struct atlas7_grp_mux c0_can_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(c0_can_grp1_pad_mux),
+ .pad_mux_list = c0_can_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux c1_can_grp0_pad_mux[] = {
+ MUX(1, 138, 2, 0xa00, 4, 0xa80, 4),
+ MUX(1, 137, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux c1_can_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(c1_can_grp0_pad_mux),
+ .pad_mux_list = c1_can_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux c1_can_grp1_pad_mux[] = {
+ MUX(1, 147, 2, 0xa00, 4, 0xa80, 4),
+ MUX(1, 146, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux c1_can_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(c1_can_grp1_pad_mux),
+ .pad_mux_list = c1_can_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux c1_can_grp2_pad_mux[] = {
+ MUX(0, 2, 2, 0xa00, 4, 0xa80, 4),
+ MUX(0, 3, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux c1_can_grp2_mux = {
+ .pad_mux_count = ARRAY_SIZE(c1_can_grp2_pad_mux),
+ .pad_mux_list = c1_can_grp2_pad_mux,
+};
+
+static struct atlas7_pad_mux ca_audio_lpc_grp_pad_mux[] = {
+ MUX(1, 62, 4, N, N, N, N),
+ MUX(1, 63, 4, N, N, N, N),
+ MUX(1, 64, 4, N, N, N, N),
+ MUX(1, 65, 4, N, N, N, N),
+ MUX(1, 66, 4, N, N, N, N),
+ MUX(1, 67, 4, N, N, N, N),
+ MUX(1, 68, 4, N, N, N, N),
+ MUX(1, 69, 4, N, N, N, N),
+ MUX(1, 70, 4, N, N, N, N),
+ MUX(1, 71, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ca_audio_lpc_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ca_audio_lpc_grp_pad_mux),
+ .pad_mux_list = ca_audio_lpc_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux ca_bt_lpc_grp_pad_mux[] = {
+ MUX(1, 85, 5, N, N, N, N),
+ MUX(1, 86, 5, N, N, N, N),
+ MUX(1, 87, 5, N, N, N, N),
+ MUX(1, 88, 5, N, N, N, N),
+ MUX(1, 89, 5, N, N, N, N),
+ MUX(1, 90, 5, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ca_bt_lpc_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ca_bt_lpc_grp_pad_mux),
+ .pad_mux_list = ca_bt_lpc_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux ca_coex_grp_pad_mux[] = {
+ MUX(1, 129, 1, N, N, N, N),
+ MUX(1, 130, 1, N, N, N, N),
+ MUX(1, 131, 1, N, N, N, N),
+ MUX(1, 132, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ca_coex_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ca_coex_grp_pad_mux),
+ .pad_mux_list = ca_coex_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux ca_curator_lpc_grp_pad_mux[] = {
+ MUX(1, 57, 4, N, N, N, N),
+ MUX(1, 58, 4, N, N, N, N),
+ MUX(1, 59, 4, N, N, N, N),
+ MUX(1, 60, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ca_curator_lpc_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ca_curator_lpc_grp_pad_mux),
+ .pad_mux_list = ca_curator_lpc_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux ca_pcm_debug_grp_pad_mux[] = {
+ MUX(1, 91, 5, N, N, N, N),
+ MUX(1, 93, 5, N, N, N, N),
+ MUX(1, 94, 5, N, N, N, N),
+ MUX(1, 92, 5, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ca_pcm_debug_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ca_pcm_debug_grp_pad_mux),
+ .pad_mux_list = ca_pcm_debug_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux ca_pio_grp_pad_mux[] = {
+ MUX(1, 121, 2, N, N, N, N),
+ MUX(1, 122, 2, N, N, N, N),
+ MUX(1, 125, 6, N, N, N, N),
+ MUX(1, 126, 6, N, N, N, N),
+ MUX(1, 38, 5, N, N, N, N),
+ MUX(1, 37, 5, N, N, N, N),
+ MUX(1, 47, 5, N, N, N, N),
+ MUX(1, 49, 5, N, N, N, N),
+ MUX(1, 50, 5, N, N, N, N),
+ MUX(1, 54, 4, N, N, N, N),
+ MUX(1, 55, 4, N, N, N, N),
+ MUX(1, 56, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ca_pio_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ca_pio_grp_pad_mux),
+ .pad_mux_list = ca_pio_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux ca_sdio_debug_grp_pad_mux[] = {
+ MUX(1, 40, 5, N, N, N, N),
+ MUX(1, 39, 5, N, N, N, N),
+ MUX(1, 44, 5, N, N, N, N),
+ MUX(1, 43, 5, N, N, N, N),
+ MUX(1, 42, 5, N, N, N, N),
+ MUX(1, 41, 5, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ca_sdio_debug_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ca_sdio_debug_grp_pad_mux),
+ .pad_mux_list = ca_sdio_debug_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux ca_spi_grp_pad_mux[] = {
+ MUX(1, 82, 5, N, N, N, N),
+ MUX(1, 79, 5, 0xa08, 6, 0xa88, 6),
+ MUX(1, 80, 5, N, N, N, N),
+ MUX(1, 81, 5, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ca_spi_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ca_spi_grp_pad_mux),
+ .pad_mux_list = ca_spi_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux ca_trb_grp_pad_mux[] = {
+ MUX(1, 91, 4, N, N, N, N),
+ MUX(1, 93, 4, N, N, N, N),
+ MUX(1, 94, 4, N, N, N, N),
+ MUX(1, 95, 4, N, N, N, N),
+ MUX(1, 96, 4, N, N, N, N),
+ MUX(1, 78, 5, N, N, N, N),
+ MUX(1, 74, 5, N, N, N, N),
+ MUX(1, 75, 5, N, N, N, N),
+ MUX(1, 76, 5, N, N, N, N),
+ MUX(1, 77, 5, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ca_trb_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ca_trb_grp_pad_mux),
+ .pad_mux_list = ca_trb_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux ca_uart_debug_grp_pad_mux[] = {
+ MUX(1, 136, 3, N, N, N, N),
+ MUX(1, 135, 3, N, N, N, N),
+ MUX(1, 134, 3, N, N, N, N),
+ MUX(1, 133, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ca_uart_debug_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ca_uart_debug_grp_pad_mux),
+ .pad_mux_list = ca_uart_debug_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux clkc_grp0_pad_mux[] = {
+ MUX(1, 30, 2, 0xa08, 14, 0xa88, 14),
+ MUX(1, 47, 6, N, N, N, N),
+};
+
+static struct atlas7_grp_mux clkc_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(clkc_grp0_pad_mux),
+ .pad_mux_list = clkc_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux clkc_grp1_pad_mux[] = {
+ MUX(1, 78, 3, 0xa08, 14, 0xa88, 14),
+ MUX(1, 54, 5, N, N, N, N),
+};
+
+static struct atlas7_grp_mux clkc_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(clkc_grp1_pad_mux),
+ .pad_mux_list = clkc_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_gnss_i2c_grp_pad_mux[] = {
+ MUX(1, 128, 2, N, N, N, N),
+ MUX(1, 127, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gn_gnss_i2c_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_gnss_i2c_grp_pad_mux),
+ .pad_mux_list = gn_gnss_i2c_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_gnss_uart_nopause_grp_pad_mux[] = {
+ MUX(1, 134, 4, N, N, N, N),
+ MUX(1, 133, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gn_gnss_uart_nopause_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_gnss_uart_nopause_grp_pad_mux),
+ .pad_mux_list = gn_gnss_uart_nopause_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_gnss_uart_grp_pad_mux[] = {
+ MUX(1, 134, 4, N, N, N, N),
+ MUX(1, 133, 4, N, N, N, N),
+ MUX(1, 136, 4, N, N, N, N),
+ MUX(1, 135, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gn_gnss_uart_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_gnss_uart_grp_pad_mux),
+ .pad_mux_list = gn_gnss_uart_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_trg_spi_grp0_pad_mux[] = {
+ MUX(1, 22, 1, N, N, N, N),
+ MUX(1, 25, 1, N, N, N, N),
+ MUX(1, 23, 1, 0xa00, 10, 0xa80, 10),
+ MUX(1, 24, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gn_trg_spi_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_trg_spi_grp0_pad_mux),
+ .pad_mux_list = gn_trg_spi_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_trg_spi_grp1_pad_mux[] = {
+ MUX(1, 82, 3, N, N, N, N),
+ MUX(1, 79, 3, N, N, N, N),
+ MUX(1, 80, 3, 0xa00, 10, 0xa80, 10),
+ MUX(1, 81, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gn_trg_spi_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_trg_spi_grp1_pad_mux),
+ .pad_mux_list = gn_trg_spi_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_grp_pad_mux[] = {
+ MUX(1, 54, 3, N, N, N, N),
+ MUX(1, 53, 3, N, N, N, N),
+ MUX(1, 82, 7, N, N, N, N),
+ MUX(1, 74, 7, N, N, N, N),
+ MUX(1, 75, 7, N, N, N, N),
+ MUX(1, 76, 7, N, N, N, N),
+ MUX(1, 77, 7, N, N, N, N),
+ MUX(1, 78, 7, N, N, N, N),
+ MUX(1, 79, 7, N, N, N, N),
+ MUX(1, 80, 7, N, N, N, N),
+ MUX(1, 81, 7, N, N, N, N),
+ MUX(1, 83, 7, N, N, N, N),
+ MUX(1, 84, 7, N, N, N, N),
+ MUX(1, 73, 3, N, N, N, N),
+ MUX(1, 55, 3, N, N, N, N),
+ MUX(1, 56, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_grp_pad_mux),
+ .pad_mux_list = cvbs_dbg_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp0_pad_mux[] = {
+ MUX(1, 57, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp0_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp1_pad_mux[] = {
+ MUX(1, 58, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp1_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp2_pad_mux[] = {
+ MUX(1, 59, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp2_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp2_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp2_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp3_pad_mux[] = {
+ MUX(1, 60, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp3_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp3_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp3_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp4_pad_mux[] = {
+ MUX(1, 61, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp4_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp4_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp4_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp5_pad_mux[] = {
+ MUX(1, 62, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp5_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp5_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp5_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp6_pad_mux[] = {
+ MUX(1, 63, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp6_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp6_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp6_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp7_pad_mux[] = {
+ MUX(1, 64, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp7_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp7_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp7_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp8_pad_mux[] = {
+ MUX(1, 65, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp8_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp8_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp8_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp9_pad_mux[] = {
+ MUX(1, 66, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp9_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp9_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp9_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp10_pad_mux[] = {
+ MUX(1, 67, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp10_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp10_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp10_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp11_pad_mux[] = {
+ MUX(1, 68, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp11_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp11_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp11_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp12_pad_mux[] = {
+ MUX(1, 69, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp12_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp12_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp12_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp13_pad_mux[] = {
+ MUX(1, 70, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp13_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp13_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp13_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp14_pad_mux[] = {
+ MUX(1, 71, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp14_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp14_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp14_pad_mux,
+};
+
+static struct atlas7_pad_mux cvbs_dbg_test_grp15_pad_mux[] = {
+ MUX(1, 72, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux cvbs_dbg_test_grp15_mux = {
+ .pad_mux_count = ARRAY_SIZE(cvbs_dbg_test_grp15_pad_mux),
+ .pad_mux_list = cvbs_dbg_test_grp15_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_gnss_power_grp_pad_mux[] = {
+ MUX(1, 123, 7, N, N, N, N),
+ MUX(1, 124, 7, N, N, N, N),
+ MUX(1, 121, 7, N, N, N, N),
+ MUX(1, 122, 7, N, N, N, N),
+ MUX(1, 125, 7, N, N, N, N),
+ MUX(1, 120, 7, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gn_gnss_power_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_gnss_power_grp_pad_mux),
+ .pad_mux_list = gn_gnss_power_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_gnss_sw_status_grp_pad_mux[] = {
+ MUX(1, 57, 7, N, N, N, N),
+ MUX(1, 58, 7, N, N, N, N),
+ MUX(1, 59, 7, N, N, N, N),
+ MUX(1, 60, 7, N, N, N, N),
+ MUX(1, 61, 7, N, N, N, N),
+ MUX(1, 62, 7, N, N, N, N),
+ MUX(1, 63, 7, N, N, N, N),
+ MUX(1, 64, 7, N, N, N, N),
+ MUX(1, 65, 7, N, N, N, N),
+ MUX(1, 66, 7, N, N, N, N),
+ MUX(1, 67, 7, N, N, N, N),
+ MUX(1, 68, 7, N, N, N, N),
+ MUX(1, 69, 7, N, N, N, N),
+ MUX(1, 70, 7, N, N, N, N),
+ MUX(1, 71, 7, N, N, N, N),
+ MUX(1, 72, 7, N, N, N, N),
+ MUX(1, 53, 7, N, N, N, N),
+ MUX(1, 55, 7, N, N, N, N),
+ MUX(1, 56, 7, 0xa08, 12, 0xa88, 12),
+ MUX(1, 54, 7, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gn_gnss_sw_status_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_gnss_sw_status_grp_pad_mux),
+ .pad_mux_list = gn_gnss_sw_status_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_gnss_eclk_grp_pad_mux[] = {
+ MUX(1, 113, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gn_gnss_eclk_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_gnss_eclk_grp_pad_mux),
+ .pad_mux_list = gn_gnss_eclk_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_gnss_irq1_grp0_pad_mux[] = {
+ MUX(1, 112, 4, 0xa08, 10, 0xa88, 10),
+};
+
+static struct atlas7_grp_mux gn_gnss_irq1_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_gnss_irq1_grp0_pad_mux),
+ .pad_mux_list = gn_gnss_irq1_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_gnss_irq2_grp0_pad_mux[] = {
+ MUX(1, 118, 4, 0xa08, 11, 0xa88, 11),
+};
+
+static struct atlas7_grp_mux gn_gnss_irq2_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_gnss_irq2_grp0_pad_mux),
+ .pad_mux_list = gn_gnss_irq2_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_gnss_tm_grp_pad_mux[] = {
+ MUX(1, 115, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gn_gnss_tm_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_gnss_tm_grp_pad_mux),
+ .pad_mux_list = gn_gnss_tm_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_gnss_tsync_grp_pad_mux[] = {
+ MUX(1, 114, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gn_gnss_tsync_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_gnss_tsync_grp_pad_mux),
+ .pad_mux_list = gn_gnss_tsync_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_io_gnsssys_sw_cfg_grp_pad_mux[] = {
+ MUX(1, 44, 7, N, N, N, N),
+ MUX(1, 43, 7, N, N, N, N),
+ MUX(1, 42, 7, N, N, N, N),
+ MUX(1, 41, 7, N, N, N, N),
+ MUX(1, 40, 7, N, N, N, N),
+ MUX(1, 39, 7, N, N, N, N),
+ MUX(1, 38, 7, N, N, N, N),
+ MUX(1, 37, 7, N, N, N, N),
+ MUX(1, 49, 7, N, N, N, N),
+ MUX(1, 50, 7, N, N, N, N),
+ MUX(1, 91, 7, N, N, N, N),
+ MUX(1, 92, 7, N, N, N, N),
+ MUX(1, 93, 7, N, N, N, N),
+ MUX(1, 94, 7, N, N, N, N),
+ MUX(1, 95, 7, N, N, N, N),
+ MUX(1, 96, 7, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gn_io_gnsssys_sw_cfg_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_io_gnsssys_sw_cfg_grp_pad_mux),
+ .pad_mux_list = gn_io_gnsssys_sw_cfg_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_trg_grp0_pad_mux[] = {
+ MUX(1, 29, 1, 0xa00, 6, 0xa80, 6),
+ MUX(1, 28, 1, 0xa00, 7, 0xa80, 7),
+ MUX(1, 26, 1, 0xa00, 8, 0xa80, 8),
+ MUX(1, 27, 1, 0xa00, 9, 0xa80, 9),
+};
+
+static struct atlas7_grp_mux gn_trg_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_trg_grp0_pad_mux),
+ .pad_mux_list = gn_trg_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_trg_grp1_pad_mux[] = {
+ MUX(1, 77, 3, 0xa00, 6, 0xa80, 6),
+ MUX(1, 76, 3, 0xa00, 7, 0xa80, 7),
+ MUX(1, 74, 3, 0xa00, 8, 0xa80, 8),
+ MUX(1, 75, 3, 0xa00, 9, 0xa80, 9),
+};
+
+static struct atlas7_grp_mux gn_trg_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_trg_grp1_pad_mux),
+ .pad_mux_list = gn_trg_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_trg_shutdown_grp0_pad_mux[] = {
+ MUX(1, 30, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gn_trg_shutdown_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_trg_shutdown_grp0_pad_mux),
+ .pad_mux_list = gn_trg_shutdown_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_trg_shutdown_grp1_pad_mux[] = {
+ MUX(1, 83, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gn_trg_shutdown_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_trg_shutdown_grp1_pad_mux),
+ .pad_mux_list = gn_trg_shutdown_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_trg_shutdown_grp2_pad_mux[] = {
+ MUX(1, 117, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gn_trg_shutdown_grp2_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_trg_shutdown_grp2_pad_mux),
+ .pad_mux_list = gn_trg_shutdown_grp2_pad_mux,
+};
+
+static struct atlas7_pad_mux gn_trg_shutdown_grp3_pad_mux[] = {
+ MUX(1, 123, 5, N, N, N, N),
+};
+
+static struct atlas7_grp_mux gn_trg_shutdown_grp3_mux = {
+ .pad_mux_count = ARRAY_SIZE(gn_trg_shutdown_grp3_pad_mux),
+ .pad_mux_list = gn_trg_shutdown_grp3_pad_mux,
+};
+
+static struct atlas7_pad_mux i2c0_grp_pad_mux[] = {
+ MUX(1, 128, 1, N, N, N, N),
+ MUX(1, 127, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux i2c0_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(i2c0_grp_pad_mux),
+ .pad_mux_list = i2c0_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux i2c1_grp_pad_mux[] = {
+ MUX(1, 126, 4, N, N, N, N),
+ MUX(1, 125, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux i2c1_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(i2c1_grp_pad_mux),
+ .pad_mux_list = i2c1_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux jtag_grp0_pad_mux[] = {
+ MUX(1, 125, 5, 0xa08, 2, 0xa88, 2),
+ MUX(0, 4, 3, 0xa08, 3, 0xa88, 3),
+ MUX(0, 2, 3, N, N, N, N),
+ MUX(0, 0, 3, N, N, N, N),
+ MUX(0, 1, 3, N, N, N, N),
+ MUX(0, 3, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux jtag_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(jtag_grp0_pad_mux),
+ .pad_mux_list = jtag_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux ks_kas_spi_grp0_pad_mux[] = {
+ MUX(1, 141, 2, N, N, N, N),
+ MUX(1, 144, 2, 0xa08, 8, 0xa88, 8),
+ MUX(1, 143, 2, N, N, N, N),
+ MUX(1, 142, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ks_kas_spi_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(ks_kas_spi_grp0_pad_mux),
+ .pad_mux_list = ks_kas_spi_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux ld_ldd_grp_pad_mux[] = {
+ MUX(1, 57, 1, N, N, N, N),
+ MUX(1, 58, 1, N, N, N, N),
+ MUX(1, 59, 1, N, N, N, N),
+ MUX(1, 60, 1, N, N, N, N),
+ MUX(1, 61, 1, N, N, N, N),
+ MUX(1, 62, 1, N, N, N, N),
+ MUX(1, 63, 1, N, N, N, N),
+ MUX(1, 64, 1, N, N, N, N),
+ MUX(1, 65, 1, N, N, N, N),
+ MUX(1, 66, 1, N, N, N, N),
+ MUX(1, 67, 1, N, N, N, N),
+ MUX(1, 68, 1, N, N, N, N),
+ MUX(1, 69, 1, N, N, N, N),
+ MUX(1, 70, 1, N, N, N, N),
+ MUX(1, 71, 1, N, N, N, N),
+ MUX(1, 72, 1, N, N, N, N),
+ MUX(1, 74, 2, N, N, N, N),
+ MUX(1, 75, 2, N, N, N, N),
+ MUX(1, 76, 2, N, N, N, N),
+ MUX(1, 77, 2, N, N, N, N),
+ MUX(1, 78, 2, N, N, N, N),
+ MUX(1, 79, 2, N, N, N, N),
+ MUX(1, 80, 2, N, N, N, N),
+ MUX(1, 81, 2, N, N, N, N),
+ MUX(1, 56, 1, N, N, N, N),
+ MUX(1, 53, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ld_ldd_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ld_ldd_grp_pad_mux),
+ .pad_mux_list = ld_ldd_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux ld_ldd_16bit_grp_pad_mux[] = {
+ MUX(1, 57, 1, N, N, N, N),
+ MUX(1, 58, 1, N, N, N, N),
+ MUX(1, 59, 1, N, N, N, N),
+ MUX(1, 60, 1, N, N, N, N),
+ MUX(1, 61, 1, N, N, N, N),
+ MUX(1, 62, 1, N, N, N, N),
+ MUX(1, 63, 1, N, N, N, N),
+ MUX(1, 64, 1, N, N, N, N),
+ MUX(1, 65, 1, N, N, N, N),
+ MUX(1, 66, 1, N, N, N, N),
+ MUX(1, 67, 1, N, N, N, N),
+ MUX(1, 68, 1, N, N, N, N),
+ MUX(1, 69, 1, N, N, N, N),
+ MUX(1, 70, 1, N, N, N, N),
+ MUX(1, 71, 1, N, N, N, N),
+ MUX(1, 72, 1, N, N, N, N),
+ MUX(1, 56, 1, N, N, N, N),
+ MUX(1, 53, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ld_ldd_16bit_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ld_ldd_16bit_grp_pad_mux),
+ .pad_mux_list = ld_ldd_16bit_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux ld_ldd_fck_grp_pad_mux[] = {
+ MUX(1, 55, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ld_ldd_fck_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ld_ldd_fck_grp_pad_mux),
+ .pad_mux_list = ld_ldd_fck_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux ld_ldd_lck_grp_pad_mux[] = {
+ MUX(1, 54, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ld_ldd_lck_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ld_ldd_lck_grp_pad_mux),
+ .pad_mux_list = ld_ldd_lck_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux lr_lcdrom_grp_pad_mux[] = {
+ MUX(1, 73, 2, N, N, N, N),
+ MUX(1, 54, 2, N, N, N, N),
+ MUX(1, 57, 2, N, N, N, N),
+ MUX(1, 58, 2, N, N, N, N),
+ MUX(1, 59, 2, N, N, N, N),
+ MUX(1, 60, 2, N, N, N, N),
+ MUX(1, 61, 2, N, N, N, N),
+ MUX(1, 62, 2, N, N, N, N),
+ MUX(1, 63, 2, N, N, N, N),
+ MUX(1, 64, 2, N, N, N, N),
+ MUX(1, 65, 2, N, N, N, N),
+ MUX(1, 66, 2, N, N, N, N),
+ MUX(1, 67, 2, N, N, N, N),
+ MUX(1, 68, 2, N, N, N, N),
+ MUX(1, 69, 2, N, N, N, N),
+ MUX(1, 70, 2, N, N, N, N),
+ MUX(1, 71, 2, N, N, N, N),
+ MUX(1, 72, 2, N, N, N, N),
+ MUX(1, 56, 2, N, N, N, N),
+ MUX(1, 53, 2, N, N, N, N),
+ MUX(1, 55, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux lr_lcdrom_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(lr_lcdrom_grp_pad_mux),
+ .pad_mux_list = lr_lcdrom_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux lvds_analog_grp_pad_mux[] = {
+ MUX(1, 149, 8, N, N, N, N),
+ MUX(1, 150, 8, N, N, N, N),
+ MUX(1, 151, 8, N, N, N, N),
+ MUX(1, 152, 8, N, N, N, N),
+ MUX(1, 153, 8, N, N, N, N),
+ MUX(1, 154, 8, N, N, N, N),
+ MUX(1, 155, 8, N, N, N, N),
+ MUX(1, 156, 8, N, N, N, N),
+ MUX(1, 157, 8, N, N, N, N),
+ MUX(1, 158, 8, N, N, N, N),
+};
+
+static struct atlas7_grp_mux lvds_analog_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(lvds_analog_grp_pad_mux),
+ .pad_mux_list = lvds_analog_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux nd_df_grp_pad_mux[] = {
+ MUX(1, 44, 1, N, N, N, N),
+ MUX(1, 43, 1, N, N, N, N),
+ MUX(1, 42, 1, N, N, N, N),
+ MUX(1, 41, 1, N, N, N, N),
+ MUX(1, 40, 1, N, N, N, N),
+ MUX(1, 39, 1, N, N, N, N),
+ MUX(1, 38, 1, N, N, N, N),
+ MUX(1, 37, 1, N, N, N, N),
+ MUX(1, 47, 1, N, N, N, N),
+ MUX(1, 46, 1, N, N, N, N),
+ MUX(1, 52, 1, N, N, N, N),
+ MUX(1, 51, 1, N, N, N, N),
+ MUX(1, 45, 1, N, N, N, N),
+ MUX(1, 49, 1, N, N, N, N),
+ MUX(1, 50, 1, N, N, N, N),
+ MUX(1, 48, 1, N, N, N, N),
+ MUX(1, 124, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux nd_df_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(nd_df_grp_pad_mux),
+ .pad_mux_list = nd_df_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux nd_df_nowp_grp_pad_mux[] = {
+ MUX(1, 44, 1, N, N, N, N),
+ MUX(1, 43, 1, N, N, N, N),
+ MUX(1, 42, 1, N, N, N, N),
+ MUX(1, 41, 1, N, N, N, N),
+ MUX(1, 40, 1, N, N, N, N),
+ MUX(1, 39, 1, N, N, N, N),
+ MUX(1, 38, 1, N, N, N, N),
+ MUX(1, 37, 1, N, N, N, N),
+ MUX(1, 47, 1, N, N, N, N),
+ MUX(1, 46, 1, N, N, N, N),
+ MUX(1, 52, 1, N, N, N, N),
+ MUX(1, 51, 1, N, N, N, N),
+ MUX(1, 45, 1, N, N, N, N),
+ MUX(1, 49, 1, N, N, N, N),
+ MUX(1, 50, 1, N, N, N, N),
+ MUX(1, 48, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux nd_df_nowp_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(nd_df_nowp_grp_pad_mux),
+ .pad_mux_list = nd_df_nowp_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux ps_grp_pad_mux[] = {
+ MUX(1, 120, 2, N, N, N, N),
+ MUX(1, 119, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ps_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ps_grp_pad_mux),
+ .pad_mux_list = ps_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux pwc_core_on_grp_pad_mux[] = {
+ MUX(0, 8, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pwc_core_on_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(pwc_core_on_grp_pad_mux),
+ .pad_mux_list = pwc_core_on_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux pwc_ext_on_grp_pad_mux[] = {
+ MUX(0, 6, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pwc_ext_on_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(pwc_ext_on_grp_pad_mux),
+ .pad_mux_list = pwc_ext_on_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux pwc_gpio3_clk_grp_pad_mux[] = {
+ MUX(0, 3, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pwc_gpio3_clk_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(pwc_gpio3_clk_grp_pad_mux),
+ .pad_mux_list = pwc_gpio3_clk_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux pwc_io_on_grp_pad_mux[] = {
+ MUX(0, 9, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pwc_io_on_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(pwc_io_on_grp_pad_mux),
+ .pad_mux_list = pwc_io_on_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux pwc_lowbatt_b_grp0_pad_mux[] = {
+ MUX(0, 4, 1, 0xa08, 4, 0xa88, 4),
+};
+
+static struct atlas7_grp_mux pwc_lowbatt_b_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(pwc_lowbatt_b_grp0_pad_mux),
+ .pad_mux_list = pwc_lowbatt_b_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux pwc_mem_on_grp_pad_mux[] = {
+ MUX(0, 7, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pwc_mem_on_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(pwc_mem_on_grp_pad_mux),
+ .pad_mux_list = pwc_mem_on_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux pwc_on_key_b_grp0_pad_mux[] = {
+ MUX(0, 5, 1, 0xa08, 5, 0xa88, 5),
+};
+
+static struct atlas7_grp_mux pwc_on_key_b_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(pwc_on_key_b_grp0_pad_mux),
+ .pad_mux_list = pwc_on_key_b_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux pwc_wakeup_src0_grp_pad_mux[] = {
+ MUX(0, 0, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pwc_wakeup_src0_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(pwc_wakeup_src0_grp_pad_mux),
+ .pad_mux_list = pwc_wakeup_src0_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux pwc_wakeup_src1_grp_pad_mux[] = {
+ MUX(0, 1, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pwc_wakeup_src1_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(pwc_wakeup_src1_grp_pad_mux),
+ .pad_mux_list = pwc_wakeup_src1_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux pwc_wakeup_src2_grp_pad_mux[] = {
+ MUX(0, 2, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pwc_wakeup_src2_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(pwc_wakeup_src2_grp_pad_mux),
+ .pad_mux_list = pwc_wakeup_src2_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux pwc_wakeup_src3_grp_pad_mux[] = {
+ MUX(0, 3, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pwc_wakeup_src3_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(pwc_wakeup_src3_grp_pad_mux),
+ .pad_mux_list = pwc_wakeup_src3_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_cko0_grp0_pad_mux[] = {
+ MUX(1, 123, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_cko0_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_cko0_grp0_pad_mux),
+ .pad_mux_list = pw_cko0_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_cko0_grp1_pad_mux[] = {
+ MUX(1, 101, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_cko0_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_cko0_grp1_pad_mux),
+ .pad_mux_list = pw_cko0_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_cko0_grp2_pad_mux[] = {
+ MUX(1, 82, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_cko0_grp2_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_cko0_grp2_pad_mux),
+ .pad_mux_list = pw_cko0_grp2_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_cko1_grp0_pad_mux[] = {
+ MUX(1, 124, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_cko1_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_cko1_grp0_pad_mux),
+ .pad_mux_list = pw_cko1_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_cko1_grp1_pad_mux[] = {
+ MUX(1, 110, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_cko1_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_cko1_grp1_pad_mux),
+ .pad_mux_list = pw_cko1_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_i2s01_clk_grp0_pad_mux[] = {
+ MUX(1, 125, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_i2s01_clk_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_i2s01_clk_grp0_pad_mux),
+ .pad_mux_list = pw_i2s01_clk_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_i2s01_clk_grp1_pad_mux[] = {
+ MUX(1, 117, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_i2s01_clk_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_i2s01_clk_grp1_pad_mux),
+ .pad_mux_list = pw_i2s01_clk_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_pwm0_grp_pad_mux[] = {
+ MUX(1, 119, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_pwm0_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_pwm0_grp_pad_mux),
+ .pad_mux_list = pw_pwm0_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_pwm1_grp_pad_mux[] = {
+ MUX(1, 120, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_pwm1_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_pwm1_grp_pad_mux),
+ .pad_mux_list = pw_pwm1_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_pwm2_grp0_pad_mux[] = {
+ MUX(1, 121, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_pwm2_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_pwm2_grp0_pad_mux),
+ .pad_mux_list = pw_pwm2_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_pwm2_grp1_pad_mux[] = {
+ MUX(1, 98, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_pwm2_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_pwm2_grp1_pad_mux),
+ .pad_mux_list = pw_pwm2_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_pwm3_grp0_pad_mux[] = {
+ MUX(1, 122, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_pwm3_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_pwm3_grp0_pad_mux),
+ .pad_mux_list = pw_pwm3_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_pwm3_grp1_pad_mux[] = {
+ MUX(1, 73, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_pwm3_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_pwm3_grp1_pad_mux),
+ .pad_mux_list = pw_pwm3_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_pwm_cpu_vol_grp0_pad_mux[] = {
+ MUX(1, 121, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_pwm_cpu_vol_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_pwm_cpu_vol_grp0_pad_mux),
+ .pad_mux_list = pw_pwm_cpu_vol_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_pwm_cpu_vol_grp1_pad_mux[] = {
+ MUX(1, 98, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_pwm_cpu_vol_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_pwm_cpu_vol_grp1_pad_mux),
+ .pad_mux_list = pw_pwm_cpu_vol_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_backlight_grp0_pad_mux[] = {
+ MUX(1, 122, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_backlight_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_backlight_grp0_pad_mux),
+ .pad_mux_list = pw_backlight_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux pw_backlight_grp1_pad_mux[] = {
+ MUX(1, 73, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux pw_backlight_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(pw_backlight_grp1_pad_mux),
+ .pad_mux_list = pw_backlight_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux rg_eth_mac_grp_pad_mux[] = {
+ MUX(1, 108, 1, N, N, N, N),
+ MUX(1, 103, 1, N, N, N, N),
+ MUX(1, 104, 1, N, N, N, N),
+ MUX(1, 105, 1, N, N, N, N),
+ MUX(1, 106, 1, N, N, N, N),
+ MUX(1, 107, 1, N, N, N, N),
+ MUX(1, 102, 1, N, N, N, N),
+ MUX(1, 97, 1, N, N, N, N),
+ MUX(1, 98, 1, N, N, N, N),
+ MUX(1, 99, 1, N, N, N, N),
+ MUX(1, 100, 1, N, N, N, N),
+ MUX(1, 101, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux rg_eth_mac_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(rg_eth_mac_grp_pad_mux),
+ .pad_mux_list = rg_eth_mac_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux rg_gmac_phy_intr_n_grp_pad_mux[] = {
+ MUX(1, 111, 1, 0xa08, 13, 0xa88, 13),
+};
+
+static struct atlas7_grp_mux rg_gmac_phy_intr_n_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(rg_gmac_phy_intr_n_grp_pad_mux),
+ .pad_mux_list = rg_gmac_phy_intr_n_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux rg_rgmii_mac_grp_pad_mux[] = {
+ MUX(1, 109, 1, N, N, N, N),
+ MUX(1, 110, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux rg_rgmii_mac_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(rg_rgmii_mac_grp_pad_mux),
+ .pad_mux_list = rg_rgmii_mac_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux rg_rgmii_phy_ref_clk_grp0_pad_mux[] = {
+ MUX(1, 111, 5, N, N, N, N),
+};
+
+static struct atlas7_grp_mux rg_rgmii_phy_ref_clk_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(rg_rgmii_phy_ref_clk_grp0_pad_mux),
+ .pad_mux_list = rg_rgmii_phy_ref_clk_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux rg_rgmii_phy_ref_clk_grp1_pad_mux[] = {
+ MUX(1, 53, 4, N, N, N, N),
+};
+
+static struct atlas7_grp_mux rg_rgmii_phy_ref_clk_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(rg_rgmii_phy_ref_clk_grp1_pad_mux),
+ .pad_mux_list = rg_rgmii_phy_ref_clk_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux sd0_grp_pad_mux[] = {
+ MUX(1, 46, 2, N, N, N, N),
+ MUX(1, 47, 2, N, N, N, N),
+ MUX(1, 44, 2, N, N, N, N),
+ MUX(1, 43, 2, N, N, N, N),
+ MUX(1, 42, 2, N, N, N, N),
+ MUX(1, 41, 2, N, N, N, N),
+ MUX(1, 40, 2, N, N, N, N),
+ MUX(1, 39, 2, N, N, N, N),
+ MUX(1, 38, 2, N, N, N, N),
+ MUX(1, 37, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux sd0_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(sd0_grp_pad_mux),
+ .pad_mux_list = sd0_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux sd0_4bit_grp_pad_mux[] = {
+ MUX(1, 46, 2, N, N, N, N),
+ MUX(1, 47, 2, N, N, N, N),
+ MUX(1, 44, 2, N, N, N, N),
+ MUX(1, 43, 2, N, N, N, N),
+ MUX(1, 42, 2, N, N, N, N),
+ MUX(1, 41, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux sd0_4bit_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(sd0_4bit_grp_pad_mux),
+ .pad_mux_list = sd0_4bit_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux sd1_grp_pad_mux[] = {
+ MUX(1, 48, 3, N, N, N, N),
+ MUX(1, 49, 3, N, N, N, N),
+ MUX(1, 44, 3, 0xa00, 0, 0xa80, 0),
+ MUX(1, 43, 3, 0xa00, 1, 0xa80, 1),
+ MUX(1, 42, 3, 0xa00, 2, 0xa80, 2),
+ MUX(1, 41, 3, 0xa00, 3, 0xa80, 3),
+ MUX(1, 40, 3, N, N, N, N),
+ MUX(1, 39, 3, N, N, N, N),
+ MUX(1, 38, 3, N, N, N, N),
+ MUX(1, 37, 3, N, N, N, N),
+};
+
+static struct atlas7_grp_mux sd1_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(sd1_grp_pad_mux),
+ .pad_mux_list = sd1_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux sd1_4bit_grp0_pad_mux[] = {
+ MUX(1, 48, 3, N, N, N, N),
+ MUX(1, 49, 3, N, N, N, N),
+ MUX(1, 44, 3, 0xa00, 0, 0xa80, 0),
+ MUX(1, 43, 3, 0xa00, 1, 0xa80, 1),
+ MUX(1, 42, 3, 0xa00, 2, 0xa80, 2),
+ MUX(1, 41, 3, 0xa00, 3, 0xa80, 3),
+};
+
+static struct atlas7_grp_mux sd1_4bit_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(sd1_4bit_grp0_pad_mux),
+ .pad_mux_list = sd1_4bit_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux sd1_4bit_grp1_pad_mux[] = {
+ MUX(1, 48, 3, N, N, N, N),
+ MUX(1, 49, 3, N, N, N, N),
+ MUX(1, 40, 4, 0xa00, 0, 0xa80, 0),
+ MUX(1, 39, 4, 0xa00, 1, 0xa80, 1),
+ MUX(1, 38, 4, 0xa00, 2, 0xa80, 2),
+ MUX(1, 37, 4, 0xa00, 3, 0xa80, 3),
+};
+
+static struct atlas7_grp_mux sd1_4bit_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(sd1_4bit_grp1_pad_mux),
+ .pad_mux_list = sd1_4bit_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux sd2_grp0_pad_mux[] = {
+ MUX(1, 124, 2, 0xa08, 7, 0xa88, 7),
+ MUX(1, 31, 1, N, N, N, N),
+ MUX(1, 32, 1, N, N, N, N),
+ MUX(1, 33, 1, N, N, N, N),
+ MUX(1, 34, 1, N, N, N, N),
+ MUX(1, 35, 1, N, N, N, N),
+ MUX(1, 36, 1, N, N, N, N),
+ MUX(1, 123, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux sd2_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(sd2_grp0_pad_mux),
+ .pad_mux_list = sd2_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux sd2_no_cdb_grp0_pad_mux[] = {
+ MUX(1, 31, 1, N, N, N, N),
+ MUX(1, 32, 1, N, N, N, N),
+ MUX(1, 33, 1, N, N, N, N),
+ MUX(1, 34, 1, N, N, N, N),
+ MUX(1, 35, 1, N, N, N, N),
+ MUX(1, 36, 1, N, N, N, N),
+ MUX(1, 123, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux sd2_no_cdb_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(sd2_no_cdb_grp0_pad_mux),
+ .pad_mux_list = sd2_no_cdb_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux sd3_grp_pad_mux[] = {
+ MUX(1, 85, 1, N, N, N, N),
+ MUX(1, 86, 1, N, N, N, N),
+ MUX(1, 87, 1, N, N, N, N),
+ MUX(1, 88, 1, N, N, N, N),
+ MUX(1, 89, 1, N, N, N, N),
+ MUX(1, 90, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux sd3_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(sd3_grp_pad_mux),
+ .pad_mux_list = sd3_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux sd5_grp_pad_mux[] = {
+ MUX(1, 91, 1, N, N, N, N),
+ MUX(1, 92, 1, N, N, N, N),
+ MUX(1, 93, 1, N, N, N, N),
+ MUX(1, 94, 1, N, N, N, N),
+ MUX(1, 95, 1, N, N, N, N),
+ MUX(1, 96, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux sd5_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(sd5_grp_pad_mux),
+ .pad_mux_list = sd5_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux sd6_grp0_pad_mux[] = {
+ MUX(1, 79, 4, 0xa00, 27, 0xa80, 27),
+ MUX(1, 78, 4, 0xa00, 26, 0xa80, 26),
+ MUX(1, 74, 4, 0xa00, 28, 0xa80, 28),
+ MUX(1, 75, 4, 0xa00, 29, 0xa80, 29),
+ MUX(1, 76, 4, 0xa00, 30, 0xa80, 30),
+ MUX(1, 77, 4, 0xa00, 31, 0xa80, 31),
+};
+
+static struct atlas7_grp_mux sd6_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(sd6_grp0_pad_mux),
+ .pad_mux_list = sd6_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux sd6_grp1_pad_mux[] = {
+ MUX(1, 101, 3, 0xa00, 27, 0xa80, 27),
+ MUX(1, 99, 3, 0xa00, 26, 0xa80, 26),
+ MUX(1, 100, 3, 0xa00, 28, 0xa80, 28),
+ MUX(1, 110, 3, 0xa00, 29, 0xa80, 29),
+ MUX(1, 109, 3, 0xa00, 30, 0xa80, 30),
+ MUX(1, 111, 3, 0xa00, 31, 0xa80, 31),
+};
+
+static struct atlas7_grp_mux sd6_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(sd6_grp1_pad_mux),
+ .pad_mux_list = sd6_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux sp0_ext_ldo_on_grp_pad_mux[] = {
+ MUX(0, 4, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux sp0_ext_ldo_on_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(sp0_ext_ldo_on_grp_pad_mux),
+ .pad_mux_list = sp0_ext_ldo_on_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux sp0_qspi_grp_pad_mux[] = {
+ MUX(0, 12, 1, N, N, N, N),
+ MUX(0, 13, 1, N, N, N, N),
+ MUX(0, 14, 1, N, N, N, N),
+ MUX(0, 15, 1, N, N, N, N),
+ MUX(0, 16, 1, N, N, N, N),
+ MUX(0, 17, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux sp0_qspi_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(sp0_qspi_grp_pad_mux),
+ .pad_mux_list = sp0_qspi_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux sp1_spi_grp_pad_mux[] = {
+ MUX(1, 19, 1, N, N, N, N),
+ MUX(1, 20, 1, N, N, N, N),
+ MUX(1, 21, 1, N, N, N, N),
+ MUX(1, 18, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux sp1_spi_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(sp1_spi_grp_pad_mux),
+ .pad_mux_list = sp1_spi_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux tpiu_trace_grp_pad_mux[] = {
+ MUX(1, 53, 5, N, N, N, N),
+ MUX(1, 56, 5, N, N, N, N),
+ MUX(1, 57, 5, N, N, N, N),
+ MUX(1, 58, 5, N, N, N, N),
+ MUX(1, 59, 5, N, N, N, N),
+ MUX(1, 60, 5, N, N, N, N),
+ MUX(1, 61, 5, N, N, N, N),
+ MUX(1, 62, 5, N, N, N, N),
+ MUX(1, 63, 5, N, N, N, N),
+ MUX(1, 64, 5, N, N, N, N),
+ MUX(1, 65, 5, N, N, N, N),
+ MUX(1, 66, 5, N, N, N, N),
+ MUX(1, 67, 5, N, N, N, N),
+ MUX(1, 68, 5, N, N, N, N),
+ MUX(1, 69, 5, N, N, N, N),
+ MUX(1, 70, 5, N, N, N, N),
+ MUX(1, 71, 5, N, N, N, N),
+ MUX(1, 72, 5, N, N, N, N),
+};
+
+static struct atlas7_grp_mux tpiu_trace_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(tpiu_trace_grp_pad_mux),
+ .pad_mux_list = tpiu_trace_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux uart0_grp_pad_mux[] = {
+ MUX(1, 121, 4, N, N, N, N),
+ MUX(1, 120, 4, N, N, N, N),
+ MUX(1, 134, 1, N, N, N, N),
+ MUX(1, 133, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux uart0_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(uart0_grp_pad_mux),
+ .pad_mux_list = uart0_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux uart0_nopause_grp_pad_mux[] = {
+ MUX(1, 134, 1, N, N, N, N),
+ MUX(1, 133, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux uart0_nopause_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(uart0_nopause_grp_pad_mux),
+ .pad_mux_list = uart0_nopause_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux uart1_grp_pad_mux[] = {
+ MUX(1, 136, 1, N, N, N, N),
+ MUX(1, 135, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux uart1_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(uart1_grp_pad_mux),
+ .pad_mux_list = uart1_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux uart2_grp_pad_mux[] = {
+ MUX(0, 11, 2, N, N, N, N),
+ MUX(0, 10, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux uart2_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(uart2_grp_pad_mux),
+ .pad_mux_list = uart2_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux uart3_grp0_pad_mux[] = {
+ MUX(1, 125, 2, 0xa08, 0, 0xa88, 0),
+ MUX(1, 126, 2, N, N, N, N),
+ MUX(1, 138, 1, 0xa00, 5, 0xa80, 5),
+ MUX(1, 137, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux uart3_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(uart3_grp0_pad_mux),
+ .pad_mux_list = uart3_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux uart3_grp1_pad_mux[] = {
+ MUX(1, 111, 4, 0xa08, 0, 0xa88, 0),
+ MUX(1, 109, 4, N, N, N, N),
+ MUX(1, 84, 2, 0xa00, 5, 0xa80, 5),
+ MUX(1, 83, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux uart3_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(uart3_grp1_pad_mux),
+ .pad_mux_list = uart3_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux uart3_grp2_pad_mux[] = {
+ MUX(1, 140, 2, 0xa08, 0, 0xa88, 0),
+ MUX(1, 139, 2, N, N, N, N),
+ MUX(1, 138, 1, 0xa00, 5, 0xa80, 5),
+ MUX(1, 137, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux uart3_grp2_mux = {
+ .pad_mux_count = ARRAY_SIZE(uart3_grp2_pad_mux),
+ .pad_mux_list = uart3_grp2_pad_mux,
+};
+
+static struct atlas7_pad_mux uart3_grp3_pad_mux[] = {
+ MUX(1, 139, 2, N, N, N, N),
+ MUX(1, 140, 2, 0xa08, 0, 0xa88, 0),
+ MUX(1, 84, 2, 0xa00, 5, 0xa80, 5),
+ MUX(1, 83, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux uart3_grp3_mux = {
+ .pad_mux_count = ARRAY_SIZE(uart3_grp3_pad_mux),
+ .pad_mux_list = uart3_grp3_pad_mux,
+};
+
+static struct atlas7_pad_mux uart3_nopause_grp0_pad_mux[] = {
+ MUX(1, 138, 1, 0xa00, 5, 0xa80, 5),
+ MUX(1, 137, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux uart3_nopause_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(uart3_nopause_grp0_pad_mux),
+ .pad_mux_list = uart3_nopause_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux uart3_nopause_grp1_pad_mux[] = {
+ MUX(1, 84, 2, 0xa00, 5, 0xa80, 5),
+ MUX(1, 83, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux uart3_nopause_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(uart3_nopause_grp1_pad_mux),
+ .pad_mux_list = uart3_nopause_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux uart4_grp0_pad_mux[] = {
+ MUX(1, 122, 4, 0xa08, 1, 0xa88, 1),
+ MUX(1, 123, 4, N, N, N, N),
+ MUX(1, 140, 1, N, N, N, N),
+ MUX(1, 139, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux uart4_grp0_mux = {
+ .pad_mux_count = ARRAY_SIZE(uart4_grp0_pad_mux),
+ .pad_mux_list = uart4_grp0_pad_mux,
+};
+
+static struct atlas7_pad_mux uart4_grp1_pad_mux[] = {
+ MUX(1, 100, 4, 0xa08, 1, 0xa88, 1),
+ MUX(1, 99, 4, N, N, N, N),
+ MUX(1, 140, 1, N, N, N, N),
+ MUX(1, 139, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux uart4_grp1_mux = {
+ .pad_mux_count = ARRAY_SIZE(uart4_grp1_pad_mux),
+ .pad_mux_list = uart4_grp1_pad_mux,
+};
+
+static struct atlas7_pad_mux uart4_grp2_pad_mux[] = {
+ MUX(1, 117, 2, 0xa08, 1, 0xa88, 1),
+ MUX(1, 116, 2, N, N, N, N),
+ MUX(1, 140, 1, N, N, N, N),
+ MUX(1, 139, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux uart4_grp2_mux = {
+ .pad_mux_count = ARRAY_SIZE(uart4_grp2_pad_mux),
+ .pad_mux_list = uart4_grp2_pad_mux,
+};
+
+static struct atlas7_pad_mux uart4_nopause_grp_pad_mux[] = {
+ MUX(1, 140, 1, N, N, N, N),
+ MUX(1, 139, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux uart4_nopause_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(uart4_nopause_grp_pad_mux),
+ .pad_mux_list = uart4_nopause_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux usb0_drvvbus_grp_pad_mux[] = {
+ MUX(1, 51, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux usb0_drvvbus_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(usb0_drvvbus_grp_pad_mux),
+ .pad_mux_list = usb0_drvvbus_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux usb1_drvvbus_grp_pad_mux[] = {
+ MUX(1, 134, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux usb1_drvvbus_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(usb1_drvvbus_grp_pad_mux),
+ .pad_mux_list = usb1_drvvbus_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux visbus_dout_grp_pad_mux[] = {
+ MUX(1, 57, 6, N, N, N, N),
+ MUX(1, 58, 6, N, N, N, N),
+ MUX(1, 59, 6, N, N, N, N),
+ MUX(1, 60, 6, N, N, N, N),
+ MUX(1, 61, 6, N, N, N, N),
+ MUX(1, 62, 6, N, N, N, N),
+ MUX(1, 63, 6, N, N, N, N),
+ MUX(1, 64, 6, N, N, N, N),
+ MUX(1, 65, 6, N, N, N, N),
+ MUX(1, 66, 6, N, N, N, N),
+ MUX(1, 67, 6, N, N, N, N),
+ MUX(1, 68, 6, N, N, N, N),
+ MUX(1, 69, 6, N, N, N, N),
+ MUX(1, 70, 6, N, N, N, N),
+ MUX(1, 71, 6, N, N, N, N),
+ MUX(1, 72, 6, N, N, N, N),
+ MUX(1, 53, 6, N, N, N, N),
+ MUX(1, 54, 6, N, N, N, N),
+ MUX(1, 55, 6, N, N, N, N),
+ MUX(1, 56, 6, N, N, N, N),
+ MUX(1, 85, 6, N, N, N, N),
+ MUX(1, 86, 6, N, N, N, N),
+ MUX(1, 87, 6, N, N, N, N),
+ MUX(1, 88, 6, N, N, N, N),
+ MUX(1, 89, 6, N, N, N, N),
+ MUX(1, 90, 6, N, N, N, N),
+ MUX(1, 91, 6, N, N, N, N),
+ MUX(1, 92, 6, N, N, N, N),
+ MUX(1, 93, 6, N, N, N, N),
+ MUX(1, 94, 6, N, N, N, N),
+ MUX(1, 95, 6, N, N, N, N),
+ MUX(1, 96, 6, N, N, N, N),
+};
+
+static struct atlas7_grp_mux visbus_dout_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(visbus_dout_grp_pad_mux),
+ .pad_mux_list = visbus_dout_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux vi_vip1_grp_pad_mux[] = {
+ MUX(1, 74, 1, N, N, N, N),
+ MUX(1, 75, 1, N, N, N, N),
+ MUX(1, 76, 1, N, N, N, N),
+ MUX(1, 77, 1, N, N, N, N),
+ MUX(1, 78, 1, N, N, N, N),
+ MUX(1, 79, 1, N, N, N, N),
+ MUX(1, 80, 1, N, N, N, N),
+ MUX(1, 81, 1, N, N, N, N),
+ MUX(1, 82, 1, N, N, N, N),
+ MUX(1, 83, 1, N, N, N, N),
+ MUX(1, 84, 1, N, N, N, N),
+ MUX(1, 103, 2, N, N, N, N),
+ MUX(1, 104, 2, N, N, N, N),
+ MUX(1, 105, 2, N, N, N, N),
+ MUX(1, 106, 2, N, N, N, N),
+ MUX(1, 107, 2, N, N, N, N),
+ MUX(1, 102, 2, N, N, N, N),
+ MUX(1, 97, 2, N, N, N, N),
+ MUX(1, 98, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux vi_vip1_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(vi_vip1_grp_pad_mux),
+ .pad_mux_list = vi_vip1_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux vi_vip1_ext_grp_pad_mux[] = {
+ MUX(1, 74, 1, N, N, N, N),
+ MUX(1, 75, 1, N, N, N, N),
+ MUX(1, 76, 1, N, N, N, N),
+ MUX(1, 77, 1, N, N, N, N),
+ MUX(1, 78, 1, N, N, N, N),
+ MUX(1, 79, 1, N, N, N, N),
+ MUX(1, 80, 1, N, N, N, N),
+ MUX(1, 81, 1, N, N, N, N),
+ MUX(1, 82, 1, N, N, N, N),
+ MUX(1, 83, 1, N, N, N, N),
+ MUX(1, 84, 1, N, N, N, N),
+ MUX(1, 108, 2, N, N, N, N),
+ MUX(1, 103, 2, N, N, N, N),
+ MUX(1, 104, 2, N, N, N, N),
+ MUX(1, 105, 2, N, N, N, N),
+ MUX(1, 106, 2, N, N, N, N),
+ MUX(1, 107, 2, N, N, N, N),
+ MUX(1, 102, 2, N, N, N, N),
+ MUX(1, 97, 2, N, N, N, N),
+ MUX(1, 98, 2, N, N, N, N),
+ MUX(1, 99, 2, N, N, N, N),
+ MUX(1, 100, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux vi_vip1_ext_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(vi_vip1_ext_grp_pad_mux),
+ .pad_mux_list = vi_vip1_ext_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux vi_vip1_low8bit_grp_pad_mux[] = {
+ MUX(1, 74, 1, N, N, N, N),
+ MUX(1, 75, 1, N, N, N, N),
+ MUX(1, 76, 1, N, N, N, N),
+ MUX(1, 77, 1, N, N, N, N),
+ MUX(1, 78, 1, N, N, N, N),
+ MUX(1, 79, 1, N, N, N, N),
+ MUX(1, 80, 1, N, N, N, N),
+ MUX(1, 81, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux vi_vip1_low8bit_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(vi_vip1_low8bit_grp_pad_mux),
+ .pad_mux_list = vi_vip1_low8bit_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux vi_vip1_high8bit_grp_pad_mux[] = {
+ MUX(1, 82, 1, N, N, N, N),
+ MUX(1, 83, 1, N, N, N, N),
+ MUX(1, 84, 1, N, N, N, N),
+ MUX(1, 108, 2, N, N, N, N),
+ MUX(1, 103, 2, N, N, N, N),
+ MUX(1, 104, 2, N, N, N, N),
+ MUX(1, 105, 2, N, N, N, N),
+ MUX(1, 106, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux vi_vip1_high8bit_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(vi_vip1_high8bit_grp_pad_mux),
+ .pad_mux_list = vi_vip1_high8bit_grp_pad_mux,
+};
+
+static struct atlas7_pmx_func atlas7_pmx_functions[] = {
+ FUNCTION("gnss_gpio", gnss_gpio_grp, &gnss_gpio_grp_mux),
+ FUNCTION("lcd_vip_gpio", lcd_vip_gpio_grp, &lcd_vip_gpio_grp_mux),
+ FUNCTION("sdio_i2s_gpio", sdio_i2s_gpio_grp, &sdio_i2s_gpio_grp_mux),
+ FUNCTION("sp_rgmii_gpio", sp_rgmii_gpio_grp, &sp_rgmii_gpio_grp_mux),
+ FUNCTION("lvds_gpio", lvds_gpio_grp, &lvds_gpio_grp_mux),
+ FUNCTION("uart_nand_gpio",
+ uart_nand_gpio_grp,
+ &uart_nand_gpio_grp_mux),
+ FUNCTION("rtc_gpio", rtc_gpio_grp, &rtc_gpio_grp_mux),
+ FUNCTION("audio_ac97", audio_ac97_grp, &audio_ac97_grp_mux),
+ FUNCTION("audio_func_dbg",
+ audio_func_dbg_grp,
+ &audio_func_dbg_grp_mux),
+ FUNCTION("audio_i2s", audio_i2s_grp, &audio_i2s_grp_mux),
+ FUNCTION("audio_i2s_2ch", audio_i2s_2ch_grp, &audio_i2s_2ch_grp_mux),
+ FUNCTION("audio_i2s_extclk",
+ audio_i2s_extclk_grp,
+ &audio_i2s_extclk_grp_mux),
+ FUNCTION("audio_uart0", audio_uart0_grp, &audio_uart0_grp_mux),
+ FUNCTION("audio_uart1", audio_uart1_grp, &audio_uart1_grp_mux),
+ FUNCTION("audio_uart2_m0", audio_uart2_grp0, &audio_uart2_grp0_mux),
+ FUNCTION("audio_uart2_m1", audio_uart2_grp1, &audio_uart2_grp1_mux),
+ FUNCTION("c_can_trnsvr", c_can_trnsvr_grp, &c_can_trnsvr_grp_mux),
+ FUNCTION("c0_can_m0", c0_can_grp0, &c0_can_grp0_mux),
+ FUNCTION("c0_can_m1", c0_can_grp1, &c0_can_grp1_mux),
+ FUNCTION("c1_can_m0", c1_can_grp0, &c1_can_grp0_mux),
+ FUNCTION("c1_can_m1", c1_can_grp1, &c1_can_grp1_mux),
+ FUNCTION("c1_can_m2", c1_can_grp2, &c1_can_grp2_mux),
+ FUNCTION("ca_audio_lpc", ca_audio_lpc_grp, &ca_audio_lpc_grp_mux),
+ FUNCTION("ca_bt_lpc", ca_bt_lpc_grp, &ca_bt_lpc_grp_mux),
+ FUNCTION("ca_coex", ca_coex_grp, &ca_coex_grp_mux),
+ FUNCTION("ca_curator_lpc",
+ ca_curator_lpc_grp,
+ &ca_curator_lpc_grp_mux),
+ FUNCTION("ca_pcm_debug", ca_pcm_debug_grp, &ca_pcm_debug_grp_mux),
+ FUNCTION("ca_pio", ca_pio_grp, &ca_pio_grp_mux),
+ FUNCTION("ca_sdio_debug", ca_sdio_debug_grp, &ca_sdio_debug_grp_mux),
+ FUNCTION("ca_spi", ca_spi_grp, &ca_spi_grp_mux),
+ FUNCTION("ca_trb", ca_trb_grp, &ca_trb_grp_mux),
+ FUNCTION("ca_uart_debug", ca_uart_debug_grp, &ca_uart_debug_grp_mux),
+ FUNCTION("clkc_m0", clkc_grp0, &clkc_grp0_mux),
+ FUNCTION("clkc_m1", clkc_grp1, &clkc_grp1_mux),
+ FUNCTION("gn_gnss_i2c", gn_gnss_i2c_grp, &gn_gnss_i2c_grp_mux),
+ FUNCTION("gn_gnss_uart_nopause",
+ gn_gnss_uart_nopause_grp,
+ &gn_gnss_uart_nopause_grp_mux),
+ FUNCTION("gn_gnss_uart", gn_gnss_uart_grp, &gn_gnss_uart_grp_mux),
+ FUNCTION("gn_trg_spi_m0", gn_trg_spi_grp0, &gn_trg_spi_grp0_mux),
+ FUNCTION("gn_trg_spi_m1", gn_trg_spi_grp1, &gn_trg_spi_grp1_mux),
+ FUNCTION("cvbs_dbg", cvbs_dbg_grp, &cvbs_dbg_grp_mux),
+ FUNCTION("cvbs_dbg_test_m0",
+ cvbs_dbg_test_grp0,
+ &cvbs_dbg_test_grp0_mux),
+ FUNCTION("cvbs_dbg_test_m1",
+ cvbs_dbg_test_grp1,
+ &cvbs_dbg_test_grp1_mux),
+ FUNCTION("cvbs_dbg_test_m2",
+ cvbs_dbg_test_grp2,
+ &cvbs_dbg_test_grp2_mux),
+ FUNCTION("cvbs_dbg_test_m3",
+ cvbs_dbg_test_grp3,
+ &cvbs_dbg_test_grp3_mux),
+ FUNCTION("cvbs_dbg_test_m4",
+ cvbs_dbg_test_grp4,
+ &cvbs_dbg_test_grp4_mux),
+ FUNCTION("cvbs_dbg_test_m5",
+ cvbs_dbg_test_grp5,
+ &cvbs_dbg_test_grp5_mux),
+ FUNCTION("cvbs_dbg_test_m6",
+ cvbs_dbg_test_grp6,
+ &cvbs_dbg_test_grp6_mux),
+ FUNCTION("cvbs_dbg_test_m7",
+ cvbs_dbg_test_grp7,
+ &cvbs_dbg_test_grp7_mux),
+ FUNCTION("cvbs_dbg_test_m8",
+ cvbs_dbg_test_grp8,
+ &cvbs_dbg_test_grp8_mux),
+ FUNCTION("cvbs_dbg_test_m9",
+ cvbs_dbg_test_grp9,
+ &cvbs_dbg_test_grp9_mux),
+ FUNCTION("cvbs_dbg_test_m10",
+ cvbs_dbg_test_grp10,
+ &cvbs_dbg_test_grp10_mux),
+ FUNCTION("cvbs_dbg_test_m11",
+ cvbs_dbg_test_grp11,
+ &cvbs_dbg_test_grp11_mux),
+ FUNCTION("cvbs_dbg_test_m12",
+ cvbs_dbg_test_grp12,
+ &cvbs_dbg_test_grp12_mux),
+ FUNCTION("cvbs_dbg_test_m13",
+ cvbs_dbg_test_grp13,
+ &cvbs_dbg_test_grp13_mux),
+ FUNCTION("cvbs_dbg_test_m14",
+ cvbs_dbg_test_grp14,
+ &cvbs_dbg_test_grp14_mux),
+ FUNCTION("cvbs_dbg_test_m15",
+ cvbs_dbg_test_grp15,
+ &cvbs_dbg_test_grp15_mux),
+ FUNCTION("gn_gnss_power", gn_gnss_power_grp, &gn_gnss_power_grp_mux),
+ FUNCTION("gn_gnss_sw_status",
+ gn_gnss_sw_status_grp,
+ &gn_gnss_sw_status_grp_mux),
+ FUNCTION("gn_gnss_eclk", gn_gnss_eclk_grp, &gn_gnss_eclk_grp_mux),
+ FUNCTION("gn_gnss_irq1_m0",
+ gn_gnss_irq1_grp0,
+ &gn_gnss_irq1_grp0_mux),
+ FUNCTION("gn_gnss_irq2_m0",
+ gn_gnss_irq2_grp0,
+ &gn_gnss_irq2_grp0_mux),
+ FUNCTION("gn_gnss_tm", gn_gnss_tm_grp, &gn_gnss_tm_grp_mux),
+ FUNCTION("gn_gnss_tsync", gn_gnss_tsync_grp, &gn_gnss_tsync_grp_mux),
+ FUNCTION("gn_io_gnsssys_sw_cfg",
+ gn_io_gnsssys_sw_cfg_grp,
+ &gn_io_gnsssys_sw_cfg_grp_mux),
+ FUNCTION("gn_trg_m0", gn_trg_grp0, &gn_trg_grp0_mux),
+ FUNCTION("gn_trg_m1", gn_trg_grp1, &gn_trg_grp1_mux),
+ FUNCTION("gn_trg_shutdown_m0",
+ gn_trg_shutdown_grp0,
+ &gn_trg_shutdown_grp0_mux),
+ FUNCTION("gn_trg_shutdown_m1",
+ gn_trg_shutdown_grp1,
+ &gn_trg_shutdown_grp1_mux),
+ FUNCTION("gn_trg_shutdown_m2",
+ gn_trg_shutdown_grp2,
+ &gn_trg_shutdown_grp2_mux),
+ FUNCTION("gn_trg_shutdown_m3",
+ gn_trg_shutdown_grp3,
+ &gn_trg_shutdown_grp3_mux),
+ FUNCTION("i2c0", i2c0_grp, &i2c0_grp_mux),
+ FUNCTION("i2c1", i2c1_grp, &i2c1_grp_mux),
+ FUNCTION("jtag_m0", jtag_grp0, &jtag_grp0_mux),
+ FUNCTION("ks_kas_spi_m0", ks_kas_spi_grp0, &ks_kas_spi_grp0_mux),
+ FUNCTION("ld_ldd", ld_ldd_grp, &ld_ldd_grp_mux),
+ FUNCTION("ld_ldd_16bit", ld_ldd_16bit_grp, &ld_ldd_16bit_grp_mux),
+ FUNCTION("ld_ldd_fck", ld_ldd_fck_grp, &ld_ldd_fck_grp_mux),
+ FUNCTION("ld_ldd_lck", ld_ldd_lck_grp, &ld_ldd_lck_grp_mux),
+ FUNCTION("lr_lcdrom", lr_lcdrom_grp, &lr_lcdrom_grp_mux),
+ FUNCTION("lvds_analog", lvds_analog_grp, &lvds_analog_grp_mux),
+ FUNCTION("nd_df", nd_df_grp, &nd_df_grp_mux),
+ FUNCTION("nd_df_nowp", nd_df_nowp_grp, &nd_df_nowp_grp_mux),
+ FUNCTION("ps", ps_grp, &ps_grp_mux),
+ FUNCTION("pwc_core_on", pwc_core_on_grp, &pwc_core_on_grp_mux),
+ FUNCTION("pwc_ext_on", pwc_ext_on_grp, &pwc_ext_on_grp_mux),
+ FUNCTION("pwc_gpio3_clk", pwc_gpio3_clk_grp, &pwc_gpio3_clk_grp_mux),
+ FUNCTION("pwc_io_on", pwc_io_on_grp, &pwc_io_on_grp_mux),
+ FUNCTION("pwc_lowbatt_b_m0",
+ pwc_lowbatt_b_grp0,
+ &pwc_lowbatt_b_grp0_mux),
+ FUNCTION("pwc_mem_on", pwc_mem_on_grp, &pwc_mem_on_grp_mux),
+ FUNCTION("pwc_on_key_b_m0",
+ pwc_on_key_b_grp0,
+ &pwc_on_key_b_grp0_mux),
+ FUNCTION("pwc_wakeup_src0",
+ pwc_wakeup_src0_grp,
+ &pwc_wakeup_src0_grp_mux),
+ FUNCTION("pwc_wakeup_src1",
+ pwc_wakeup_src1_grp,
+ &pwc_wakeup_src1_grp_mux),
+ FUNCTION("pwc_wakeup_src2",
+ pwc_wakeup_src2_grp,
+ &pwc_wakeup_src2_grp_mux),
+ FUNCTION("pwc_wakeup_src3",
+ pwc_wakeup_src3_grp,
+ &pwc_wakeup_src3_grp_mux),
+ FUNCTION("pw_cko0_m0", pw_cko0_grp0, &pw_cko0_grp0_mux),
+ FUNCTION("pw_cko0_m1", pw_cko0_grp1, &pw_cko0_grp1_mux),
+ FUNCTION("pw_cko0_m2", pw_cko0_grp2, &pw_cko0_grp2_mux),
+ FUNCTION("pw_cko1_m0", pw_cko1_grp0, &pw_cko1_grp0_mux),
+ FUNCTION("pw_cko1_m1", pw_cko1_grp1, &pw_cko1_grp1_mux),
+ FUNCTION("pw_i2s01_clk_m0",
+ pw_i2s01_clk_grp0,
+ &pw_i2s01_clk_grp0_mux),
+ FUNCTION("pw_i2s01_clk_m1",
+ pw_i2s01_clk_grp1,
+ &pw_i2s01_clk_grp1_mux),
+ FUNCTION("pw_pwm0", pw_pwm0_grp, &pw_pwm0_grp_mux),
+ FUNCTION("pw_pwm1", pw_pwm1_grp, &pw_pwm1_grp_mux),
+ FUNCTION("pw_pwm2_m0", pw_pwm2_grp0, &pw_pwm2_grp0_mux),
+ FUNCTION("pw_pwm2_m1", pw_pwm2_grp1, &pw_pwm2_grp1_mux),
+ FUNCTION("pw_pwm3_m0", pw_pwm3_grp0, &pw_pwm3_grp0_mux),
+ FUNCTION("pw_pwm3_m1", pw_pwm3_grp1, &pw_pwm3_grp1_mux),
+ FUNCTION("pw_pwm_cpu_vol_m0",
+ pw_pwm_cpu_vol_grp0,
+ &pw_pwm_cpu_vol_grp0_mux),
+ FUNCTION("pw_pwm_cpu_vol_m1",
+ pw_pwm_cpu_vol_grp1,
+ &pw_pwm_cpu_vol_grp1_mux),
+ FUNCTION("pw_backlight_m0",
+ pw_backlight_grp0,
+ &pw_backlight_grp0_mux),
+ FUNCTION("pw_backlight_m1",
+ pw_backlight_grp1,
+ &pw_backlight_grp1_mux),
+ FUNCTION("rg_eth_mac", rg_eth_mac_grp, &rg_eth_mac_grp_mux),
+ FUNCTION("rg_gmac_phy_intr_n",
+ rg_gmac_phy_intr_n_grp,
+ &rg_gmac_phy_intr_n_grp_mux),
+ FUNCTION("rg_rgmii_mac", rg_rgmii_mac_grp, &rg_rgmii_mac_grp_mux),
+ FUNCTION("rg_rgmii_phy_ref_clk_m0",
+ rg_rgmii_phy_ref_clk_grp0,
+ &rg_rgmii_phy_ref_clk_grp0_mux),
+ FUNCTION("rg_rgmii_phy_ref_clk_m1",
+ rg_rgmii_phy_ref_clk_grp1,
+ &rg_rgmii_phy_ref_clk_grp1_mux),
+ FUNCTION("sd0", sd0_grp, &sd0_grp_mux),
+ FUNCTION("sd0_4bit", sd0_4bit_grp, &sd0_4bit_grp_mux),
+ FUNCTION("sd1", sd1_grp, &sd1_grp_mux),
+ FUNCTION("sd1_4bit_m0", sd1_4bit_grp0, &sd1_4bit_grp0_mux),
+ FUNCTION("sd1_4bit_m1", sd1_4bit_grp1, &sd1_4bit_grp1_mux),
+ FUNCTION("sd2_m0", sd2_grp0, &sd2_grp0_mux),
+ FUNCTION("sd2_no_cdb_m0", sd2_no_cdb_grp0, &sd2_no_cdb_grp0_mux),
+ FUNCTION("sd3", sd3_grp, &sd3_grp_mux),
+ FUNCTION("sd5", sd5_grp, &sd5_grp_mux),
+ FUNCTION("sd6_m0", sd6_grp0, &sd6_grp0_mux),
+ FUNCTION("sd6_m1", sd6_grp1, &sd6_grp1_mux),
+ FUNCTION("sp0_ext_ldo_on",
+ sp0_ext_ldo_on_grp,
+ &sp0_ext_ldo_on_grp_mux),
+ FUNCTION("sp0_qspi", sp0_qspi_grp, &sp0_qspi_grp_mux),
+ FUNCTION("sp1_spi", sp1_spi_grp, &sp1_spi_grp_mux),
+ FUNCTION("tpiu_trace", tpiu_trace_grp, &tpiu_trace_grp_mux),
+ FUNCTION("uart0", uart0_grp, &uart0_grp_mux),
+ FUNCTION("uart0_nopause", uart0_nopause_grp, &uart0_nopause_grp_mux),
+ FUNCTION("uart1", uart1_grp, &uart1_grp_mux),
+ FUNCTION("uart2", uart2_grp, &uart2_grp_mux),
+ FUNCTION("uart3_m0", uart3_grp0, &uart3_grp0_mux),
+ FUNCTION("uart3_m1", uart3_grp1, &uart3_grp1_mux),
+ FUNCTION("uart3_m2", uart3_grp2, &uart3_grp2_mux),
+ FUNCTION("uart3_m3", uart3_grp3, &uart3_grp3_mux),
+ FUNCTION("uart3_nopause_m0",
+ uart3_nopause_grp0,
+ &uart3_nopause_grp0_mux),
+ FUNCTION("uart3_nopause_m1",
+ uart3_nopause_grp1,
+ &uart3_nopause_grp1_mux),
+ FUNCTION("uart4_m0", uart4_grp0, &uart4_grp0_mux),
+ FUNCTION("uart4_m1", uart4_grp1, &uart4_grp1_mux),
+ FUNCTION("uart4_m2", uart4_grp2, &uart4_grp2_mux),
+ FUNCTION("uart4_nopause", uart4_nopause_grp, &uart4_nopause_grp_mux),
+ FUNCTION("usb0_drvvbus", usb0_drvvbus_grp, &usb0_drvvbus_grp_mux),
+ FUNCTION("usb1_drvvbus", usb1_drvvbus_grp, &usb1_drvvbus_grp_mux),
+ FUNCTION("visbus_dout", visbus_dout_grp, &visbus_dout_grp_mux),
+ FUNCTION("vi_vip1", vi_vip1_grp, &vi_vip1_grp_mux),
+ FUNCTION("vi_vip1_ext", vi_vip1_ext_grp, &vi_vip1_ext_grp_mux),
+ FUNCTION("vi_vip1_low8bit",
+ vi_vip1_low8bit_grp,
+ &vi_vip1_low8bit_grp_mux),
+ FUNCTION("vi_vip1_high8bit",
+ vi_vip1_high8bit_grp,
+ &vi_vip1_high8bit_grp_mux),
+};
+
+struct atlas7_pinctrl_data atlas7_ioc_data = {
+ .pads = (struct pinctrl_pin_desc *)atlas7_ioc_pads,
+ .pads_cnt = ARRAY_SIZE(atlas7_ioc_pads),
+ .grps = (struct atlas7_pin_group *)altas7_pin_groups,
+ .grps_cnt = ARRAY_SIZE(altas7_pin_groups),
+ .funcs = (struct atlas7_pmx_func *)atlas7_pmx_functions,
+ .funcs_cnt = ARRAY_SIZE(atlas7_pmx_functions),
+ .confs = (struct atlas7_pad_config *)atlas7_ioc_pad_confs,
+ .confs_cnt = ARRAY_SIZE(atlas7_ioc_pad_confs),
+};
+
+static inline u32 atlas7_pin_to_bank(u32 pin)
+{
+ return (pin >= ATLAS7_PINCTRL_BANK_0_PINS) ? 1 : 0;
+}
+
+static int atlas7_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+ struct atlas7_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ return pmx->pctl_data->funcs_cnt;
+}
+
+static const char *atlas7_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ u32 selector)
+{
+ struct atlas7_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ return pmx->pctl_data->funcs[selector].name;
+}
+
+static int atlas7_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+ u32 selector, const char * const **groups,
+ u32 * const num_groups)
+{
+ struct atlas7_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = pmx->pctl_data->funcs[selector].groups;
+ *num_groups = pmx->pctl_data->funcs[selector].num_groups;
+
+ return 0;
+}
+
+static void __atlas7_pmx_pin_input_disable_set(struct atlas7_pmx *pmx,
+ const struct atlas7_pad_mux *mux)
+{
+ /* Set Input Disable to avoid input glitches
+ *
+ * All Input-Disable Control registers are located on IOCRTC.
+ * So the regs bank is always 0.
+ *
+ */
+ if (mux->dinput_reg && mux->dinput_val_reg) {
+ writel(DI_MASK << mux->dinput_bit,
+ pmx->regs[BANK_DS] + CLR_REG(mux->dinput_reg));
+ writel(DI_DISABLE << mux->dinput_bit,
+ pmx->regs[BANK_DS] + mux->dinput_reg);
+
+
+ writel(DIV_MASK << mux->dinput_val_bit,
+ pmx->regs[BANK_DS] + CLR_REG(mux->dinput_val_reg));
+ writel(DIV_DISABLE << mux->dinput_val_bit,
+ pmx->regs[BANK_DS] + mux->dinput_val_reg);
+ }
+}
+
+static void __atlas7_pmx_pin_input_disable_clr(struct atlas7_pmx *pmx,
+ const struct atlas7_pad_mux *mux)
+{
+ /* Clear Input Disable to avoid input glitches */
+ if (mux->dinput_reg && mux->dinput_val_reg) {
+ writel(DI_MASK << mux->dinput_bit,
+ pmx->regs[BANK_DS] + CLR_REG(mux->dinput_reg));
+ writel(DI_ENABLE << mux->dinput_bit,
+ pmx->regs[BANK_DS] + mux->dinput_reg);
+
+ writel(DIV_MASK << mux->dinput_val_bit,
+ pmx->regs[BANK_DS] + CLR_REG(mux->dinput_val_reg));
+ writel(DIV_ENABLE << mux->dinput_val_bit,
+ pmx->regs[BANK_DS] + mux->dinput_val_reg);
+ }
+}
+
+static int __atlas7_pmx_pin_ad_sel(struct atlas7_pmx *pmx,
+ struct atlas7_pad_config *conf,
+ u32 bank, u32 ad_sel)
+{
+ unsigned long regv;
+
+ /* Write to clear register to clear A/D selector */
+ writel(ANA_CLEAR_MASK << conf->ad_ctrl_bit,
+ pmx->regs[bank] + CLR_REG(conf->ad_ctrl_reg));
+
+ /* Set target pad A/D selector */
+ regv = readl(pmx->regs[bank] + conf->ad_ctrl_reg);
+ regv &= ~(ANA_CLEAR_MASK << conf->ad_ctrl_bit);
+ writel(regv | (ad_sel << conf->ad_ctrl_bit),
+ pmx->regs[bank] + conf->ad_ctrl_reg);
+
+ regv = readl(pmx->regs[bank] + conf->ad_ctrl_reg);
+ pr_debug("bank:%d reg:0x%04x val:0x%08lx\n",
+ bank, conf->ad_ctrl_reg, regv);
+ return 0;
+}
+
+static int __atlas7_pmx_pin_analog_enable(struct atlas7_pmx *pmx,
+ struct atlas7_pad_config *conf, u32 bank)
+{
+ /* Only PAD_T_AD pins can change between Analogue&Digital */
+ if (conf->type != PAD_T_AD)
+ return -EINVAL;
+
+ return __atlas7_pmx_pin_ad_sel(pmx, conf, bank, 0);
+}
+
+static int __atlas7_pmx_pin_digital_enable(struct atlas7_pmx *pmx,
+ struct atlas7_pad_config *conf, u32 bank)
+{
+ /* Other type pads are always digital */
+ if (conf->type != PAD_T_AD)
+ return 0;
+
+ return __atlas7_pmx_pin_ad_sel(pmx, conf, bank, 1);
+}
+
+static int __atlas7_pmx_pin_enable(struct atlas7_pmx *pmx,
+ u32 pin, u32 func)
+{
+ struct atlas7_pad_config *conf;
+ u32 bank;
+ int ret;
+ unsigned long regv;
+
+ pr_debug("PMX DUMP ### pin#%d func:%d #### START >>>\n",
+ pin, func);
+
+ /* Get this Pad's descriptor from PINCTRL */
+ conf = &pmx->pctl_data->confs[pin];
+ bank = atlas7_pin_to_bank(pin);
+
+ /* Just enable the analog function of this pad */
+ if (FUNC_ANALOGUE == func) {
+ ret = __atlas7_pmx_pin_analog_enable(pmx, conf, bank);
+ if (ret)
+ dev_err(pmx->dev,
+ "Convert pad#%d to analog failed, ret=%d\n",
+ pin, ret);
+ return ret;
+ }
+
+ /* Set Pads from analog to digital */
+ ret = __atlas7_pmx_pin_digital_enable(pmx, conf, bank);
+ if (ret) {
+ dev_err(pmx->dev,
+ "Convert pad#%d to digital failed, ret=%d\n",
+ pin, ret);
+ return ret;
+ }
+
+ /* Write to clear register to clear current function */
+ writel(FUNC_CLEAR_MASK << conf->mux_bit,
+ pmx->regs[bank] + CLR_REG(conf->mux_reg));
+
+ /* Set target pad mux function */
+ regv = readl(pmx->regs[bank] + conf->mux_reg);
+ regv &= ~(FUNC_CLEAR_MASK << conf->mux_bit);
+ writel(regv | (func << conf->mux_bit),
+ pmx->regs[bank] + conf->mux_reg);
+
+ regv = readl(pmx->regs[bank] + conf->mux_reg);
+ pr_debug("bank:%d reg:0x%04x val:0x%08lx\n",
+ bank, conf->mux_reg, regv);
+
+ return 0;
+}
+
+static int atlas7_pmx_set_mux(struct pinctrl_dev *pctldev,
+ u32 func_selector, u32 group_selector)
+{
+ int idx, ret;
+ struct atlas7_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ struct atlas7_pmx_func *pmx_func;
+ struct atlas7_pin_group *pin_grp;
+ const struct atlas7_grp_mux *grp_mux;
+ const struct atlas7_pad_mux *mux;
+
+ pmx_func = &pmx->pctl_data->funcs[func_selector];
+ pin_grp = &pmx->pctl_data->grps[group_selector];
+
+ pr_debug("PMX DUMP ### Function:[%s] Group:[%s] #### START >>>\n",
+ pmx_func->name, pin_grp->name);
+
+ grp_mux = pmx_func->grpmux;
+
+ for (idx = 0; idx < grp_mux->pad_mux_count; idx++) {
+ mux = &grp_mux->pad_mux_list[idx];
+ __atlas7_pmx_pin_input_disable_set(pmx, mux);
+ ret = __atlas7_pmx_pin_enable(pmx, mux->pin, mux->func);
+ if (ret) {
+ dev_err(pmx->dev,
+ "FUNC:%s GRP:%s PIN#%d.%d failed, ret=%d\n",
+ pmx_func->name, pin_grp->name,
+ mux->pin, mux->func, ret);
+ BUG_ON(1);
+ }
+ __atlas7_pmx_pin_input_disable_clr(pmx, mux);
+ }
+ pr_debug("PMX DUMP ### Function:[%s] Group:[%s] #### END <<<\n",
+ pmx_func->name, pin_grp->name);
+
+ return 0;
+}
+
+struct atlas7_ds_info {
+ u32 ma;
+ u32 ds_16st;
+ u32 ds_4we;
+ u32 ds_0204m31;
+ u32 ds_0610m31;
+};
+
+const struct atlas7_ds_info atlas7_ds_map[] = {
+ { 2, DS_16ST_0, DS_4WE_0, DS_M31_0, DS_NULL},
+ { 4, DS_16ST_1, DS_NULL, DS_M31_1, DS_NULL},
+ { 6, DS_16ST_2, DS_NULL, DS_NULL, DS_M31_0},
+ { 8, DS_16ST_3, DS_4WE_1, DS_NULL, DS_NULL},
+ { 10, DS_16ST_4, DS_NULL, DS_NULL, DS_M31_1},
+ { 12, DS_16ST_5, DS_NULL, DS_NULL, DS_NULL},
+ { 14, DS_16ST_6, DS_NULL, DS_NULL, DS_NULL},
+ { 16, DS_16ST_7, DS_4WE_2, DS_NULL, DS_NULL},
+ { 18, DS_16ST_8, DS_NULL, DS_NULL, DS_NULL},
+ { 20, DS_16ST_9, DS_NULL, DS_NULL, DS_NULL},
+ { 22, DS_16ST_10, DS_NULL, DS_NULL, DS_NULL},
+ { 24, DS_16ST_11, DS_NULL, DS_NULL, DS_NULL},
+ { 26, DS_16ST_12, DS_NULL, DS_NULL, DS_NULL},
+ { 28, DS_16ST_13, DS_4WE_3, DS_NULL, DS_NULL},
+ { 30, DS_16ST_14, DS_NULL, DS_NULL, DS_NULL},
+ { 32, DS_16ST_15, DS_NULL, DS_NULL, DS_NULL},
+};
+
+static u32 convert_current_to_drive_strength(u32 type, u32 ma)
+{
+ int idx;
+
+ for (idx = 0; idx < ARRAY_SIZE(atlas7_ds_map); idx++) {
+ if (atlas7_ds_map[idx].ma != ma)
+ continue;
+
+ if (type == PAD_T_4WE_PD || type == PAD_T_4WE_PU)
+ return atlas7_ds_map[idx].ds_4we;
+ else if (type == PAD_T_16ST)
+ return atlas7_ds_map[idx].ds_16st;
+ else if (type == PAD_T_M31_0204_PD || type == PAD_T_M31_0204_PU)
+ return atlas7_ds_map[idx].ds_0204m31;
+ else if (type == PAD_T_M31_0610_PD || type == PAD_T_M31_0610_PU)
+ return atlas7_ds_map[idx].ds_0610m31;
+ }
+
+ return DS_NULL;
+}
+
+static int altas7_pinctrl_set_pull_sel(struct pinctrl_dev *pctldev,
+ u32 pin, u32 sel)
+{
+ struct atlas7_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ struct atlas7_pad_config *conf = &pmx->pctl_data->confs[pin];
+ u32 type = conf->type;
+ u32 shift = conf->pupd_bit;
+ u32 bank = atlas7_pin_to_bank(pin);
+ void __iomem *pull_sel_reg, *pull_clr_reg;
+
+ pull_sel_reg = pmx->regs[bank] + conf->pupd_reg;
+ pull_clr_reg = CLR_REG(pull_sel_reg);
+
+ if (type == PAD_T_4WE_PD || type == PAD_T_4WE_PU) {
+ writel(P4WE_PULL_MASK << shift, pull_clr_reg);
+
+ if (sel == PULL_UP)
+ writel(P4WE_PULL_UP << shift, pull_sel_reg);
+ else if (sel == HIGH_HYSTERESIS)
+ writel(P4WE_HIGH_HYSTERESIS << shift, pull_sel_reg);
+ else if (sel == HIGH_Z)
+ writel(P4WE_HIGH_Z << shift, pull_sel_reg);
+ else if (sel == PULL_DOWN)
+ writel(P4WE_PULL_DOWN << shift, pull_sel_reg);
+ else {
+ pr_err("Unknown Pull select type for 4WEPAD#%d\n",
+ pin);
+ return -ENOTSUPP;
+ }
+ } else if (type == PAD_T_16ST) {
+ writel(P16ST_PULL_MASK << shift, pull_clr_reg);
+
+ if (sel == PULL_UP)
+ writel(P16ST_PULL_UP << shift, pull_sel_reg);
+ else if (sel == HIGH_Z)
+ writel(P16ST_HIGH_Z << shift, pull_sel_reg);
+ else if (sel == PULL_DOWN)
+ writel(P16ST_PULL_DOWN << shift, pull_sel_reg);
+ else {
+ pr_err("Unknown Pull select type for 16STPAD#%d\n",
+ pin);
+ return -ENOTSUPP;
+ }
+ } else if (type == PAD_T_M31_0204_PD ||
+ type == PAD_T_M31_0204_PU ||
+ type == PAD_T_M31_0610_PD ||
+ type == PAD_T_M31_0610_PU) {
+ writel(PM31_PULL_MASK << shift, pull_clr_reg);
+
+ if (sel == PULL_UP)
+ writel(PM31_PULL_ENABLED << shift, pull_sel_reg);
+ else if (sel == PULL_DOWN)
+ writel(PM31_PULL_DISABLED << shift, pull_sel_reg);
+ else {
+ pr_err("Unknown Pull select type for M31PAD#%d\n",
+ pin);
+ return -ENOTSUPP;
+ }
+ } else if (type == PAD_T_AD) {
+ writel(PANGD_PULL_MASK << shift, pull_clr_reg);
+
+ if (sel == PULL_UP)
+ writel(PANGD_PULL_UP << shift, pull_sel_reg);
+ else if (sel == HIGH_Z)
+ writel(PANGD_HIGH_Z << shift, pull_sel_reg);
+ else if (sel == PULL_DOWN)
+ writel(PANGD_PULL_DOWN << shift, pull_sel_reg);
+ else {
+ pr_err("Unknown Pull select type for A/D PAD#%d\n",
+ pin);
+ return -ENOTSUPP;
+ }
+ } else {
+ pr_err("Unknown Pad type[%d] for pull select PAD#%d\n",
+ type, pin);
+ return -ENOTSUPP;
+ }
+
+ pr_debug("PIN_CFG ### SET PIN#%d PULL SELECTOR:%d == OK ####\n",
+ pin, sel);
+ return 0;
+}
+
+static int __altas7_pinctrl_set_drive_strength_sel(struct pinctrl_dev *pctldev,
+ u32 pin, u32 sel)
+{
+ struct atlas7_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ struct atlas7_pad_config *conf = &pmx->pctl_data->confs[pin];
+ u32 type = conf->type;
+ u32 shift = conf->drvstr_bit;
+ u32 bank = atlas7_pin_to_bank(pin);
+ void __iomem *ds_sel_reg, *ds_clr_reg;
+
+ ds_sel_reg = pmx->regs[bank] + conf->drvstr_reg;
+ ds_clr_reg = CLR_REG(ds_sel_reg);
+ if (type == PAD_T_4WE_PD || type == PAD_T_4WE_PU) {
+ if (sel & (~DS_2BIT_MASK))
+ goto unsupport;
+
+ writel(DS_2BIT_IM_VAL << shift, ds_clr_reg);
+ writel(sel << shift, ds_sel_reg);
+
+ return 0;
+ } else if (type == PAD_T_16ST) {
+ if (sel & (~DS_4BIT_MASK))
+ goto unsupport;
+
+ writel(DS_4BIT_IM_VAL << shift, ds_clr_reg);
+ writel(sel << shift, ds_sel_reg);
+
+ return 0;
+ } else if (type == PAD_T_M31_0204_PD || type == PAD_T_M31_0204_PU ||
+ type == PAD_T_M31_0610_PD || type == PAD_T_M31_0610_PU) {
+ if (sel & (~DS_1BIT_MASK))
+ goto unsupport;
+
+ writel(DS_1BIT_IM_VAL << shift, ds_clr_reg);
+ writel(sel << shift, ds_sel_reg);
+
+ return 0;
+ }
+
+unsupport:
+ pr_err("Pad#%d type[%d] doesn't support ds code[%d]!\n",
+ pin, type, sel);
+ return -ENOTSUPP;
+}
+
+static int altas7_pinctrl_set_drive_strength_sel(struct pinctrl_dev *pctldev,
+ u32 pin, u32 ma)
+{
+ struct atlas7_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ struct atlas7_pad_config *conf = &pmx->pctl_data->confs[pin];
+ u32 type = conf->type;
+ u32 sel;
+ int ret;
+
+ sel = convert_current_to_drive_strength(conf->type, ma);
+ if (DS_NULL == sel) {
+ pr_err("Pad#%d type[%d] doesn't support ds current[%d]!\n",
+ pin, type, ma);
+ return -ENOTSUPP;
+ }
+
+ ret = __altas7_pinctrl_set_drive_strength_sel(pctldev,
+ pin, sel);
+ pr_debug("PIN_CFG ### SET PIN#%d DS:%d MA:%d == %s ####\n",
+ pin, sel, ma, ret?"FAILED":"OK");
+ return ret;
+}
+
+static int atlas7_pmx_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, u32 pin)
+{
+ struct atlas7_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ u32 idx;
+
+ dev_dbg(pmx->dev,
+ "atlas7_pmx_gpio_request_enable: pin=%d\n", pin);
+ for (idx = 0; idx < range->npins; idx++) {
+ if (pin == range->pins[idx])
+ break;
+ }
+
+ if (idx >= range->npins) {
+ dev_err(pmx->dev,
+ "The pin#%d could not be requested as GPIO!!\n",
+ pin);
+ return -EPERM;
+ }
+
+ __atlas7_pmx_pin_enable(pmx, pin, FUNC_GPIO);
+
+ return 0;
+}
+
+static struct pinmux_ops atlas7_pinmux_ops = {
+ .get_functions_count = atlas7_pmx_get_funcs_count,
+ .get_function_name = atlas7_pmx_get_func_name,
+ .get_function_groups = atlas7_pmx_get_func_groups,
+ .set_mux = atlas7_pmx_set_mux,
+ .gpio_request_enable = atlas7_pmx_gpio_request_enable,
+};
+
+static int atlas7_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct atlas7_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ return pmx->pctl_data->grps_cnt;
+}
+
+static const char *atlas7_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+ u32 group)
+{
+ struct atlas7_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ return pmx->pctl_data->grps[group].name;
+}
+
+static int atlas7_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ u32 group, const u32 **pins, u32 *num_pins)
+{
+ struct atlas7_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ *num_pins = pmx->pctl_data->grps[group].num_pins;
+ *pins = pmx->pctl_data->grps[group].pins;
+
+ return 0;
+}
+
+static int atlas7_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map,
+ u32 *num_maps)
+{
+ return pinconf_generic_dt_node_to_map(pctldev, np_config, map,
+ num_maps, PIN_MAP_TYPE_INVALID);
+}
+
+static void atlas7_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, u32 num_maps)
+{
+ kfree(map);
+}
+
+static const struct pinctrl_ops atlas7_pinctrl_ops = {
+ .get_groups_count = atlas7_pinctrl_get_groups_count,
+ .get_group_name = atlas7_pinctrl_get_group_name,
+ .get_group_pins = atlas7_pinctrl_get_group_pins,
+ .dt_node_to_map = atlas7_pinctrl_dt_node_to_map,
+ .dt_free_map = atlas7_pinctrl_dt_free_map,
+};
+
+static int atlas7_pin_config_set(struct pinctrl_dev *pctldev,
+ unsigned pin, unsigned long *configs,
+ unsigned num_configs)
+{
+ u16 param, arg;
+ int idx, err;
+
+ for (idx = 0; idx < num_configs; idx++) {
+ param = pinconf_to_config_param(configs[idx]);
+ arg = pinconf_to_config_argument(configs[idx]);
+
+ pr_debug("PMX CFG###### ATLAS7 PIN#%d [%s] CONFIG PARAM:%d ARG:%d >>>>>\n",
+ pin, atlas7_ioc_pads[pin].name, param, arg);
+ switch (param) {
+ case PIN_CONFIG_BIAS_PULL_UP:
+ err = altas7_pinctrl_set_pull_sel(pctldev,
+ pin, PULL_UP);
+ if (err)
+ return err;
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ err = altas7_pinctrl_set_pull_sel(pctldev,
+ pin, PULL_DOWN);
+ if (err)
+ return err;
+ break;
+
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ err = altas7_pinctrl_set_pull_sel(pctldev,
+ pin, HIGH_HYSTERESIS);
+ if (err)
+ return err;
+ break;
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ err = altas7_pinctrl_set_pull_sel(pctldev,
+ pin, HIGH_Z);
+ if (err)
+ return err;
+ break;
+
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ err = altas7_pinctrl_set_drive_strength_sel(pctldev,
+ pin, arg);
+ if (err)
+ return err;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+ pr_debug("PMX CFG###### ATLAS7 PIN#%d [%s] CONFIG PARAM:%d ARG:%d <<<<\n",
+ pin, atlas7_ioc_pads[pin].name, param, arg);
+ }
+
+ return 0;
+}
+
+static int atlas7_pin_config_group_set(struct pinctrl_dev *pctldev,
+ unsigned group, unsigned long *configs,
+ unsigned num_configs)
+{
+ const unsigned *pins;
+ unsigned npins;
+ int i, ret;
+
+ ret = atlas7_pinctrl_get_group_pins(pctldev, group, &pins, &npins);
+ if (ret)
+ return ret;
+ for (i = 0; i < npins; i++) {
+ if (atlas7_pin_config_set(pctldev, pins[i],
+ configs, num_configs))
+ return -ENOTSUPP;
+ }
+ return 0;
+}
+
+static const struct pinconf_ops atlas7_pinconf_ops = {
+ .pin_config_set = atlas7_pin_config_set,
+ .pin_config_group_set = atlas7_pin_config_group_set,
+ .is_generic = true,
+};
+
+static int atlas7_pinmux_probe(struct platform_device *pdev)
+{
+ int ret, idx;
+ struct atlas7_pmx *pmx;
+ struct device_node *np = pdev->dev.of_node;
+ u32 banks = ATLAS7_PINCTRL_REG_BANKS;
+
+ /* Create state holders etc for this driver */
+ pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
+ if (!pmx)
+ return -ENOMEM;
+
+ pmx->dev = &pdev->dev;
+
+ pmx->pctl_data = &atlas7_ioc_data;
+ pmx->pctl_desc.name = "pinctrl-atlas7";
+ pmx->pctl_desc.pins = pmx->pctl_data->pads;
+ pmx->pctl_desc.npins = pmx->pctl_data->pads_cnt;
+ pmx->pctl_desc.pctlops = &atlas7_pinctrl_ops;
+ pmx->pctl_desc.pmxops = &atlas7_pinmux_ops;
+ pmx->pctl_desc.confops = &atlas7_pinconf_ops;
+
+ for (idx = 0; idx < banks; idx++) {
+ pmx->regs[idx] = of_iomap(np, idx);
+ if (!pmx->regs[idx]) {
+ dev_err(&pdev->dev,
+ "can't map ioc bank#%d registers\n", idx);
+ ret = -ENOMEM;
+ goto unmap_io;
+ }
+ }
+
+ /* Now register the pin controller and all pins it handles */
+ pmx->pctl = pinctrl_register(&pmx->pctl_desc, &pdev->dev, pmx);
+ if (IS_ERR(pmx->pctl)) {
+ dev_err(&pdev->dev, "could not register atlas7 pinmux driver\n");
+ ret = PTR_ERR(pmx->pctl);
+ goto unmap_io;
+ }
+
+ platform_set_drvdata(pdev, pmx);
+
+ dev_info(&pdev->dev, "initialized atlas7 pinmux driver\n");
+
+ return 0;
+
+unmap_io:
+ for (idx = 0; idx < banks; idx++) {
+ if (!pmx->regs[idx])
+ break;
+ iounmap(pmx->regs[idx]);
+ }
+
+ return ret;
+}
+
+static const struct of_device_id atlas7_pinmux_ids[] = {
+ { .compatible = "sirf,atlas7-ioc",},
+};
+
+static struct platform_driver atlas7_pinmux_driver = {
+ .driver = {
+ .name = "atlas7-ioc",
+ .of_match_table = atlas7_pinmux_ids,
+ },
+ .probe = atlas7_pinmux_probe,
+};
+
+static int __init atlas7_pinmux_init(void)
+{
+ return platform_driver_register(&atlas7_pinmux_driver);
+}
+arch_initcall(atlas7_pinmux_init);
+
+
+/**
+ * The Following is GPIO Code
+ */
+static inline struct
+atlas7_gpio_bank *atlas7_gpio_to_bank(struct atlas7_gpio_chip *a7gc, u32 gpio)
+{
+ return &a7gc->banks[GPIO_TO_BANK(gpio)];
+}
+
+static int __atlas7_gpio_to_pin(struct atlas7_gpio_chip *a7gc, u32 gpio)
+{
+ struct atlas7_gpio_bank *bank;
+ u32 ofs;
+
+ bank = atlas7_gpio_to_bank(a7gc, gpio);
+ ofs = gpio - bank->gpio_offset;
+ if (ofs >= bank->ngpio)
+ return -ENODEV;
+
+ return bank->gpio_pins[ofs];
+}
+
+static void atlas7_gpio_irq_ack(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc);
+ struct atlas7_gpio_bank *bank;
+ void __iomem *ctrl_reg;
+ u32 val, pin_in_bank;
+ unsigned long flags;
+
+ bank = atlas7_gpio_to_bank(a7gc, d->hwirq);
+ pin_in_bank = d->hwirq - bank->gpio_offset;
+ ctrl_reg = ATLAS7_GPIO_CTRL(bank, pin_in_bank);
+
+ spin_lock_irqsave(&a7gc->lock, flags);
+
+ val = readl(ctrl_reg);
+ /* clear interrupt status */
+ writel(val, ctrl_reg);
+
+ spin_unlock_irqrestore(&a7gc->lock, flags);
+}
+
+static void __atlas7_gpio_irq_mask(struct atlas7_gpio_chip *a7gc, int idx)
+{
+ struct atlas7_gpio_bank *bank;
+ void __iomem *ctrl_reg;
+ u32 val, pin_in_bank;
+
+ bank = atlas7_gpio_to_bank(a7gc, idx);
+ pin_in_bank = idx - bank->gpio_offset;
+ ctrl_reg = ATLAS7_GPIO_CTRL(bank, pin_in_bank);
+
+ val = readl(ctrl_reg);
+ val &= ~(ATLAS7_GPIO_CTL_INTR_EN_MASK |
+ ATLAS7_GPIO_CTL_INTR_STATUS_MASK);
+ writel(val, ctrl_reg);
+}
+
+static void atlas7_gpio_irq_mask(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&a7gc->lock, flags);
+
+ __atlas7_gpio_irq_mask(a7gc, d->hwirq);
+
+ spin_unlock_irqrestore(&a7gc->lock, flags);
+}
+
+static void atlas7_gpio_irq_unmask(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc);
+ struct atlas7_gpio_bank *bank;
+ void __iomem *ctrl_reg;
+ u32 val, pin_in_bank;
+ unsigned long flags;
+
+ bank = atlas7_gpio_to_bank(a7gc, d->hwirq);
+ pin_in_bank = d->hwirq - bank->gpio_offset;
+ ctrl_reg = ATLAS7_GPIO_CTRL(bank, pin_in_bank);
+
+ spin_lock_irqsave(&a7gc->lock, flags);
+
+ val = readl(ctrl_reg);
+ val &= ~ATLAS7_GPIO_CTL_INTR_STATUS_MASK;
+ val |= ATLAS7_GPIO_CTL_INTR_EN_MASK;
+ writel(val, ctrl_reg);
+
+ spin_unlock_irqrestore(&a7gc->lock, flags);
+}
+
+static int atlas7_gpio_irq_type(struct irq_data *d,
+ unsigned int type)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc);
+ struct atlas7_gpio_bank *bank;
+ void __iomem *ctrl_reg;
+ u32 val, pin_in_bank;
+ unsigned long flags;
+
+ bank = atlas7_gpio_to_bank(a7gc, d->hwirq);
+ pin_in_bank = d->hwirq - bank->gpio_offset;
+ ctrl_reg = ATLAS7_GPIO_CTRL(bank, pin_in_bank);
+
+ spin_lock_irqsave(&a7gc->lock, flags);
+
+ val = readl(ctrl_reg);
+ val &= ~(ATLAS7_GPIO_CTL_INTR_STATUS_MASK |
+ ATLAS7_GPIO_CTL_INTR_EN_MASK);
+
+ switch (type) {
+ case IRQ_TYPE_NONE:
+ break;
+
+ case IRQ_TYPE_EDGE_RISING:
+ val |= ATLAS7_GPIO_CTL_INTR_HIGH_MASK |
+ ATLAS7_GPIO_CTL_INTR_TYPE_MASK;
+ val &= ~ATLAS7_GPIO_CTL_INTR_LOW_MASK;
+ break;
+
+ case IRQ_TYPE_EDGE_FALLING:
+ val &= ~ATLAS7_GPIO_CTL_INTR_HIGH_MASK;
+ val |= ATLAS7_GPIO_CTL_INTR_LOW_MASK |
+ ATLAS7_GPIO_CTL_INTR_TYPE_MASK;
+ break;
+
+ case IRQ_TYPE_EDGE_BOTH:
+ val |= ATLAS7_GPIO_CTL_INTR_HIGH_MASK |
+ ATLAS7_GPIO_CTL_INTR_LOW_MASK |
+ ATLAS7_GPIO_CTL_INTR_TYPE_MASK;
+ break;
+
+ case IRQ_TYPE_LEVEL_LOW:
+ val &= ~(ATLAS7_GPIO_CTL_INTR_HIGH_MASK |
+ ATLAS7_GPIO_CTL_INTR_TYPE_MASK);
+ val |= ATLAS7_GPIO_CTL_INTR_LOW_MASK;
+ break;
+
+ case IRQ_TYPE_LEVEL_HIGH:
+ val |= ATLAS7_GPIO_CTL_INTR_HIGH_MASK;
+ val &= ~(ATLAS7_GPIO_CTL_INTR_LOW_MASK |
+ ATLAS7_GPIO_CTL_INTR_TYPE_MASK);
+ break;
+ }
+
+ writel(val, ctrl_reg);
+
+ spin_unlock_irqrestore(&a7gc->lock, flags);
+
+ return 0;
+}
+
+static struct irq_chip atlas7_gpio_irq_chip = {
+ .name = "atlas7-gpio-irq",
+ .irq_ack = atlas7_gpio_irq_ack,
+ .irq_mask = atlas7_gpio_irq_mask,
+ .irq_unmask = atlas7_gpio_irq_unmask,
+ .irq_set_type = atlas7_gpio_irq_type,
+};
+
+static void atlas7_gpio_handle_irq(unsigned int irq, struct irq_desc *desc)
+{
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+ struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc);
+ struct atlas7_gpio_bank *bank = NULL;
+ u32 status, ctrl;
+ int pin_in_bank = 0, idx;
+ struct irq_chip *chip = irq_get_chip(irq);
+
+ for (idx = 0; idx < a7gc->nbank; idx++) {
+ bank = &a7gc->banks[idx];
+ if (bank->irq == irq)
+ break;
+ }
+ BUG_ON(idx == a7gc->nbank);
+
+ chained_irq_enter(chip, desc);
+
+ status = readl(ATLAS7_GPIO_INT_STATUS(bank));
+ if (!status) {
+ pr_warn("%s: gpio [%s] status %#x no interrupt is flaged\n",
+ __func__, gc->label, status);
+ handle_bad_irq(irq, desc);
+ return;
+ }
+
+ while (status) {
+ ctrl = readl(ATLAS7_GPIO_CTRL(bank, pin_in_bank));
+
+ /*
+ * Here we must check whether the corresponding GPIO's
+ * interrupt has been enabled, otherwise just skip it
+ */
+ if ((status & 0x1) && (ctrl & ATLAS7_GPIO_CTL_INTR_EN_MASK)) {
+ pr_debug("%s: chip[%s] gpio:%d happens\n",
+ __func__, gc->label,
+ bank->gpio_offset + pin_in_bank);
+ generic_handle_irq(
+ irq_find_mapping(gc->irqdomain,
+ bank->gpio_offset + pin_in_bank));
+ }
+
+ if (++pin_in_bank >= bank->ngpio)
+ break;
+
+ status = status >> 1;
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void __atlas7_gpio_set_input(struct atlas7_gpio_chip *a7gc,
+ unsigned int gpio)
+{
+ struct atlas7_gpio_bank *bank;
+ void __iomem *ctrl_reg;
+ u32 val, pin_in_bank;
+
+ bank = atlas7_gpio_to_bank(a7gc, gpio);
+ pin_in_bank = gpio - bank->gpio_offset;
+ ctrl_reg = ATLAS7_GPIO_CTRL(bank, pin_in_bank);
+
+ val = readl(ctrl_reg);
+ val &= ~ATLAS7_GPIO_CTL_OUT_EN_MASK;
+ writel(val, ctrl_reg);
+}
+
+static int atlas7_gpio_request(struct gpio_chip *chip,
+ unsigned int gpio)
+{
+ struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+ int ret;
+ unsigned long flags;
+
+ ret = __atlas7_gpio_to_pin(a7gc, gpio);
+ if (ret < 0)
+ return ret;
+
+ if (pinctrl_request_gpio(chip->base + gpio))
+ return -ENODEV;
+
+ spin_lock_irqsave(&a7gc->lock, flags);
+
+ /*
+ * default status:
+ * set direction as input and mask irq
+ */
+ __atlas7_gpio_set_input(a7gc, gpio);
+ __atlas7_gpio_irq_mask(a7gc, gpio);
+
+ spin_unlock_irqrestore(&a7gc->lock, flags);
+
+ return 0;
+}
+
+static void atlas7_gpio_free(struct gpio_chip *chip,
+ unsigned int gpio)
+{
+ struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+ unsigned long flags;
+
+ spin_lock_irqsave(&a7gc->lock, flags);
+
+ __atlas7_gpio_irq_mask(a7gc, gpio);
+ __atlas7_gpio_set_input(a7gc, gpio);
+
+ spin_unlock_irqrestore(&a7gc->lock, flags);
+
+ pinctrl_free_gpio(chip->base + gpio);
+}
+
+static int atlas7_gpio_direction_input(struct gpio_chip *chip,
+ unsigned int gpio)
+{
+ struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+ unsigned long flags;
+
+ spin_lock_irqsave(&a7gc->lock, flags);
+
+ __atlas7_gpio_set_input(a7gc, gpio);
+
+ spin_unlock_irqrestore(&a7gc->lock, flags);
+
+ return 0;
+}
+
+static void __atlas7_gpio_set_output(struct atlas7_gpio_chip *a7gc,
+ unsigned int gpio, int value)
+{
+ struct atlas7_gpio_bank *bank;
+ void __iomem *ctrl_reg;
+ u32 out_ctrl, pin_in_bank;
+
+ bank = atlas7_gpio_to_bank(a7gc, gpio);
+ pin_in_bank = gpio - bank->gpio_offset;
+ ctrl_reg = ATLAS7_GPIO_CTRL(bank, pin_in_bank);
+
+ out_ctrl = readl(ctrl_reg);
+ if (value)
+ out_ctrl |= ATLAS7_GPIO_CTL_DATAOUT_MASK;
+ else
+ out_ctrl &= ~ATLAS7_GPIO_CTL_DATAOUT_MASK;
+
+ out_ctrl &= ~ATLAS7_GPIO_CTL_INTR_EN_MASK;
+ out_ctrl |= ATLAS7_GPIO_CTL_OUT_EN_MASK;
+ writel(out_ctrl, ctrl_reg);
+}
+
+static int atlas7_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int gpio, int value)
+{
+ struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+ unsigned long flags;
+
+ spin_lock_irqsave(&a7gc->lock, flags);
+
+ __atlas7_gpio_set_output(a7gc, gpio, value);
+
+ spin_unlock_irqrestore(&a7gc->lock, flags);
+
+ return 0;
+}
+
+static int atlas7_gpio_get_value(struct gpio_chip *chip,
+ unsigned int gpio)
+{
+ struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+ struct atlas7_gpio_bank *bank;
+ u32 val, pin_in_bank;
+ unsigned long flags;
+
+ bank = atlas7_gpio_to_bank(a7gc, gpio);
+ pin_in_bank = gpio - bank->gpio_offset;
+
+ spin_lock_irqsave(&a7gc->lock, flags);
+
+ val = readl(ATLAS7_GPIO_CTRL(bank, pin_in_bank));
+
+ spin_unlock_irqrestore(&a7gc->lock, flags);
+
+ return !!(val & ATLAS7_GPIO_CTL_DATAIN_MASK);
+}
+
+static void atlas7_gpio_set_value(struct gpio_chip *chip,
+ unsigned int gpio, int value)
+{
+ struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+ struct atlas7_gpio_bank *bank;
+ void __iomem *ctrl_reg;
+ u32 ctrl, pin_in_bank;
+ unsigned long flags;
+
+ bank = atlas7_gpio_to_bank(a7gc, gpio);
+ pin_in_bank = gpio - bank->gpio_offset;
+ ctrl_reg = ATLAS7_GPIO_CTRL(bank, pin_in_bank);
+
+ spin_lock_irqsave(&a7gc->lock, flags);
+
+ ctrl = readl(ctrl_reg);
+ if (value)
+ ctrl |= ATLAS7_GPIO_CTL_DATAOUT_MASK;
+ else
+ ctrl &= ~ATLAS7_GPIO_CTL_DATAOUT_MASK;
+ writel(ctrl, ctrl_reg);
+
+ spin_unlock_irqrestore(&a7gc->lock, flags);
+}
+
+static const struct of_device_id atlas7_gpio_ids[] = {
+ { .compatible = "sirf,atlas7-gpio", },
+};
+
+static int atlas7_gpio_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct atlas7_gpio_chip *a7gc;
+ struct gpio_chip *chip;
+ u32 nbank;
+ int ret, idx;
+
+ ret = of_property_read_u32(np, "gpio-banks", &nbank);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Could not find GPIO bank info,ret=%d!\n",
+ ret);
+ return ret;
+ }
+
+ /* retrieve gpio descriptor data */
+ a7gc = devm_kzalloc(&pdev->dev, sizeof(*a7gc) +
+ sizeof(struct atlas7_gpio_bank) * nbank, GFP_KERNEL);
+ if (!a7gc)
+ return -ENOMEM;
+
+ /* Get Gpio clk */
+ a7gc->clk = of_clk_get(np, 0);
+ if (!IS_ERR(a7gc->clk)) {
+ ret = clk_prepare_enable(a7gc->clk);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Could not enable clock!\n");
+ return ret;
+ }
+ }
+
+ /* Get Gpio Registers */
+ a7gc->reg = of_iomap(np, 0);
+ if (!a7gc->reg) {
+ dev_err(&pdev->dev, "Could not map GPIO Registers!\n");
+ return -ENOMEM;
+ }
+
+ a7gc->nbank = nbank;
+ spin_lock_init(&a7gc->lock);
+
+ /* Setup GPIO Chip */
+ chip = &a7gc->chip;
+ chip->request = atlas7_gpio_request;
+ chip->free = atlas7_gpio_free;
+ chip->direction_input = atlas7_gpio_direction_input;
+ chip->get = atlas7_gpio_get_value;
+ chip->direction_output = atlas7_gpio_direction_output;
+ chip->set = atlas7_gpio_set_value;
+ chip->base = -1;
+ /* Each chip can support 32 pins at one bank */
+ chip->ngpio = NGPIO_OF_BANK * nbank;
+ chip->label = kstrdup(np->name, GFP_KERNEL);
+ chip->of_node = np;
+ chip->of_gpio_n_cells = 2;
+ chip->dev = &pdev->dev;
+
+ /* Add gpio chip to system */
+ ret = gpiochip_add(chip);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: error in probe function with status %d\n",
+ np->name, ret);
+ goto failed;
+ }
+
+ /* Add gpio chip to irq subsystem */
+ ret = gpiochip_irqchip_add(chip, &atlas7_gpio_irq_chip,
+ 0, handle_level_irq, IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "could not connect irqchip to gpiochip\n");
+ goto failed;
+ }
+
+ for (idx = 0; idx < nbank; idx++) {
+ struct gpio_pin_range *pin_range;
+ struct atlas7_gpio_bank *bank;
+
+ bank = &a7gc->banks[idx];
+ /* Set ctrl registers' base of this bank */
+ bank->base = ATLAS7_GPIO_BASE(a7gc, idx);
+
+ /* Get interrupt number from DTS */
+ ret = of_irq_get(np, idx);
+ if (ret == -EPROBE_DEFER) {
+ dev_err(&pdev->dev,
+ "Unable to find IRQ number. ret=%d\n", ret);
+ goto failed;
+ }
+ bank->irq = ret;
+
+ gpiochip_set_chained_irqchip(chip, &atlas7_gpio_irq_chip,
+ bank->irq, atlas7_gpio_handle_irq);
+
+ /* Records gpio_pin_range to a7gc */
+ list_for_each_entry(pin_range, &chip->pin_ranges, node) {
+ struct pinctrl_gpio_range *range;
+
+ range = &pin_range->range;
+ if (range->id == NGPIO_OF_BANK * idx) {
+ bank->gpio_offset = range->id;
+ bank->ngpio = range->npins;
+ bank->gpio_pins = range->pins;
+ bank->pctldev = pin_range->pctldev;
+ break;
+ }
+ }
+
+ BUG_ON(!bank->pctldev);
+ }
+
+ dev_info(&pdev->dev, "add to system.\n");
+ return 0;
+failed:
+ return ret;
+}
+
+static struct platform_driver atlas7_gpio_driver = {
+ .driver = {
+ .name = "atlas7-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = atlas7_gpio_ids,
+ },
+ .probe = atlas7_gpio_probe,
+};
+
+static int __init atlas7_gpio_init(void)
+{
+ return platform_driver_register(&atlas7_gpio_driver);
+}
+subsys_initcall(atlas7_gpio_init);
+
+MODULE_DESCRIPTION("SIRFSOC Atlas7 pin control driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c
index e2efbbae4061..8ba26e45499a 100644
--- a/drivers/pinctrl/sirf/pinctrl-sirf.c
+++ b/drivers/pinctrl/sirf/pinctrl-sirf.c
@@ -310,9 +310,9 @@ static int sirfsoc_pinmux_probe(struct platform_device *pdev)
/* Now register the pin controller and all pins it handles */
spmx->pmx = pinctrl_register(&sirfsoc_pinmux_desc, &pdev->dev, spmx);
- if (!spmx->pmx) {
+ if (IS_ERR(spmx->pmx)) {
dev_err(&pdev->dev, "could not register SIRFSOC pinmux driver\n");
- ret = -EINVAL;
+ ret = PTR_ERR(spmx->pmx);
goto out_no_pmx;
}
diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c
index abdb05ac43dc..f87a5eaf75da 100644
--- a/drivers/pinctrl/spear/pinctrl-spear.c
+++ b/drivers/pinctrl/spear/pinctrl-spear.c
@@ -396,9 +396,9 @@ int spear_pinctrl_probe(struct platform_device *pdev,
spear_pinctrl_desc.npins = machdata->npins;
pmx->pctl = pinctrl_register(&spear_pinctrl_desc, &pdev->dev, pmx);
- if (!pmx->pctl) {
+ if (IS_ERR(pmx->pctl)) {
dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
- return -ENODEV;
+ return PTR_ERR(pmx->pctl);
}
return 0;
diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
index 2eb893e0ea1e..ae27872ff3a6 100644
--- a/drivers/pinctrl/sunxi/Kconfig
+++ b/drivers/pinctrl/sunxi/Kconfig
@@ -38,6 +38,10 @@ config PINCTRL_SUN8I_A23
def_bool MACH_SUN8I
select PINCTRL_SUNXI_COMMON
+config PINCTRL_SUN8I_A33
+ def_bool MACH_SUN8I
+ select PINCTRL_SUNXI_COMMON
+
config PINCTRL_SUN8I_A23_R
def_bool MACH_SUN8I
depends on RESET_CONTROLLER
diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile
index b796d579dce6..227a1213947c 100644
--- a/drivers/pinctrl/sunxi/Makefile
+++ b/drivers/pinctrl/sunxi/Makefile
@@ -11,4 +11,5 @@ obj-$(CONFIG_PINCTRL_SUN6I_A31_R) += pinctrl-sun6i-a31-r.o
obj-$(CONFIG_PINCTRL_SUN7I_A20) += pinctrl-sun7i-a20.o
obj-$(CONFIG_PINCTRL_SUN8I_A23) += pinctrl-sun8i-a23.o
obj-$(CONFIG_PINCTRL_SUN8I_A23_R) += pinctrl-sun8i-a23-r.o
+obj-$(CONFIG_PINCTRL_SUN8I_A33) += pinctrl-sun8i-a33.o
obj-$(CONFIG_PINCTRL_SUN9I_A80) += pinctrl-sun9i-a80.o
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c
index d3725dcd6979..e570d5c93ecc 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c
@@ -804,7 +804,6 @@ static struct platform_driver sun6i_a31s_pinctrl_driver = {
.probe = sun6i_a31s_pinctrl_probe,
.driver = {
.name = "sun6i-a31s-pinctrl",
- .owner = THIS_MODULE,
.of_match_table = sun6i_a31s_pinctrl_match,
},
};
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c
new file mode 100644
index 000000000000..00265f0435a7
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c
@@ -0,0 +1,513 @@
+/*
+ * Allwinner a33 SoCs pinctrl driver.
+ *
+ * Copyright (C) 2015 Vishnu Patekar <vishnupatekar0510@gmail.com>
+ *
+ * Based on pinctrl-sun8i-a23.c, which is:
+ * Copyright (C) 2014 Chen-Yu Tsai <wens@csie.org>
+ * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin sun8i_a33_pins[] = {
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* TX */
+ SUNXI_FUNCTION(0x3, "uart0"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 0)), /* PB_EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RX */
+ SUNXI_FUNCTION(0x3, "uart0"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 1)), /* PB_EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 2)), /* PB_EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 3)), /* PB_EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* SYNC */
+ SUNXI_FUNCTION(0x3, "aif2"), /* SYNC */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 4)), /* PB_EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* BCLK */
+ SUNXI_FUNCTION(0x3, "aif2"), /* BCLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 5)), /* PB_EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* DOUT */
+ SUNXI_FUNCTION(0x3, "aif2"), /* DOUT */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 6)), /* PB_EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* DIN */
+ SUNXI_FUNCTION(0x3, "aif2"), /* DIN */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 0, 7)), /* PB_EINT7 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* WE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* ALE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* MISO */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* CLE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* CE1 */
+ SUNXI_FUNCTION(0x3, "spi0")), /* CS */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* CE0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* RE */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* RB0 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* RB1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ0 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ1 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ2 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ3 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ4 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ5 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand"), /* DQ6 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand"), /* DQ7 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand"), /* DQS */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* RST */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */
+ SUNXI_FUNCTION(0x3, "mmc1")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */
+ SUNXI_FUNCTION(0x3, "mmc1")), /* CMD */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */
+ SUNXI_FUNCTION(0x3, "mmc1")), /* D0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */
+ SUNXI_FUNCTION(0x3, "mmc1")), /* D1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */
+ SUNXI_FUNCTION(0x3, "mmc1")), /* D2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */
+ SUNXI_FUNCTION(0x3, "mmc1")), /* D3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D10 */
+ SUNXI_FUNCTION(0x3, "uart1")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D11 */
+ SUNXI_FUNCTION(0x3, "uart1")), /* RX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D12 */
+ SUNXI_FUNCTION(0x3, "uart1")), /* RTS */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D13 */
+ SUNXI_FUNCTION(0x3, "uart1")), /* CTS */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D14 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D15 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D18 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D19 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VN0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D20 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D21 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VN1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D22 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D23 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VN2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VPC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 25),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* DE */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VNC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 26),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* HSYNC */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 27),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* VSYNC */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VN3 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* PCLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* MCLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* HSYNC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* VSYNC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi")), /* D7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* SCK */
+ SUNXI_FUNCTION(0x3, "i2c2")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* SDA */
+ SUNXI_FUNCTION(0x3, "i2c2")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */
+ SUNXI_FUNCTION(0x3, "jtag")), /* MS1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */
+ SUNXI_FUNCTION(0x3, "jtag")), /* DI1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "uart0")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */
+ SUNXI_FUNCTION(0x3, "jtag")), /* DO1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */
+ SUNXI_FUNCTION(0x3, "uart0")), /* RX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */
+ SUNXI_FUNCTION(0x3, "jtag")), /* CK1 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 0)), /* PG_EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 1)), /* PG_EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D0 */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 2)), /* PG_EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D1 */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 3)), /* PG_EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D2 */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 4)), /* PG_EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D3 */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 5)), /* PG_EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 6)), /* PG_EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 7)), /* PG_EINT7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 8)), /* PG_EINT8 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 9)), /* PG_EINT9 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1"), /* SYNC */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 10)), /* PG_EINT10 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 11)), /* PG_EINT11 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1"), /* DOUT */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 12)), /* PG_EINT12 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1"), /* DIN */
+ SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 13)), /* PG_EINT13 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "pwm0")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "pwm1")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* CS */
+ SUNXI_FUNCTION(0x3, "uart3")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "uart3")), /* RX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* DOUT */
+ SUNXI_FUNCTION(0x3, "uart3")), /* RTS */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* DIN */
+ SUNXI_FUNCTION(0x3, "uart3")), /* CTS */
+};
+
+static const struct sunxi_pinctrl_desc sun8i_a33_pinctrl_data = {
+ .pins = sun8i_a33_pins,
+ .npins = ARRAY_SIZE(sun8i_a33_pins),
+ .irq_banks = 2,
+};
+
+static int sun8i_a33_pinctrl_probe(struct platform_device *pdev)
+{
+ return sunxi_pinctrl_init(pdev,
+ &sun8i_a33_pinctrl_data);
+}
+
+static const struct of_device_id sun8i_a33_pinctrl_match[] = {
+ { .compatible = "allwinner,sun8i-a33-pinctrl", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun8i_a33_pinctrl_match);
+
+static struct platform_driver sun8i_a33_pinctrl_driver = {
+ .probe = sun8i_a33_pinctrl_probe,
+ .driver = {
+ .name = "sun8i-a33-pinctrl",
+ .of_match_table = sun8i_a33_pinctrl_match,
+ },
+};
+module_platform_driver(sun8i_a33_pinctrl_driver);
+
+MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510@gmail.com>");
+MODULE_DESCRIPTION("Allwinner a33 pinctrl driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index f8e171b76693..d7857c72e627 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -911,9 +911,9 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
pctl->pctl_dev = pinctrl_register(pctrl_desc,
&pdev->dev, pctl);
- if (!pctl->pctl_dev) {
+ if (IS_ERR(pctl->pctl_dev)) {
dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
- return -EINVAL;
+ return PTR_ERR(pctl->pctl_dev);
}
pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c
index d055d63309e4..c15316b003c5 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wmt.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c
@@ -594,9 +594,9 @@ int wmt_pinctrl_probe(struct platform_device *pdev,
data->dev = &pdev->dev;
data->pctl_dev = pinctrl_register(&wmt_desc, &pdev->dev, data);
- if (!data->pctl_dev) {
+ if (IS_ERR(data->pctl_dev)) {
dev_err(&pdev->dev, "Failed to register pinctrl\n");
- return -EINVAL;
+ return PTR_ERR(data->pctl_dev);
}
err = gpiochip_add(&data->gpio_chip);
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 00b7d9c9fe48..2f5b518b0e78 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -2150,7 +2150,7 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
rc = lcs_detect(card);
if (rc) {
LCS_DBF_TEXT(2, setup, "dtctfail");
- dev_err(&card->dev->dev,
+ dev_err(&ccwgdev->dev,
"Detecting a network adapter for LCS devices"
" failed with rc=%d (0x%x)\n", rc, rc);
lcs_stopcard(card);
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 3abac028899f..ba974a2e409f 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -175,6 +175,8 @@ struct qeth_sbp_info {
__u32 supported_funcs;
enum qeth_sbp_roles role;
__u32 hostnotification:1;
+ __u32 reflect_promisc:1;
+ __u32 reflect_promisc_primary:1;
};
static inline int qeth_is_ipa_supported(struct qeth_ipa_info *ipa,
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 3466d3cb7647..5e20fba37bff 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -645,7 +645,8 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
card->info.hwtrap = 2;
qeth_schedule_recovery(card);
return NULL;
- case IPA_CMD_SETBRIDGEPORT:
+ case IPA_CMD_SETBRIDGEPORT_IQD:
+ case IPA_CMD_SETBRIDGEPORT_OSA:
case IPA_CMD_ADDRESS_CHANGE_NOTIF:
if (card->discipline->control_event_handler
(card, cmd))
diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c
index 7b55768a9592..beb4bdc26de5 100644
--- a/drivers/s390/net/qeth_core_mpc.c
+++ b/drivers/s390/net/qeth_core_mpc.c
@@ -237,6 +237,7 @@ static struct ipa_cmd_names qeth_ipa_cmd_names[] = {
{IPA_CMD_DELGMAC, "delgmac"},
{IPA_CMD_SETVLAN, "setvlan"},
{IPA_CMD_DELVLAN, "delvlan"},
+ {IPA_CMD_SETBRIDGEPORT_OSA, "set_bridge_port(osa)"},
{IPA_CMD_SETCCID, "setccid"},
{IPA_CMD_DELCCID, "delccid"},
{IPA_CMD_MODCCID, "modccid"},
@@ -249,7 +250,7 @@ static struct ipa_cmd_names qeth_ipa_cmd_names[] = {
{IPA_CMD_DELIP, "delip"},
{IPA_CMD_SETADAPTERPARMS, "setadapterparms"},
{IPA_CMD_SET_DIAG_ASS, "set_diag_ass"},
- {IPA_CMD_SETBRIDGEPORT, "set_bridge_port"},
+ {IPA_CMD_SETBRIDGEPORT_IQD, "set_bridge_port(hs)"},
{IPA_CMD_CREATE_ADDR, "create_addr"},
{IPA_CMD_DESTROY_ADDR, "destroy_addr"},
{IPA_CMD_REGISTER_LOCAL_ADDR, "register_local_addr"},
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index 1558be1af72d..6cccc9a49ede 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -92,6 +92,7 @@ enum qeth_ipa_cmds {
IPA_CMD_DELGMAC = 0x24,
IPA_CMD_SETVLAN = 0x25,
IPA_CMD_DELVLAN = 0x26,
+ IPA_CMD_SETBRIDGEPORT_OSA = 0x2b,
IPA_CMD_SETCCID = 0x41,
IPA_CMD_DELCCID = 0x42,
IPA_CMD_MODCCID = 0x43,
@@ -104,7 +105,7 @@ enum qeth_ipa_cmds {
IPA_CMD_DELIP = 0xb7,
IPA_CMD_SETADAPTERPARMS = 0xb8,
IPA_CMD_SET_DIAG_ASS = 0xb9,
- IPA_CMD_SETBRIDGEPORT = 0xbe,
+ IPA_CMD_SETBRIDGEPORT_IQD = 0xbe,
IPA_CMD_CREATE_ADDR = 0xc3,
IPA_CMD_DESTROY_ADDR = 0xc4,
IPA_CMD_REGISTER_LOCAL_ADDR = 0xd1,
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 0ea0869120cf..2e65b989a9ea 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -137,7 +137,7 @@ static int qeth_setdel_makerc(struct qeth_card *card, int retcode)
rc = 0;
break;
case IPA_RC_L2_UNSUPPORTED_CMD:
- rc = -ENOSYS;
+ rc = -EOPNOTSUPP;
break;
case IPA_RC_L2_ADDR_TABLE_FULL:
rc = -ENOSPC;
@@ -683,6 +683,39 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
return rc ? -EINVAL : 0;
}
+static void qeth_promisc_to_bridge(struct qeth_card *card)
+{
+ struct net_device *dev = card->dev;
+ enum qeth_ipa_promisc_modes promisc_mode;
+ int role;
+ int rc;
+
+ QETH_CARD_TEXT(card, 3, "pmisc2br");
+
+ if (!card->options.sbp.reflect_promisc)
+ return;
+ promisc_mode = (dev->flags & IFF_PROMISC) ? SET_PROMISC_MODE_ON
+ : SET_PROMISC_MODE_OFF;
+ if (promisc_mode == card->info.promisc_mode)
+ return;
+
+ if (promisc_mode == SET_PROMISC_MODE_ON) {
+ if (card->options.sbp.reflect_promisc_primary)
+ role = QETH_SBP_ROLE_PRIMARY;
+ else
+ role = QETH_SBP_ROLE_SECONDARY;
+ } else
+ role = QETH_SBP_ROLE_NONE;
+
+ rc = qeth_bridgeport_setrole(card, role);
+ QETH_DBF_TEXT_(SETUP, 2, "bpm%c%04x",
+ (promisc_mode == SET_PROMISC_MODE_ON) ? '+' : '-', rc);
+ if (!rc) {
+ card->options.sbp.role = role;
+ card->info.promisc_mode = promisc_mode;
+ }
+}
+
static void qeth_l2_set_multicast_list(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
@@ -704,9 +737,10 @@ static void qeth_l2_set_multicast_list(struct net_device *dev)
qeth_l2_add_mc(card, ha->addr, 1);
spin_unlock_bh(&card->mclock);
- if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
- return;
- qeth_setadp_promisc_mode(card);
+ if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
+ qeth_setadp_promisc_mode(card);
+ else
+ qeth_promisc_to_bridge(card);
}
static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -994,7 +1028,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
qeth_bridgeport_query_support(card);
if (card->options.sbp.supported_funcs)
dev_info(&card->gdev->dev,
- "The device represents a HiperSockets Bridge Capable Port\n");
+ "The device represents a Bridge Capable Port\n");
qeth_trace_features(card);
if (!card->dev && qeth_l2_setup_netdev(card)) {
@@ -1247,7 +1281,8 @@ static int qeth_l2_control_event(struct qeth_card *card,
struct qeth_ipa_cmd *cmd)
{
switch (cmd->hdr.command) {
- case IPA_CMD_SETBRIDGEPORT:
+ case IPA_CMD_SETBRIDGEPORT_OSA:
+ case IPA_CMD_SETBRIDGEPORT_IQD:
if (cmd->data.sbp.hdr.command_code ==
IPA_SBP_BRIDGE_PORT_STATE_CHANGE) {
qeth_bridge_state_change(card, cmd);
@@ -1533,7 +1568,7 @@ static void qeth_bridge_host_event_worker(struct work_struct *work)
if (data->hostevs.lost_event_mask) {
dev_info(&data->card->gdev->dev,
-"Address notification from the HiperSockets Bridge Port stopped %s (%s)\n",
+"Address notification from the Bridge Port stopped %s (%s)\n",
data->card->dev->name,
(data->hostevs.lost_event_mask == 0x01)
? "Overflow"
@@ -1617,70 +1652,80 @@ static int qeth_bridgeport_makerc(struct qeth_card *card,
struct _qeth_sbp_cbctl *cbctl, enum qeth_ipa_sbp_cmd setcmd)
{
int rc;
+ int is_iqd = (card->info.type == QETH_CARD_TYPE_IQD);
- switch (cbctl->ipa_rc) {
- case IPA_RC_SUCCESS:
+ if ((is_iqd && (cbctl->ipa_rc == IPA_RC_SUCCESS)) ||
+ (!is_iqd && (cbctl->ipa_rc == cbctl->cmd_rc)))
switch (cbctl->cmd_rc) {
case 0x0000:
rc = 0;
break;
+ case 0x2B04:
case 0x0004:
- rc = -ENOSYS;
+ rc = -EOPNOTSUPP;
break;
+ case 0x2B0C:
case 0x000C: /* Not configured as bridge Port */
rc = -ENODEV; /* maybe not the best code here? */
dev_err(&card->gdev->dev,
- "The HiperSockets device is not configured as a Bridge Port\n");
+ "The device is not configured as a Bridge Port\n");
break;
+ case 0x2B14:
case 0x0014: /* Another device is Primary */
switch (setcmd) {
case IPA_SBP_SET_PRIMARY_BRIDGE_PORT:
rc = -EEXIST;
dev_err(&card->gdev->dev,
- "The HiperSockets LAN already has a primary Bridge Port\n");
+ "The LAN already has a primary Bridge Port\n");
break;
case IPA_SBP_SET_SECONDARY_BRIDGE_PORT:
rc = -EBUSY;
dev_err(&card->gdev->dev,
- "The HiperSockets device is already a primary Bridge Port\n");
+ "The device is already a primary Bridge Port\n");
break;
default:
rc = -EIO;
}
break;
+ case 0x2B18:
case 0x0018: /* This device is currently Secondary */
rc = -EBUSY;
dev_err(&card->gdev->dev,
- "The HiperSockets device is already a secondary Bridge Port\n");
+ "The device is already a secondary Bridge Port\n");
break;
+ case 0x2B1C:
case 0x001C: /* Limit for Secondary devices reached */
rc = -EEXIST;
dev_err(&card->gdev->dev,
- "The HiperSockets LAN cannot have more secondary Bridge Ports\n");
+ "The LAN cannot have more secondary Bridge Ports\n");
break;
+ case 0x2B24:
case 0x0024: /* This device is currently Primary */
rc = -EBUSY;
dev_err(&card->gdev->dev,
- "The HiperSockets device is already a primary Bridge Port\n");
+ "The device is already a primary Bridge Port\n");
break;
+ case 0x2B20:
case 0x0020: /* Not authorized by zManager */
rc = -EACCES;
dev_err(&card->gdev->dev,
- "The HiperSockets device is not authorized to be a Bridge Port\n");
+ "The device is not authorized to be a Bridge Port\n");
break;
default:
rc = -EIO;
}
- break;
- case IPA_RC_NOTSUPP:
- rc = -ENOSYS;
- break;
- case IPA_RC_UNSUPPORTED_COMMAND:
- rc = -ENOSYS;
- break;
- default:
- rc = -EIO;
- }
+ else
+ switch (cbctl->ipa_rc) {
+ case IPA_RC_NOTSUPP:
+ rc = -EOPNOTSUPP;
+ break;
+ case IPA_RC_UNSUPPORTED_COMMAND:
+ rc = -EOPNOTSUPP;
+ break;
+ default:
+ rc = -EIO;
+ }
+
if (rc) {
QETH_CARD_TEXT_(card, 2, "SBPi%04x", cbctl->ipa_rc);
QETH_CARD_TEXT_(card, 2, "SBPc%04x", cbctl->cmd_rc);
@@ -1688,6 +1733,13 @@ static int qeth_bridgeport_makerc(struct qeth_card *card,
return rc;
}
+static inline int ipa_cmd_sbp(struct qeth_card *card)
+{
+ return (card->info.type == QETH_CARD_TYPE_IQD) ?
+ IPA_CMD_SETBRIDGEPORT_IQD :
+ IPA_CMD_SETBRIDGEPORT_OSA;
+}
+
static int qeth_bridgeport_query_support_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data)
{
@@ -1719,7 +1771,7 @@ static void qeth_bridgeport_query_support(struct qeth_card *card)
struct _qeth_sbp_cbctl cbctl;
QETH_CARD_TEXT(card, 2, "brqsuppo");
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0);
+ iob = qeth_get_ipacmd_buffer(card, ipa_cmd_sbp(card), 0);
if (!iob)
return;
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
@@ -1796,7 +1848,7 @@ int qeth_bridgeport_query_ports(struct qeth_card *card,
QETH_CARD_TEXT(card, 2, "brqports");
if (!(card->options.sbp.supported_funcs & IPA_SBP_QUERY_BRIDGE_PORTS))
return -EOPNOTSUPP;
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0);
+ iob = qeth_get_ipacmd_buffer(card, ipa_cmd_sbp(card), 0);
if (!iob)
return -ENOMEM;
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
@@ -1808,10 +1860,9 @@ int qeth_bridgeport_query_ports(struct qeth_card *card,
cmd->data.sbp.hdr.seq_no = 1;
rc = qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_ports_cb,
(void *)&cbctl);
- if (rc)
+ if (rc < 0)
return rc;
- rc = qeth_bridgeport_makerc(card, &cbctl, IPA_SBP_QUERY_BRIDGE_PORTS);
- return rc;
+ return qeth_bridgeport_makerc(card, &cbctl, IPA_SBP_QUERY_BRIDGE_PORTS);
}
EXPORT_SYMBOL_GPL(qeth_bridgeport_query_ports);
@@ -1864,7 +1915,7 @@ int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role)
}
if (!(card->options.sbp.supported_funcs & setcmd))
return -EOPNOTSUPP;
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0);
+ iob = qeth_get_ipacmd_buffer(card, ipa_cmd_sbp(card), 0);
if (!iob)
return -ENOMEM;
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
@@ -1874,10 +1925,9 @@ int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role)
cmd->data.sbp.hdr.seq_no = 1;
rc = qeth_send_ipa_cmd(card, iob, qeth_bridgeport_set_cb,
(void *)&cbctl);
- if (rc)
+ if (rc < 0)
return rc;
- rc = qeth_bridgeport_makerc(card, &cbctl, setcmd);
- return rc;
+ return qeth_bridgeport_makerc(card, &cbctl, setcmd);
}
/**
@@ -1898,7 +1948,7 @@ static int qeth_anset_makerc(struct qeth_card *card, int pnso_rc, u16 response)
case 0x0004:
case 0x0100:
case 0x0106:
- rc = -ENOSYS;
+ rc = -EOPNOTSUPP;
dev_err(&card->gdev->dev,
"Setting address notification failed\n");
break;
diff --git a/drivers/s390/net/qeth_l2_sys.c b/drivers/s390/net/qeth_l2_sys.c
index 59e3aa538b4d..52673cd1db99 100644
--- a/drivers/s390/net/qeth_l2_sys.c
+++ b/drivers/s390/net/qeth_l2_sys.c
@@ -23,8 +23,6 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
if (!card)
return -EINVAL;
- mutex_lock(&card->conf_mutex);
-
if (qeth_card_hw_is_reachable(card) &&
card->options.sbp.supported_funcs)
rc = qeth_bridgeport_query_ports(card,
@@ -59,8 +57,6 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
rc = sprintf(buf, "%s\n", word);
}
- mutex_unlock(&card->conf_mutex);
-
return rc;
}
@@ -90,7 +86,9 @@ static ssize_t qeth_bridge_port_role_store(struct device *dev,
mutex_lock(&card->conf_mutex);
- if (qeth_card_hw_is_reachable(card)) {
+ if (card->options.sbp.reflect_promisc) /* Forbid direct manipulation */
+ rc = -EPERM;
+ else if (qeth_card_hw_is_reachable(card)) {
rc = qeth_bridgeport_setrole(card, role);
if (!rc)
card->options.sbp.role = role;
@@ -123,12 +121,8 @@ static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev,
if (!card)
return -EINVAL;
- mutex_lock(&card->conf_mutex);
-
enabled = card->options.sbp.hostnotification;
- mutex_unlock(&card->conf_mutex);
-
return sprintf(buf, "%d\n", enabled);
}
@@ -167,10 +161,72 @@ static DEVICE_ATTR(bridge_hostnotify, 0644,
qeth_bridgeport_hostnotification_show,
qeth_bridgeport_hostnotification_store);
+static ssize_t qeth_bridgeport_reflect_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qeth_card *card = dev_get_drvdata(dev);
+ char *state;
+
+ if (!card)
+ return -EINVAL;
+
+ if (card->options.sbp.reflect_promisc) {
+ if (card->options.sbp.reflect_promisc_primary)
+ state = "primary";
+ else
+ state = "secondary";
+ } else
+ state = "none";
+
+ return sprintf(buf, "%s\n", state);
+}
+
+static ssize_t qeth_bridgeport_reflect_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct qeth_card *card = dev_get_drvdata(dev);
+ int enable, primary;
+ int rc = 0;
+
+ if (!card)
+ return -EINVAL;
+
+ if (sysfs_streq(buf, "none")) {
+ enable = 0;
+ primary = 0;
+ } else if (sysfs_streq(buf, "primary")) {
+ enable = 1;
+ primary = 1;
+ } else if (sysfs_streq(buf, "secondary")) {
+ enable = 1;
+ primary = 0;
+ } else
+ return -EINVAL;
+
+ mutex_lock(&card->conf_mutex);
+
+ if (card->options.sbp.role != QETH_SBP_ROLE_NONE)
+ rc = -EPERM;
+ else {
+ card->options.sbp.reflect_promisc = enable;
+ card->options.sbp.reflect_promisc_primary = primary;
+ rc = 0;
+ }
+
+ mutex_unlock(&card->conf_mutex);
+
+ return rc ? rc : count;
+}
+
+static DEVICE_ATTR(bridge_reflect_promisc, 0644,
+ qeth_bridgeport_reflect_show,
+ qeth_bridgeport_reflect_store);
+
static struct attribute *qeth_l2_bridgeport_attrs[] = {
&dev_attr_bridge_role.attr,
&dev_attr_bridge_state.attr,
&dev_attr_bridge_hostnotify.attr,
+ &dev_attr_bridge_reflect_promisc.attr,
NULL,
};
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 04e42c649134..70eb2f61bb92 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -3198,8 +3198,7 @@ static int qeth_l3_set_features(struct net_device *dev,
netdev_features_t features)
{
struct qeth_card *card = dev->ml_priv;
- u32 changed = dev->features ^ features;
- int err;
+ netdev_features_t changed = dev->features ^ features;
if (!(changed & NETIF_F_RXCSUM))
return 0;
@@ -3208,11 +3207,7 @@ static int qeth_l3_set_features(struct net_device *dev,
card->state == CARD_STATE_RECOVER)
return 0;
- err = qeth_l3_set_rx_csum(card, features & NETIF_F_RXCSUM);
- if (err)
- dev->features = features ^ NETIF_F_RXCSUM;
-
- return err;
+ return qeth_l3_set_rx_csum(card, features & NETIF_F_RXCSUM ? 1 : 0);
}
static const struct ethtool_ops qeth_l3_ethtool_ops = {
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index 1d42e4f88b96..f3bb7af4e984 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -732,7 +732,7 @@ static struct cxgbi_sock *cxgbi_check_route6(struct sockaddr *dst_addr)
}
ndev = n->dev;
- if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
+ if (ipv6_addr_is_multicast(&daddr6->sin6_addr)) {
pr_info("multi-cast route %pI6 port %u, dev %s.\n",
daddr6->sin6_addr.s6_addr,
ntohs(daddr6->sin6_port), ndev->name);
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 5c9e680aa375..e32d24ec7a11 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -27,6 +27,7 @@
#include <linux/moduleparam.h>
#include <generated/utsrelease.h>
#include <linux/utsname.h>
+#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/slab.h>
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index 8f6d0fb2cd80..a7cfc270bd08 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -26,6 +26,7 @@
#include <linux/mutex.h>
#include <linux/aer.h>
#include <linux/bsg-lib.h>
+#include <linux/vmalloc.h>
#include <net/tcp.h>
#include <scsi/scsi.h>
diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
index bc95ce89af06..5ab2f6978209 100644
--- a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
+++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
@@ -379,7 +379,7 @@ void rtw_cfg80211_indicate_disconnect(struct rtw_adapter *padapter)
GFP_ATOMIC);
} else {
cfg80211_disconnected(padapter->pnetdev, 0, NULL,
- 0, GFP_ATOMIC);
+ 0, false, GFP_ATOMIC);
}
}
}
diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c
index 0343ae386f03..458bc340aece 100644
--- a/drivers/staging/vt6655/device_main.c
+++ b/drivers/staging/vt6655/device_main.c
@@ -1524,21 +1524,12 @@ static void vnt_configure(struct ieee80211_hw *hw,
struct vnt_private *priv = hw->priv;
u8 rx_mode = 0;
- *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_PROMISC_IN_BSS |
- FIF_BCN_PRBRESP_PROMISC;
+ *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC;
VNSvInPortB(priv->PortOffset + MAC_REG_RCR, &rx_mode);
dev_dbg(&priv->pcid->dev, "rx mode in = %x\n", rx_mode);
- if (changed_flags & FIF_PROMISC_IN_BSS) {
- /* unconditionally log net taps */
- if (*total_flags & FIF_PROMISC_IN_BSS)
- rx_mode |= RCR_UNICAST;
- else
- rx_mode &= ~RCR_UNICAST;
- }
-
if (changed_flags & FIF_ALLMULTI) {
if (*total_flags & FIF_ALLMULTI) {
unsigned long flags;
@@ -1802,10 +1793,10 @@ vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent)
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
- priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_TIMING_BEACON_ONLY;
+ ieee80211_hw_set(priv->hw, TIMING_BEACON_ONLY);
+ ieee80211_hw_set(priv->hw, SIGNAL_DBM);
+ ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(priv->hw, REPORTS_TX_ACK_STATUS);
priv->hw->max_signal = 100;
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index ab3ab84cb0a7..2ccfbff37c42 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -785,8 +785,7 @@ static void vnt_configure(struct ieee80211_hw *hw,
u8 rx_mode = 0;
int rc;
- *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_PROMISC_IN_BSS |
- FIF_BCN_PRBRESP_PROMISC;
+ *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC;
rc = vnt_control_in(priv, MESSAGE_TYPE_READ, MAC_REG_RCR,
MESSAGE_REQUEST_MACREG, sizeof(u8), &rx_mode);
@@ -796,14 +795,6 @@ static void vnt_configure(struct ieee80211_hw *hw,
dev_dbg(&priv->usb->dev, "rx mode in = %x\n", rx_mode);
- if (changed_flags & FIF_PROMISC_IN_BSS) {
- /* unconditionally log net taps */
- if (*total_flags & FIF_PROMISC_IN_BSS)
- rx_mode |= RCR_UNICAST;
- else
- rx_mode &= ~RCR_UNICAST;
- }
-
if (changed_flags & FIF_ALLMULTI) {
if (*total_flags & FIF_ALLMULTI) {
if (priv->mc_list_count > 2)
@@ -987,10 +978,10 @@ vt6656_probe(struct usb_interface *intf, const struct usb_device_id *id)
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
- priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_TIMING_BEACON_ONLY;
+ ieee80211_hw_set(priv->hw, TIMING_BEACON_ONLY);
+ ieee80211_hw_set(priv->hw, SIGNAL_DBM);
+ ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(priv->hw, REPORTS_TX_ACK_STATUS);
priv->hw->max_signal = 100;
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index 7c87aecf4744..342e2b30c48f 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -722,7 +722,7 @@ void prism2_connect_result(wlandevice_t *wlandev, u8 failed)
void prism2_disconnected(wlandevice_t *wlandev)
{
cfg80211_disconnected(wlandev->netdev, 0, NULL,
- 0, GFP_KERNEL);
+ 0, false, GFP_KERNEL);
}
void prism2_roamed(wlandevice_t *wlandev)
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 4672bb1a24d0..a3fba366cebe 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -21,6 +21,7 @@
#include <linux/crypto.h>
#include <linux/completion.h>
#include <linux/module.h>
+#include <linux/vmalloc.h>
#include <linux/idr.h>
#include <asm/unaligned.h>
#include <scsi/scsi_proto.h>
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index d48379a258c7..664171353289 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -30,6 +30,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/module.h>
+#include <linux/vmalloc.h>
#include <linux/falloc.h>
#include <scsi/scsi_proto.h>
#include <asm/unaligned.h>
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 7ca642361f9c..8e5fa291f878 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/list.h>
+#include <linux/vmalloc.h>
#include <linux/file.h>
#include <scsi/scsi_proto.h>
#include <asm/unaligned.h>
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index fdf867230e18..0b4e24217564 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -34,6 +34,7 @@
#include <linux/cdrom.h>
#include <linux/module.h>
#include <linux/ratelimit.h>
+#include <linux/vmalloc.h>
#include <asm/unaligned.h>
#include <net/sock.h>
#include <net/tcp.h>
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index 5efef9a2a3d3..549af9847c28 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -22,6 +22,7 @@
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/parser.h>
+#include <linux/vmalloc.h>
#include <linux/uio_driver.h>
#include <net/genetlink.h>
#include <scsi/scsi_common.h>
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index b20d2c0ec451..1c4791033b72 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -55,9 +55,6 @@
static int __read_mostly sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE;
static bool __read_mostly sysrq_always_enabled;
-unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED };
-int sysrq_reset_downtime_ms __weak;
-
static bool sysrq_on(void)
{
return sysrq_enabled || sysrq_always_enabled;
@@ -571,6 +568,7 @@ void handle_sysrq(int key)
EXPORT_SYMBOL(handle_sysrq);
#ifdef CONFIG_INPUT
+static int sysrq_reset_downtime_ms;
/* Simple translation table for the SysRq keys */
static const unsigned char sysrq_xlate[KEY_CNT] =
@@ -951,23 +949,8 @@ static bool sysrq_handler_registered;
static inline void sysrq_register_handler(void)
{
- unsigned short key;
int error;
- int i;
-
- /* First check if a __weak interface was instantiated. */
- for (i = 0; i < ARRAY_SIZE(sysrq_reset_seq); i++) {
- key = platform_sysrq_reset_seq[i];
- if (key == KEY_RESERVED || key > KEY_MAX)
- break;
-
- sysrq_reset_seq[sysrq_reset_seq_len++] = key;
- }
- /*
- * DT configuration takes precedence over anything that would
- * have been defined via the __weak interface.
- */
sysrq_of_get_keyreset_config();
error = input_register_handler(&sysrq_handler);
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 8a89f6e7715d..6f0336fff501 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -33,6 +33,7 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/leds.h>
#include <linux/kbd_kern.h>
#include <linux/kbd_diacr.h>
@@ -129,7 +130,7 @@ static char rep; /* flag telling character repeat */
static int shift_state = 0;
-static unsigned char ledstate = 0xff; /* undefined */
+static unsigned int ledstate = -1U; /* undefined */
static unsigned char ledioctl;
/*
@@ -961,6 +962,122 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
}
}
+#if IS_ENABLED(CONFIG_INPUT_LEDS) && IS_ENABLED(CONFIG_LEDS_TRIGGERS)
+
+struct kbd_led_trigger {
+ struct led_trigger trigger;
+ unsigned int mask;
+};
+
+static void kbd_led_trigger_activate(struct led_classdev *cdev)
+{
+ struct kbd_led_trigger *trigger =
+ container_of(cdev->trigger, struct kbd_led_trigger, trigger);
+
+ tasklet_disable(&keyboard_tasklet);
+ if (ledstate != -1U)
+ led_trigger_event(&trigger->trigger,
+ ledstate & trigger->mask ?
+ LED_FULL : LED_OFF);
+ tasklet_enable(&keyboard_tasklet);
+}
+
+#define KBD_LED_TRIGGER(_led_bit, _name) { \
+ .trigger = { \
+ .name = _name, \
+ .activate = kbd_led_trigger_activate, \
+ }, \
+ .mask = BIT(_led_bit), \
+ }
+
+#define KBD_LOCKSTATE_TRIGGER(_led_bit, _name) \
+ KBD_LED_TRIGGER((_led_bit) + 8, _name)
+
+static struct kbd_led_trigger kbd_led_triggers[] = {
+ KBD_LED_TRIGGER(VC_SCROLLOCK, "kbd-scrollock"),
+ KBD_LED_TRIGGER(VC_NUMLOCK, "kbd-numlock"),
+ KBD_LED_TRIGGER(VC_CAPSLOCK, "kbd-capslock"),
+ KBD_LED_TRIGGER(VC_KANALOCK, "kbd-kanalock"),
+
+ KBD_LOCKSTATE_TRIGGER(VC_SHIFTLOCK, "kbd-shiftlock"),
+ KBD_LOCKSTATE_TRIGGER(VC_ALTGRLOCK, "kbd-altgrlock"),
+ KBD_LOCKSTATE_TRIGGER(VC_CTRLLOCK, "kbd-ctrllock"),
+ KBD_LOCKSTATE_TRIGGER(VC_ALTLOCK, "kbd-altlock"),
+ KBD_LOCKSTATE_TRIGGER(VC_SHIFTLLOCK, "kbd-shiftllock"),
+ KBD_LOCKSTATE_TRIGGER(VC_SHIFTRLOCK, "kbd-shiftrlock"),
+ KBD_LOCKSTATE_TRIGGER(VC_CTRLLLOCK, "kbd-ctrlllock"),
+ KBD_LOCKSTATE_TRIGGER(VC_CTRLRLOCK, "kbd-ctrlrlock"),
+};
+
+static void kbd_propagate_led_state(unsigned int old_state,
+ unsigned int new_state)
+{
+ struct kbd_led_trigger *trigger;
+ unsigned int changed = old_state ^ new_state;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) {
+ trigger = &kbd_led_triggers[i];
+
+ if (changed & trigger->mask)
+ led_trigger_event(&trigger->trigger,
+ new_state & trigger->mask ?
+ LED_FULL : LED_OFF);
+ }
+}
+
+static int kbd_update_leds_helper(struct input_handle *handle, void *data)
+{
+ unsigned int led_state = *(unsigned int *)data;
+
+ if (test_bit(EV_LED, handle->dev->evbit))
+ kbd_propagate_led_state(~led_state, led_state);
+
+ return 0;
+}
+
+static void kbd_init_leds(void)
+{
+ int error;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) {
+ error = led_trigger_register(&kbd_led_triggers[i].trigger);
+ if (error)
+ pr_err("error %d while registering trigger %s\n",
+ error, kbd_led_triggers[i].trigger.name);
+ }
+}
+
+#else
+
+static int kbd_update_leds_helper(struct input_handle *handle, void *data)
+{
+ unsigned int leds = *(unsigned int *)data;
+
+ if (test_bit(EV_LED, handle->dev->evbit)) {
+ input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
+ input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02));
+ input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04));
+ input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
+ }
+
+ return 0;
+}
+
+static void kbd_propagate_led_state(unsigned int old_state,
+ unsigned int new_state)
+{
+ input_handler_for_each_handle(&kbd_handler, &new_state,
+ kbd_update_leds_helper);
+}
+
+static void kbd_init_leds(void)
+{
+}
+
+#endif
+
/*
* The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
* or (ii) whatever pattern of lights people want to show using KDSETLED,
@@ -968,7 +1085,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
*/
static unsigned char getledstate(void)
{
- return ledstate;
+ return ledstate & 0xff;
}
void setledstate(struct kbd_struct *kb, unsigned int led)
@@ -995,20 +1112,6 @@ static inline unsigned char getleds(void)
return kb->ledflagstate;
}
-static int kbd_update_leds_helper(struct input_handle *handle, void *data)
-{
- unsigned char leds = *(unsigned char *)data;
-
- if (test_bit(EV_LED, handle->dev->evbit)) {
- input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
- input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02));
- input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04));
- input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
- }
-
- return 0;
-}
-
/**
* vt_get_leds - helper for braille console
* @console: console to read
@@ -1085,24 +1188,23 @@ void vt_kbd_con_stop(int console)
}
/*
- * This is the tasklet that updates LED state on all keyboards
- * attached to the box. The reason we use tasklet is that we
- * need to handle the scenario when keyboard handler is not
- * registered yet but we already getting updates from the VT to
- * update led state.
+ * This is the tasklet that updates LED state of LEDs using standard
+ * keyboard triggers. The reason we use tasklet is that we need to
+ * handle the scenario when keyboard handler is not registered yet
+ * but we already getting updates from the VT to update led state.
*/
static void kbd_bh(unsigned long dummy)
{
- unsigned char leds;
+ unsigned int leds;
unsigned long flags;
-
+
spin_lock_irqsave(&led_lock, flags);
leds = getleds();
+ leds |= (unsigned int)kbd->lockstate << 8;
spin_unlock_irqrestore(&led_lock, flags);
if (leds != ledstate) {
- input_handler_for_each_handle(&kbd_handler, &leds,
- kbd_update_leds_helper);
+ kbd_propagate_led_state(ledstate, leds);
ledstate = leds;
}
}
@@ -1450,7 +1552,7 @@ static void kbd_start(struct input_handle *handle)
{
tasklet_disable(&keyboard_tasklet);
- if (ledstate != 0xff)
+ if (ledstate != -1U)
kbd_update_leds_helper(handle, &ledstate);
tasklet_enable(&keyboard_tasklet);
@@ -1497,6 +1599,8 @@ int __init kbd_init(void)
kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
}
+ kbd_init_leds();
+
error = input_register_handler(&kbd_handler);
if (error)
return error;
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index 5b30d27dab50..55722feeb898 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -35,6 +35,7 @@
#include <linux/compat.h>
#include <linux/eventfd.h>
#include <linux/fs.h>
+#include <linux/vmalloc.h>
#include <linux/miscdevice.h>
#include <asm/unaligned.h>
#include <scsi/scsi_common.h>
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 2d9923a60076..0505b796d743 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -36,14 +36,16 @@ config LCD_CORGI
config LCD_L4F00242T03
tristate "Epson L4F00242T03 LCD"
- depends on SPI_MASTER && GPIOLIB
+ depends on SPI_MASTER
+ depends on GPIOLIB || COMPILE_TEST
help
SPI driver for Epson L4F00242T03. This provides basic support
for init and powering the LCD up/down through a sysfs interface.
config LCD_LMS283GF05
tristate "Samsung LMS283GF05 LCD"
- depends on SPI_MASTER && GPIOLIB
+ depends on SPI_MASTER
+ depends on GPIOLIB || COMPILE_TEST
help
SPI driver for Samsung LMS283GF05. This provides basic support
for powering the LCD up/down through a sysfs interface.
@@ -434,7 +436,7 @@ config BACKLIGHT_AS3711
config BACKLIGHT_GPIO
tristate "Generic GPIO based Backlight Driver"
- depends on GPIOLIB
+ depends on GPIOLIB || COMPILE_TEST
help
If you have a LCD backlight adjustable by GPIO, say Y to enable
this driver.
diff --git a/drivers/video/backlight/da9052_bl.c b/drivers/video/backlight/da9052_bl.c
index b1943e7735a1..fd2be417aa64 100644
--- a/drivers/video/backlight/da9052_bl.c
+++ b/drivers/video/backlight/da9052_bl.c
@@ -152,7 +152,7 @@ static int da9052_backlight_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_device_id da9052_wled_ids[] = {
+static const struct platform_device_id da9052_wled_ids[] = {
{
.name = "da9052-wled1",
.driver_data = DA9052_TYPE_WLED1,
diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c
index 439feb2389a8..5fbbc2ebdf93 100644
--- a/drivers/video/backlight/gpio_backlight.c
+++ b/drivers/video/backlight/gpio_backlight.c
@@ -146,6 +146,8 @@ static struct of_device_id gpio_backlight_of_match[] = {
{ .compatible = "gpio-backlight" },
{ /* sentinel */ }
};
+
+MODULE_DEVICE_TABLE(of, gpio_backlight_of_match);
#endif
static struct platform_driver gpio_backlight_driver = {
diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c
index a26d3bb25650..88116b493f3b 100644
--- a/drivers/video/backlight/lp855x_bl.c
+++ b/drivers/video/backlight/lp855x_bl.c
@@ -257,21 +257,15 @@ static void lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br)
static int lp855x_bl_update_status(struct backlight_device *bl)
{
struct lp855x *lp = bl_get_data(bl);
+ int brightness = bl->props.brightness;
if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
- bl->props.brightness = 0;
+ brightness = 0;
- if (lp->mode == PWM_BASED) {
- int br = bl->props.brightness;
- int max_br = bl->props.max_brightness;
-
- lp855x_pwm_ctrl(lp, br, max_br);
-
- } else if (lp->mode == REGISTER_BASED) {
- u8 val = bl->props.brightness;
-
- lp855x_write_byte(lp, lp->cfg->reg_brightness, val);
- }
+ if (lp->mode == PWM_BASED)
+ lp855x_pwm_ctrl(lp, brightness, bl->props.max_brightness);
+ else if (lp->mode == REGISTER_BASED)
+ lp855x_write_byte(lp, lp->cfg->reg_brightness, (u8)brightness);
return 0;
}
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 6897f1c1bc73..eff379b234cc 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -241,7 +241,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->dev = &pdev->dev;
pb->enabled = false;
- pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable");
+ pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
+ GPIOD_OUT_HIGH);
if (IS_ERR(pb->enable_gpio)) {
ret = PTR_ERR(pb->enable_gpio);
goto err_alloc;
@@ -263,9 +264,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->enable_gpio = gpio_to_desc(data->enable_gpio);
}
- if (pb->enable_gpio)
- gpiod_direction_output(pb->enable_gpio, 1);
-
pb->power_supply = devm_regulator_get(&pdev->dev, "power");
if (IS_ERR(pb->power_supply)) {
ret = PTR_ERR(pb->power_supply);